バランスを取りたい

よくCTFの記事を書きます

サイバーコロッセオ 2017 Writeup

サイバーコロッセオに参加してきました。

詳細はこれ。

写真はほとんど撮ってないので何も視覚的な情報がないんですが、今のところSECCON公式Twitterからランキングを見られるのでそちらからどうぞ。

これはチームのアレ。ドクターマリオっぽい背景ですね。

f:id:xrekkusu:20170305170648j:plain

続きを読む

SECCON 2016 Finals Writeup

事の発端(2月4日)

f:id:xrekkusu:20170205210158p:plain

それとなく書けという圧力を感じた。

総評

SECCON2016 CTF finals ranking table によれば24チーム中13位。1日目ラストでJeopardyを大量に倒したため一時は6位まで上がったが、2日目でAttack Pointが取れずズルズル下がってしまった。

これでも日本の学生チームでは1位だったので文部科学大臣賞や超豪華なスポンサー賞など、結構いい感じに表彰された。

サーバ4

gdbのリモートデバッグが外に露出しているので操作してエクスプロイトしろという問題。 記憶にないけどSECCON 2016のオンライン予選で出た問題の使い回しっぽい? 詳細は坂井さんのページにあります。問題バイナリも配布されています。

問題概要

問題サーバが4つ(ARM, H8, SH, V850)動いているのでそれらをエクスプロイトし、flag.txtに自チームのDefense flagを書き込めば良い。ARMサーバに関してはword.txtがあり、そこにAttack flagが置いてある。

Defense flagは4つの問題サーバのそれぞれで1 flagしか受け付けない上、受け付けるpayloadの長さは時間が経つほど5000, 3000, 2000, 1000, …, 4と短くなる(一定時間経つと回復する)ため、他のチームより遅く書き込まないとポイントにならない。

バイナリの推測

そもそも4つのサーバで何のアーキテクチャバイナリが動いているのかすらわからないため、リモートデバッグAPIを駆使してバイナリを引っこ抜く。

ステップ実行を行うコマンドはsなので、これとチェックサム(各バイトを足し合わせ、&0xFF)を合わせた+$s#73を送り、更にレジスタの内容を取得するgを使ってレジスタ内でIPらしき部分を発見する。今回は0x2000バイナリがマップされていた。

次に、メモリからデータを取得するコマンドm[addr],[size]を使い、m2000,200のようにしてバイナリを取得する。

最後に、バイナリをよく読み何のアーキテクチャかを推測する。1つ目のサーバに関しては4バイト単位で命令が並んでいたので適当にGoogleに投げたところARMだとわかった。他のバイナリも同様に推測することができる。

Exploit

GDBのリモートデバッグプロトコルには多くのコマンドがあるが今回使用できたのはc,s,m,g,Gくらいで、実質的にできることは実行・メモリリークレジスタリーク・レジスタの書き換えだけ。普段のエクスプロイトのように「スタックにファイル名を置いて〜」的なことは一切できない。

というわけで、メモリ上に任意の文字列を配置するためにはレジスタ→メモリ間の転送命令を使う必要がある。

ARMの場合はpush {r4, r5, lr}があったので3ワード(=12バイト)分一度に転送することができた。またバイナリ内にはopen-read-writeができる分のシステムコールgadgetがあり、そこにIPを飛ばすだけで普通にシステムコールが呼べるようになっていた。

Attack

Exploitで解説した要素を組み合わせると、open('word.txt', 0); read(3, 0x3000, 0x60);相当を呼ぶことができるのでメモリ上に乗ったフラグをmコマンドで読み出せば終わり。

Flag: SECCON{5f52d7fcb7fc824c}

Defense

Attackが解き終わった頃には他のチームが既にDefenseを押さえていた上、ARMのflag.txtはファイルの中身を空にされてしまいフラグを書き込んでもpayloadの長さでは完全に勝てない状態になっていた。他のサーバではまだチャンスがありそうだったが、誰もAttackを取れていないサーバ2の方に移ったため放置してしまった。このときは1日目でサーバ2は設定ミスにより解けない状態だったので大きなロス……。

サーバ5

これも過去のSECCONで出た問題とほぼ同じ。一部バイナリが変わっていて過去のwriteupを使いまわしても動かなかった。

全体のコードはここ

問題概要

UTF-16LEで書いたヘブライ語x86機械語として実行してくれる。

2日目はこのサーバは全チームDefenseを取ってくると予想し、1日目の夜に必死にヘブライ語の勉強をした。

ヘブライ語シェルコード

ヘブライ語で作れる主なx86命令は、

xchg eax, edi
add eax, 0xfbXXfbXX
add eax, 0x05XXfbXX
add eax, 0xfbXX05XX
add eax, 0x05XX05XX
xor eax, 0xXXfbXXfb
xor eax, 0xXX05XXfb
xor eax, 0xXXfbXX05
xor eax, 0xXX05XX05
stosb

くらいしかなく、しかもこれらの命令も100%ヘブライ語として通るわけではないので前後に無意味となるような命令を挟みつつstosbを使ってメモリ上にシェルコードを展開していく。stosbmov byte [edi], al; inc ediをやってくれる命令なのでなんと任意の値をメモリ上に書き込んでいくことができる。

方針

call eaxによりヘブライ語シェルコードの処理を呼び出すため、シェルコードが配置されているアドレスはeaxに格納されている。これにいくらかの値を足した位置にシェルコードを書き込むようにすれば自動的にシェルコードが実行される。

今回はz3を使ってadd eax, 0xAAAABBBBAAAA,BBBB0xfb20, 0xfb30, 0x05d0, 0x05e0のいずれかが入るような命令を組み合わせてeaxをオーバーフローさせつつ最終的にeaxに0xc00から0xf00の値を足し込めるような命令列を計算した。

次に、stagerとかを使って当日にコケたくなかったので、普通のシェルコードをヘブライ語へ変換して実行時に戻すという方法を取った。いくらヘブライ語が不自由とはいえ、下位4bitだけは0~Fのすべてが揃っていたので4bitについてヘブライ語1文字を割り当てれば簡単にデコードできる。

Attack

ここまでできていれば特に言うことはなくkeyword.txtを持ってくるだけ。

Flag: 無くした。無念

Defense

Defense用のflag.txtがどこにあるかわからず苦戦するが、httpでアクセス可能だったのでHTTPサーバの設定から頑張って探した。書き込み限定のattrがついていてコケたがとりあえず5分につき2~3ptを入手できるようになった。

どこのチーム(多分CyKor)だったかは忘れてしまったが、flag.txtに書き込んだ瞬間次の行に自チームのDefense flagを書き込んでくるスクリプトがいて恐ろしかった。

NIRVANA改SECCONカスタムを作る

これはCTF Advent Calendar 2016の14日目の記事です。今日になって何故か急に@potetisenseiポエムを投稿したので被って最悪。抜けた3日目と25日目を足して2で割って14日ってなんじゃそりゃ。

お気持ち表明

CTFの可視化って流行ってますよね。 最近SECCON本戦だけでなく、地方大会やCTF for Girls、更にはSECCON系ではないTrendMicroCTFでもCTFの可視化が行われていて「いいなー」って思うわけです。同じ感じに作っても面白くないので、ブラウザ上で動くthree.jsを使ったらどこまで行けるんだろうと勢いがあるだけやってみることにしました。

NIRVANA改SECCONカスタム (2013)

www.youtube.com

2013年のNIRVANAですが記憶に残っている人も多いと思います。これだけイケてるCTFの可視化システムは世界中を探してもSECCONくらいですね。

と、見とれるのはこれくらいにして、どうすればこれを手抜きして作れるかを考えます。パッと見て特徴的な点を挙げていくと、

  • 六角形
  • 回る
  • パケットっぽいものが飛んでる
  • 透けてる

終わり。

「突破」が足りない?問題を解いてから言いなさい。とまぁ、動画を見て抱く印象としてはだいたいこんな感じでしょう。

作ってみる

f:id:xrekkusu:20161214004200p:plain

できました

three.jsの学習にゆるゆる1週間と本体の実装に2日なのでガバガバコードです。飛んでる物体の削除が雑。3Dがよくわからん。ChromeFirefoxで描画のされ方が違うなど。

前述した4つの要素を使ってそれっぽいものを作ってみました。今のところ通信を拾ってアレコレするのが面倒だったので乱数で適当に飛ばしてます。透けてる六角柱が回ってパケットっぽいものが飛んでるだけでなんとCTFの可視化っぽくなります。

WebGLとは言えまぁまぁ重い。MBPだとRetinaGPUがファーでファンもファー。MBPはGPUを酷使すると離陸することで知られていますがTouchBarが付いたMBPはどうなんですかね。

実装的には六角柱を並べてパケットを飛ばし合う様子をカメラを回しながら見てるだけです。パケットは雑な放物線を書いたのでそれに合わせて飛ばしてます。他に書くこともあんまりないんですが乱数によりスコアっぽいものが決まって六角柱の高さが変わります。

終わりに

NIRVANA改SECCONカスタムはすごい。透ける六角柱が回ってパケットを飛ばすくらいなら簡単なのに、これをCTFの状況に応じて細かく制御したり、複数モードとその間の画面遷移を実装したり軌道を綺麗に表示したりと異常な挙動がたくさん見られるのでプロフェッショナルは強い。

CTF for ビギナーズでも可視化をやりたい気分があるのでJeopardyの可視化に自信のある人は連絡ください。

SECCON 2015 final (intercollege)

もう既に各所ニュースサイトなんかでは取り上げられてますが SECCON 2015 final (intercollege) でチーム dodododo として出場して優勝しました。

めっちゃ「 dodododo のリーダー」みたいな呼ばれ方してるんですが、本来のリーダーは akiym さんで今回は SANS Netwars で自分が出場権を取ってきたのでリーダーとして立ちまわってただけです。

適当なサイトで読めるような内容を再び書いても面白く無いので、決勝戦で何をやっていたかということについて書きます。

環境整備

環境整備の中でも特に WAF の導入をやった。

作戦として、 ModSecurity と OWASP Core Rule Set で Web アプリに対する基本的な攻撃をブロックするルールを適用して攻撃に使える時間を増やすことを考えた。

事前準備として、問題サーバが外部インターネットに繋がらない可能性を考慮して Ubuntu 用の deb パッケージの用意をしたり、 Core Rule Set の中からどのルールを適用するかを決めておいたりしたのに OS が CentOS だったため対応する rpm をダウンロードしてくる羽目になった。

vulnerable_blog の SLA チェックが安定しない

サービスは3つあり、そのうち ModSecurity が効くのは Apache 配下の vulnerable_blog と sbox2015 です。

WAF 導入後、 sbox2015 の SLA は安定しているのになぜか vulnerable_blog の SLA チェックが安定して通らない。 WAF を導入したことが原因かと思い込み、 ModSecurity のモードを DetectionOnly にしたり Off にしたりしたが状況は改善しない。

試行錯誤している間に hiromu が vulnerable_blog の脆弱性をすべて潰してくれたので WAF を外してみたものの、やはり SLA チェックは安定せず。運営しっかりしてくれ。

こうして競技時間の半分以上が溶けた。

sbox2015 の任意コード実行から vulnerable_blog の keycode を読む

任意コード実行を利用すると他のサービスの管理者パスワードをリークできるというので最後の1時間くらいはこれをやっていた。

適当に試したところ、スクリプト実行を許していてかつある程度ポイントを保持しているチーム ( security_anthem ) があったので 15 フラグくらい頂いた。

おまけ

vulnerable_blog のページ番号のパラメータのエスケープを間違えているチームが非常に多かった。

ページ番号は LIMIT 句に入ってくるので文字列としてプリペアドステートメントに突っ込んでしまうと SQL インジェクションが発生してしまう。ただ、今回は CodeIgniter が SQL のエラーをうまく表示してくれなかったのでうまく exploit に繋げられなかった。

ORDER BY , LIMIT 以降で効率よく SQL インジェクションする方法があったら教えてください。

Xmas CTF

CTF Advent Calendar 2015 - Adventarの25日目ですがさすがにボロボロすぎませんか???

スカスカなのはともかく、ネタまで書いておいて結局記事書いてない人って何してるんですかね。

というわけで、25日はクリスマスCTFとしてAmazonギフト付きのCTFをやります。

ルール

  • フラグは3つあり、それぞれで得点(=金額)が異なります
  • 得点は700, 500, 300で、ギフト券の額面はそのまま700円, 500円, 300円です
  • 各フラグにつき、Amazonギフト券を獲得できるのは先着1人のみです
  • ギフト券獲得者は @xrekkusu 宛にDMを送ってください。その際、フラグと簡単な解法を送信してください
  • ギフト券獲得者の名前はこの記事で発表します。その際、獲得者のTwitterへのリンクとscreen_nameを使います
  • 名前の発表を拒否する場合はギフト券を受け取ることはできません
  • 既にギフト券を獲得された問題についてはフラグを白文字等で伏せて発表し、以降その問題についてのDMの返信は行いません
  • 解答の受付期間は日本時間の2015年12月25日23:59:59までとします

問題

js+JSghJaKAq7ygqAU1EgQzA7CspSoiPD8tHQAXB5u4g4ixqiA4FwAnHRo5BwgDABE0Owg/KaKMs
5S2lj8jBiohCCwBP4O4uC8MPzQNP6K6nbOUlwEsLq6Nmz4xBreTti80D7y2n6qoto+xgqSvpxodM
rqMpJewnikmOgkjPZ+ejZ6Ltg8MFhgPOBE2NZOfohMHFQ8KPL6itbG/vjYXOgglCLCXqYahjDUgO
CA7PayEm5yDhISDgDQlID0WIzU1ChkYC5uQkYSInwgCFBUsPZ6bkyMkNrqemhcDPpejjqCYsz8wC
hYxMgg7OjQvBISymiEwGBwsIZS2v5i5oIePtgA3ODsCFa6LkjQnMzAyI4aMiZ2tih4CPCQfCREyL
hkwFh0SLRwWOoa6iZifsJK8kTAePTMpCSovDCQLM7uLsqGSjAgcNj4KPoqGjpiEhhAMFgQMAJqEn
oaUloSWioKCjIaelAwQGJKSg

ヒント

  • Stage1は2進数8ビット単位でどうにかしてデータを格納しています
  • 3つの問題と4つのランダムデータと1つの空白データがあります
  • ''.join(map(lambda x: '1' if ord(x) & MASK else '0', data))

ギフト券獲得者

フラグ

  • 700:
  • 500:
  • 300: 2015{c3f81b3e2}

XSSを報告したらちょっと不便になった

この記事は脆弱性"&'<<>\ Advent Calendar 2015の16日目の記事です。

2015年のアドベントカレンダーですが、大昔(2013年)にミスタードーナツ公式ページにあったXSSの話をします。

2013年3月

ミスタードーナツの公式サイトへ行った時、偶然にも検索画面で怪しい文字列を発見してしまいました。最近ではあまり見かけなくなった ie=utf-8&oe=utf-8 のようなパラメータです。

XSS界隈の人なら恐らくこんな感じのパラメータを見たらちょっと変えてみてどのような挙動を起こすか試したくなるはずです。

実際にoe=utf-8を変えたらそれに対応する値がmetaのcharsetに入るようでした。当時のことを詳しく覚えていませんが、ここから直接XSSしたわけじゃないので多分値はエスケープされていたと思います。

エンコーディング周りでは当時UTF-7が終わりを迎える時期でしたが幾つかのUTF-7 XSS記事が出回っていたためそれを試してみると、IE8なんかでは普通にcharset=UTF-7として認識されました。

というわけでレアケースなUTF-7 XSSが確認できたのでIPA経由で報告し、1ヶ月後には修正されたのですが修正方法がちょっと残念でした。

検索ボックスがそのまま消えた

奇跡的にInternetArchiveで検索ボックスが消える様子が確認できたのでそのスクリーンショットを貼ります。

報告前2月18日

f:id:xrekkusu:20151215144006p:plain

修正後5月3日

f:id:xrekkusu:20151215144048p:plain

サイト内の検索が無くなったため、若干アクセシビリティは減ったはずです。

回避はできなかったのか

当時送信したIPAへの届け出のメールを見たところ、当時のフォーマットには回避策の欄が(多分)無かったようです。そのためどのように修正するのが最善かがうまく伝わらなかったと思われます。今のフォーマットには回避策の欄があるので、脆弱性を報告するときは現状の機能を損なわないように的確に修正案を書きましょう。

--

14:35 追記 間違えてソフトウェアの方と比較してしまったらしく、今もWebの脆弱性報告には回避策の欄はないようです。脆弱性を報告して機能が消えるのはつらい…。

PayloadGenerator

片手で気合で埋めてくCTF Advent Calendar 2015の4日目です。

書いてくれたのむ。

Pwn、やってますか

時々Pwnの問題を解いているとき、ポインタの扱いでちょっと困るときがある。

例えば、リターンアドレスから既知のバッファ上に設置されたシェルコードへ飛びたい場合、大体次のようなコードを書く。

payload = 'A' * 40 + p32(buf_addr + 100)
payload = payload.ljust(100, '\0')
payload += sc

まぁ特に問題ない気がするけど、60文字弱のパディングを入れるのは微妙。もっと調節してもいいけど計算するのは面倒。

どういうことかっていうとこんな感じに書きたい。

payload = PayloadGenerator([
    'A' * 40,
    Ptr32(sc),
]).generate(base=buf_addr)

できました。

payload_generator.py · GitHub

bss = 0x804a000
execve = 0x48484848

a = PayloadGenerator([
    p32(execve),
    'AAAA',
    Ptr32('/bin/sh\0'),
    Ptr32([
        Ptr32('/bin/sh\0'),
        p32(0)
    ]),
    Ptr32(p32(0)),
])
print a.generate(base=0).encode('hex')
print a.generate(base=bss).encode('hex')

こういうコードを書くと、

4848484841414141140000001c000000300000002f62696e2f736800140000000000000000000000
484848484141414114a004081ca0040830a004082f62696e2f73680014a004080000000000000000

こんな感じに帰ってくる。

雑さ

だいぶ雑に書いてるので多分バグる

多分便利なんだろうけどこれを使うほどの問題に遭遇してない気がするし必要ないっぽい。

よろしく