2018研究でわけのわからない命令を発行しすぎてなぜかメモリバスエラーが頻出するようになりラップトップ崩壊、泣く泣く新しい物を購入して今に至ります。タイミングが悪すぎる。いうわけで過去問解いたログだけでも供養しておきます。reloadedは未だに1チームしか解けてないマゾゲーなので今は断念。V9は近いうちに解くつもり。pt)概要ユーザーとそのユーザーが所属するグループを管理するプログラム。ユーザーを追加する際、所属するグループを指定する。該当グループが既に存在すればポインタを張る。無ければ新たにグループを作成して同様にポインタを張る。Collection)が動作しており、定期的にグループリストを走査、memberが0になったつまり誰も所属していないグループは削除するようになっている。DeleteUser()で削除した際にデクリメントされるようになっている。これはユーザーのgroup_keyに一致するグループ全てのmemberをデクリメントする。3のEditGroup()でグループ名(group_key)を別名に変更できるが、文字列に対するバリデーションは特に無い。これら2点を悪用すると、それぞれ"group_A"と"group_B"に所属するユーザーAとBを作成。(member--)memberが0になりGCによって両方共グループがfreeされる。(freed)と、ヒープに対するダングリングポインタが出来る。残念ながらヒープ上にvtable等の関数ポインタが存在しないので、ヒープエクスプロイトテクニックを考えるのが良さそう。fastbinsで管理されている。3のEditGroup()によってfree済みのチャンクgroup_keyを書き換える事でfreeチャンクのfdを書き換えできる。fdを任意のアドレスに書き換えて、その後mallocを実行させていくと該当アドレスの領域を使ってくれる。これにより任意のアドレスにポインタを通してアクセス可能になる。freeチャンクのfd書き換えはfastbinsの場合malloc(2)時にセキュリティチェックが走り、abortしてしまう。ところがtcacheを使う場合はこの限りではない。tcacheは7スロットしかチャンクをキャッシュできず足りなくなった場合は通常通りfastbinsを使用する。tcacheが足りずfastbinsを使用し始めた状況をpwndbgで確認すると以下のようになる。0x0smallbinsemptylargebinsemptyさて、この後mallocを発行してtcacheに空きが出来るとどうなるかと言うとfastbinsからtcacheに移動させて、次回のmallocに備えるようになる。問題はこの移動の処理が発生した場合fastbinsのセキュリティチェックが走らない事だ。#endifつまりチャンクのfdを改竄しても、fastbinsから直接取得するのではなくtcacheを一旦通せばすんなりmallocできてしまう。今回注意しなければならないのはスレッドがメイン(以下T1)とGC用(以下T2)の2つあり、arenaとtcacheが2つあるという事。mallocするのはメインスレッド側でfreeするのはGC側なので、それぞれアクセスするtcacheが違う。ダングリングポインタによって汚染するチャンクはT2のtcacheにあるため、T1側でmallocしても汚染チャンクを取得させる事ができない。基本的には"あるスレッドでmallocした領域を、別のスレッドでfreeしても該当チャンクはmallocした側のスレッドのfreeリストに繋がれる"が成り立つ。addr)という関係が成り立つからだ。T1でmallocしたアドレスをどのスレッドでfreeした場合でも、arenaのアドレスはT1の物に計算される。KOSAKIwww.slideshare.netしかしながらtcacheだけは上記の例外でT1でmallocしてもT2でfreeすればT2側のarenaのtcacheに保存される。よってエクスプロイトは以下のような手順になる。T2側でfreeを7回以上行ってtcacheを使い切る。chunkでmallocが可能となる。今回はこれをuser[0]のアドレスに改竄。&user[0]となり、後はgroup_keyを通してuser[0]を改竄する。この後user[0]->group_keyをEditGroup()でsystemのアドレスに書き換えると、free@GOTがsystemのアドレスに書き換わる。その後DeleteUser(0)でfree(user[0]->name)が実行されsystem("/bin/sh")でシェルが取れる。ヒープのアドレスはfreeチャンクのfdをリークさせる事で計算できる。libcのアドレスはfreeチャンクが1つのみの際、fdがarena内のメンバを指しているためこの値から計算できる。linkされたバイナリでグローバル変数のバッファに文字を入力(scanf)し出力(printf)するだけ。入力文字数に制限を書けていないのでバッファオーバーフローする。leakでフラグは表示できそうだ。-txしてみる癖とか付けておいたほうが良いのか。今回の難点は__libc_argvをフラグのアドレスに書き換えてもスタック破壊が起きないのでfortify_failが呼ばれない点だ。printfの実装を調査すると一定条件下で__printf_arginfo_tableを実行してくれる処理があるらしい。NULLで__printf_arginfo_tableを調整すれば任意のアドレスをcallできる。これでfortify_failを呼べば良い。pt)概要0x300バイト単位のスロットを確保/解放/読み書きできるプログラム。Orangelibc2.24で動作するためtcacheはない。ヒープ上にvtableのような関数ポインタもなく、またSimpleGCの時のようにヒープ上のポインタ(key_slot)を通した読み書きもできない。このバイナリ独自のロジックの中でPC制御やAAR/Wに応用できる要素はほぼ無い。vtalbe)を書き換える事でPCを制御する方法である。attackによって任意のアドレスに対して限定的な値を書き込む事が出来る。(av)が代入される。(av)は、チャンクが1つしか存在しない場合arena内のメンバのアドレスになる。smallbins[4]->bk)にfakeのFILE構造体を設定、vtable->__overflowを改ざんする事で任意アドレス実行を促す事ができる。Orangeが使用できる。attackの対策が施されている。Orangeのようにvtable->overflowをsystem関数などの正規のセクション外のアドレスに書き換えるとabortしてしまうというものだ。Orangeを行う事もできる。(fp->_wide_data->_IO_buf_base);fakeのFILE構造体から_free_bufferと_IO_buf_baseの値を設定すればsystem("/bin/sh")を呼ぶことができる。system関数を呼ぶのではなく、一旦正規の関数への呼び出しを挟む事でvtableチェックはバイパスできる。pt)概要Rubyのコードを送ると実行してくれるサーバーがある。RubyのVMにはseccompによるsandboxを実装した独自パッチが適用されており、Ruby上でflagを読み込んだりコマンドを実行する事は不可能になっている。escapeを行ってフラグを読み出せという物。11LFAは内部でmallocのbinsのようなデータ構造を2つ生成してリンクする。bins[15000]各binsは決められた数のチャンクを持っておりbins->start_idxから始まる一定個数の要素を格納している。15000のbinsを生成しそこに格納する。近い添字の要素をひとまとめにして、離散的に管理している。問題の脆弱性はarr.removeを実行した時に発生する。LFAは要素数が1チャンク以下になった時、キャッシュ用に確保しておいた固定長の配列内にチャンクを移してリストで管理する事をやめる。この処理が発生した時のみ、LFAの要素数を表すメンバを更新していないという脆弱性である。#OOW一旦$arr[$ooa_size]でサイズを$ooa_sizeにした状態で残り1チャンクを削除すると、サイズは変わらず、実際はキャッシュ用の固定長配列にアクセスしようとする。このキャッシュ配列へのアクセスは$ooa_sizeまで行えるためOOR/Wが発生する。Fengshuiさて、Ruby上で巨大なヒープに対するOOR/Wが行えるとなれば次はどうするか。Fengshuiというテクニックが利用しやすい。1年ほど前のプレゼン資料参照。speakerdeck.comStringやArrayといった内部的にポインタを持っているデータ構造をヒープ上に確保して、内部ポインタを書き換える事で任意のアドレスに読み書きが行えるようになるというもの。今回はRubyのString(内部的にはRString)とArray(RArray)を悪用する。1end#getsおわりに急いで書いたので雑な説明かも。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。