fr33f0r4llスマートフォン用の表示で見るfr33f0r4ll自分用雑記この広告は、90日以上更新していないブログに表示しています。Writeup忙しくてCTFしてなかったので復帰戦、全然駄目になっていた。TiredPartyMisccontainersDumpだけ、1日目から8時間くらいやってあとはあきてしまった。pwnが解けてないのほんと駄目。Seccompare単純にstrcmpでフラグと比較しているので簡単に解けた。ltraceを使ったけどstringsとか静的解析でもすぐ分かると思う。Leakage解析してみると内部で難読化したフラグを一文字ずつ復号して比較する処理をしていた。デバッガを使って文字の比較を誤魔化してやれば一文字ずつフラグが復号される。それか一文字ずつ特定して一文字ずつ入力を合わせていってもいい、手間はあまり変わらない。Operation入力した文字列を、かなり面倒くさそうな変換処理で変換して比較している。angrを使った、こういうときに便利。使い方がまったく分からないから勉強しないと...コードは以下。simgr.found[0]print(state.posix.dumps(0))大量にある外れの分岐を探すのが一番面倒くさかった。Radare2のマウスクリックでランダムな機能が実行される不具合の原因を特定する。Tiredzlibとbase64を繰り返し適用してるだけ、最初base64じゃないと思って無駄に時間を使った。Pythonで解いた。Party暗号化処理をしているコードを見ると、秘密情報であるcoeffの3つの値を変数とした連立方程式が作れることが分かる。v3]とした場合、暗号化処理は次のようになる。c3に関する3つの一次方程式が存在することになるので、あとは解くだけである。桁が大きすぎて計算が面倒なのでPythonにやらせた。expr3])[c1]print(flag_num)print(long_to_bytes(flag_num))RSAはRSAを忘れたので解けませんでしたはい。containersWelcomeは問題じゃないので飛ばす。Dockerのコンテナか何かかと思ったけど、どうも違うらしいので適当に抽出した。作者っぽい人のツイート見る限りではオリジナルらしい?foremost使った。16進数値のクソ長いフラグを画像ごとにバラして答えとするのは悪い例だと思いますが。ある程度意味のある文字列にしないと無駄に入力ミスするし順番の勘違いもしやすいし、コピペできない形式なら非推奨だってCTFの手引きに書いてある。大人しくctf4b{th1s_1s_th3_fl4g}みたいな形式にすれば良かったと思う、他の問題だとそういうフラグあったし。Dumppcapファイル渡される、httpで通信してるっぽいので通信しているデータをwiresharkで取り出す。webshellを使ってshで命令を実行、httpで結果を返信してるらしい。命令を見てみるとflagをhexdumpで出力してるらしいので、単純にデコードする。dump]))jpgらしいので画像として開いてフラグゲット。shellcoder終わったあとに解いた、送信したデータをそのまま実行するらしいのでシェルを起動するだけ。"binsh"が含まれていると実行されないのと0x28バイトしか入力できない。これらの制約を満すシェルコードを作る必要がある。"binsh"については上位4bitと下位4bitを互い違いに加算するようにすれば誤魔化せる、長さは上手いこと調節したり。time.sleep(3)io.sendline(payload)io.interactive()久しぶり過ぎて色々忘れていて面倒だった。spiritまで来た。spirit自体の解説はhttps://github.com/shellphish/how2heap、問題はhttps://github.com/ctfs/write-ups-2014/tree/master/hack-lu-ctf-2014/oreoにある。Writeupはなしで解けた!問題fileとchecksecは以下。(0x8048000)x86でセキュリティ機構は普通。Rifleを購入するプログラムになっていて、名前や説明の入力をして注文したり、メモのようなものを残すことができる。解析Radareで解析してマニュアルデコンパイルしたコードは以下。return;}ちょっと整理されてない。add_rifleに脆弱性があり、バッファのサイズを指定するべき場所に構造体tmp_stのサイズが指定されているため、ヒープ上でのバッファオーバーフローが存在している。よってtmp_st.nameから0x38だけ任意の値に書き換えられる、例えばnextとか。これによりリンクリストの次の領域を任意のアドレスに指定できるので、任意の領域をfreeすることができる。spirit簡単に説明すると、chunkと同じように値を設定してやることでheap領域以外をfreeしてfastbinsに繋ぐ攻撃である。することで任意の領域をmallocに返させて、値を書き込んだりできるようになる。spiritを使うことは分かっているので、それを意識して考えてみた。すると、グローバル変数の値を適切に設定してやれば、ヒープオーバーフローでfreeさせられそうだと思い付いた。msgあたりをmallocで返したい。そこで、msgの上のlist_countにサイズを設定しmsgをfreeすることで、次のadd_rifleで指しているアドレスを改ざんできるようにすることを目指した。spiritによりadd_rifleでアドレスを改ざんできるようになったので、書き換えるべきアドレスを探した。GOTを書き換えられるので、ユーザの入力を受け取る標準関数sscanfを書き換えることにした。libcのバージョンを特定する必要があったため2つ以上の関数のアドレスをリークさせる必要があるがsscanfは一番最後の領域にあったため直接sscanfを指すようにしてしまうとうまくlibcのリークとGOTの書き換えが両立できない。そこで、ひとつ上のlibc_mainを指定してリークと書き換えが1度にできるようにした。'\0')io.interactive()まとめ時間はかかったけど自力で解けたので嬉しい。exploitationのお勉強、Writeup見ちゃった。参考にしたのはshellphishのhow2heap。実行ファイルだけ降ってくる。解くのにlibcが必要になるが、途中で任意アドレスの読み出しができるようになるので、ライブラリ関数のアドレスからlibcのバージョンが特定できるはず。(0x400000)普通のx64といった感じ。実行してみると、malloc、free、read、writeができるっぽい感じだと分かる。リバーシングしてみると、いくつか脆弱性を含んでいることが分かる。buf);}まず、いくつかの場所でmenu_num_bufを1バイトオーバーフローしている。このため、直下にあるbender_flgの下位1バイトを好きなように操作できる。freeされてもアドレスが残りっぱなしになっている点も脆弱性として利用できる。freeを利用して任意のアドレスをmallocで返せることを使って、powerfulの領域をmallocで返させる。6(destructor)を適当なサイズで取得し、その後でpowerfulをより大きいに設定することで、ヒープオーバーフローができるようにする。unlinkができるようになる。unlinkができれば、グローバル変数の値を改ざんしてGOTを適当に書き換えてlibcベースをリーク、systemでシェルの起動につなげればいい。exploitはWriteupのほぼ丸パクリ、動かなかった部分だけ修正した。systemなので、system("sh")となるio.interactive()細かいことはexploit中のコメントに書いた。freeは成立しないと思ってた。サイズのチェックか何かあった気がしたけどそんなことはなかった、何事も試してみるのが大事だね。exploitationのお勉強、初めてWriteup途中で見ずに解けて嬉しい。参考にしたのはshellphishのhow2heap。解く上でlibcが必要になるが、Hintととして動作環境が出されているし脆弱性を突けば任意のGOT領域の関数アドレスを表示できるので、該当するlibcのバージョンを特定して入手するのは容易のはず。今回はそれを省いてローカルのlibcをいきなり使っている。問題stkofというバイナリだけが降ってくる。fileとchecksecの出力は以下。(0x400000)普通の64bitバイナリといった感じになっている。動作させてみると、何も出力されず何をしていいか分からなかった。リバーシングしてみたところ、ほとんど何も出力しないが入力は受け付けるようになっていた。解析しないことには動作させることもままならなかったので、手動デコンパイルした。0;}1から4までの数字を受け付けて、malloc、キー入力、free、長さのチェックができることが分かる。キー入力で長さのチェックがないため、ヒープでのバッファオーバーフローが存在していることが分かる。mallocしたチャンクはグローバル領域の配列で管理されていて、ASLRでもアドレスがランダム化されない。freeするとアドレスは0クリアされるので、double-freeはできない。unlinkという手法を使う。mallocしたチャンクを書き換えてfree済みであると誤認させ、unlinkという機能を使わせることによって、あるメモリ領域を書き換えることができるという手法である。手法自体はhow2heapとかkatagaitaiのスライドとかに解説がある。unlinkで、unlinkするチャンクのアドレスが格納されている場所を、その場所から0x18上ぐらいの位置のアドレスに書き換えることができる。配列にチャンクが格納されていることと併せて考えると、配列の中身を配列自身のアドレスに書き換えられることになる。すると、配列に格納されたアドレスへの書き込みで配列中のアドレスを任意の値に設定できるので、任意のアドレスへの書き込みができることになる。これを利用してfree@GOTをputs@PLTに書き換えたあと、配列中のアドレスをGOTに設定することで関数アドレスを表示させたり、smallbinを指すfdを表示させたりして、libcベースをリークさせる。smallbinを指すfdを表示させる方法を使った。RCEを呼び出してシェルを起動すればいい。呼び出しは、libcベースのリークと同じように適当なGOTの関数アドレスを書き換えてやればいい。putsを途中で書き換えるためタイムアウトさせる。PREV_INUSEを1にする(2はunlinkしないので)。userdata、余った領域を適当に埋める。oneshot_rceio.interactive()libc内のオフセットは環境によって違うので適宜読み替えて欲しい。まとめ初めてほぼ自力で解けたのでとても嬉しい。unlinkを使っていたのもあって、解法を簡単に思い付けた。やっている最中にチャンクのサイズとかヒープのレイアウトとかも間違えていたりしたので、まだまだ練習が必要だと感じた。速く解くことを目標にする。SleepyHolderを解いたのでそのメモ。問題自体はここから、参考にしたWriteupはここ。shellphishの方のリンクはヒントも載っている上にlibcがないので見ない方がいいかも。SleepyHolderというプログラムとlibcが降ってくる。解析リバースしたソースコードはこんな感じ。freeができそうというのが分かる。freeすることも分かる。それ以上は分からなかった。ここでもうwriteupを見て、exploitを解析しながら解いた。unlinkも同時に使うらしい。unlinkはkatagaitai勉強会の第1回目のスライドを参考にした。unlinkを成立させる。unlinkによってグローバル領域にあるsmall_secretにはsmall_secret+0x18の値が格納される。次に、small_secret+0x18に書き込みをしてグローバル変数を改ざんする。big_secretにfree@GOTを格納することで、freeの呼び出しをputsの呼び出しにする。gadgetでsystemを起動できるアドレスを取得する。gadgetを設定する。これで次のputsの呼び出しでシェルが起動できる。exploitはこんな感じ、ほとんどwriteupの方のコピーで動作のメモをしただけ。タイミングの問題か、引数でDEBUGを指定しないとうまく動いてくれない。0はprev_size、0x21はサイズになる。exploitのお勉強のためにhttps://github.com/shellphish/how2heapを解いたので(Writeup見ながらだけど)、そのメモ。問題fastbin_dup_into_stackの9447-search-engineを解いた。問題のリンクはhttps://github.com/ctfs/write-ups-2015/tree/master/9447-ctf-2015/exploitation/search-engine。リンク先にあるhttps://github.com/pwning/public-writeup/tree/master/9447ctf2015/pwn230-searchとhttps://www.gulshansingh.com/posts/9447-ctf-2015-search-engine-writeup/を参考にした。問題で与えられたプログラムは、文字列の登録と検索して削除する機能がある。登録した文字列はヒープに格納されるようになっているが、削除でfreeされた後も検索可能になっている脆弱性がある。削除されるときに0埋めされるので、元々の文字の長さのヌル文字で検索すればもう一度freeすることができる。freeができるようになっている。ひとつの脆弱性は数値を読み込む処理でバッファ長だけ入力するとヌル終端されないバグがあり、スタック上の値を読み込めてしまう脆弱性がある。うまく調節してスタック中にあるスタックを指すアドレスをリークさせる。freeを使ってsmallbinsのfdをリークさせて、そこからlibcのベースアドレスを計算する。dupを使って、同じチャンクをfreeリストに繋ぐことで、スタック上のリターンアドレスのあるアドレスをヒープのアドレスとして取得する。gadgetを指すアドレスを設定して、シェルを起動する。以上のような流れになる。freeがあるから任意の読み書きができるとかの説明がまったく理解できなかったけど分かるようになった。解説は見てどういう現象が起きるのかは知っていたけど、どう使えるのかが分かってなかった。2つ問題を解いて、大分イメージできるようになってきた。exploit自分で書き直したやつ、雑なのであとで整理したい。数日間cowrieを動かしてみたので、どんな感じになったのか簡単に書いおく。2018/11/24(今も稼働中)。総接続数は約30000ほどで、そのうち14675は同じIPからの通信だった。Miraiに感染されているらしいけどやたら試行が多い。ダウンロードされたマルウェアの固体数はだいたい270前後だった。ハッシュが一致するものはひとつとして数えていて、実際には同じマルウェアが1400回くらいダウンロードされたりしてる。VirusTotalによるとだいたいがMirai系で、その他はxorddosがいくつかと、BashのIRCボット、PerlのIRCボットが2つくらいだった。一度配布してるマルウェアが変わったサーバがいた、他のやつに感染したんだろうか?特定のネットワークアドレスのホストから何度も変なアクセスがあって、TCPフォワーディングか何かで検索クエリみたいなアドレスとかがログに残っていた。いうアクセスなのかまったく分からなかった。特定のアドレスではなくネットワークアドレスが一致する複数のホストからアクセスされているのも気になった。Whoisの情報では同じ組織に割り当てられているらしいので、内部で感染拡大したのだろうか?失敗したコマンドもログに残るようになっているが、構文エラーでダウンロードに失敗しているマルウェアもいた。可能なものは手動でダウンロードしてきた。先頭に#!/bin/shがあったので、スクリプトとして保存して実行するつもりだったのかもしれない。ほとんどはパッキングされていなかったが、いくつかUPXでパックされているものや、簡単な難読化がほどこされているものもあった。いうマルウェアは目に見えてVirusTotalでの検知率が低かったのが印象的だった。実際にどれくらい攻撃がくるのかとかが分かって面白かったので、他のハニポも使っていきたいなあ。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。