Qualificationが10月19日の15:00(JST)から24時間開催されました。今年はNaruseJunで参加し、全体で5位でした。1時間程度しか寝ていないので疲れましたが、オンサイトでわいわい解くのは楽しかったです。通したフラグは合計で1736点でした。手伝った問題なども含めて関与した問題について書きます。問題とソルバはここに置きます。decodeするとopensslでaes-256-cbcで復号してる箇所があったのですが、鍵がhex4文字だったので総当りして解読しました。すると難読化シェルスクリプトが出てきたのですが、この時pwnが出題されたのでチームメンバーに任せたら解いてくれました。freeやUAF(read)がありますが、mallocできるサイズは0x40で固定です。baseを手に入れます。ポインタは1つしか用意されていないため、今回はtcache領域を書き換える方針にしました。同じチャンクを2回以上freeすることでfdにヒープのアドレスを入れ、ヒープのアドレスをleakします。大きなチャンクをfreeする際はサイズチェックが入るので、たくさんチャンクを確保して偽のサイズを用意しておきます。サイズが固定なので、今回はtcacheの管理領域を破壊することにしました。countやfdに注意すると適切な場所に大きなサイズのチャンクを用意でき、それをfreeすればlibcのアドレスが手に入ります。poisoningで__free_hookをsystemに書き換えればOKです。libc.symbol("system")))add("/bin/sh")delete()sock.interactive()ほい。sumRELROやPIEは無効です。総和を求めてくれるプログラムですが、sumのポインタを上書きできるので、任意アドレスに入力した値の総和を入れられます。exitをmainにしたのですが、その後相当悩みました。chainとして使えるようなのですが、全然気付きませんでした。setvbufの第一引数にstdin/stdoutが渡されますが、setvbufをputsに変えても0xfbad1883が出力されるだけです。ところが、dynのstdoutはsetvbufでしか使われていないので下位1バイトを破壊してもsetvbufを呼ばない限り怒られません。(この辺はkriwさんといけるんじゃね?的な話をして実現しました。stdoutを0x10バイトずらすと(setvbufでNULLが設定されているので)libcのアドレスがリークできます。gadgetを呼び出してシェルが取れました。libc_one_gadget)sock.interactive()いぇい。lazyバイナリは渡されませんが、繋ぐと部分的にソースコードが見られます。*buf){.....[省略]}普通にバッファオーバーフローがあるのですが、とりあえずユーザー名とパスワード当てたらフラグが貰えるかなーと思ってバッファオーバーリードでユーザー名とパスワードをリークしました。すると、オプションにManageが現れてバイナリをダウンロードできるようになります。「.」が付いていたらダウンロードできないのでlibc.so.6はダウンロードできません。lazyをダウンロードするとCanary付きPIE無効なバイナリでした。普通に考えたらBOFで終わりですが、libcのバージョンがdbに存在しない独自ビルドでした。そこでlibcをリークしようとしたのですが、接続が途中で切れて最後まで落とせません。仕方なくret2libcしようとしたりlisting機能を使ってflagのパスを調べたりしましたが、前者は.rel.pltが無くて詰み、降車は用意されたcatを使わないとflagが読めない謎仕様だったのでダメでした。2時間ほど詰まって私もキれていたのですが、最終的にDynELFで一瞬で解けました。p64(addr_system)login_pass(password)sock.send("/bin/sh\x00")sock.interactive()DynELFは有能だったり無能だったりするけど今回は最高に便利でした。810a0afb2c69f8864ee65f0bdca999d7_FLAGSECCON{Keep_Going!_KEEP_GOING!_K33P_G01NG!}$これをやらせたいのならBOFだけでいいと思いますし、最初の方のログインとかディレクトリリスティングとかミスリーディングな要素が多かったのは気に入りませんでした。(まぁ某web問に比べれば良問ですけどね。2.30が出題されたのは観測した限りたぶん初めてだと思います。freeとUAF(write)があります。show系の機能はないので_IO_2_1_stdout_を使う系問題ですね。最大10個しかチャンクを確保できず、freeしても残るので資源を有効活用する必要があります。exitができるので、正確には11回使えます。ホワイトボードでヒープの様子を描いていたら丁度10回でシェルが取れる順番になったので愚直に実装しました。私のコードは16ビット分のguessが必要です。time.sleep(0.1)この問題は特に詰まることなく解けました。Operatorこの問題は基本的にkriwさんが解いてくれました。baseのリークは簡単ですが、シェルを取る方法に悩みました。終了前にnが使えないFSBがあるのですが、そこでcanaryをbypassする方法をひたすら考えました。私は早々にリタイアしてremainを始めたのですが、remainを解いている途中にkriwさんが「libcのアドレス分かってるからTLSのcanary取れるくね?」と提案し、その方向で解いてくれました。canaryだからstackのアドレスをどうやって取るかに囚われてTLSの存在を忘れていました。7w1n5ELFバイナリが2つ渡されます。点数が低い割にかなり後半まで誰も触れていなかったのでremainを解いた後にやりました。データを復号するっぽい関数arc4が多用されており、かといって読むのも面倒なのでangrにやらせました。yoshi-campでふるつきに教えてもらったangrテクニックをふんだんに使ってarc4の復号結果を取得したり、envchkの戻り値を書き換えたりしたらBrother1にフラグの前半が出てきました。changed!\x00'後半も同じスクリプトで呼び出すバイナリをBrother2に変えたら出てきました。相談できるpwnerがいるのはやはり心強いです。多少難しくてもさくさく進む。pitballの謎命令は知らなかったので、解けなかったですが勉強になりました。面白い問題が多かったです。同時に年々難しくなっている気がします。exeのweb問は評判悪いから変えた方が良いのでは?オンサイトで集まってやるとやる気も出るし楽しい。運営および参加者の方々、お疲れ様でした。4のwriteupなんかtwitterで流れてたのでzer0ptsで参加しました。Writeup月別アーカイブはてなブログをはじめよう!ptr-yudaiさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。