OverTheWire やってみた(Bandit 編)
最近、CTF(Capture the flag)という言葉をよく聞くので入門者向けのやつをやってみた。YouTube 上にビギナー向けの CTF サービスを紹介している 動画 があり、それが OverTheWire の Wargames をオススメしていたのでやってみた。
今回は初心者向けの bandit 編を順番に解いてみた。次の問題に行くにはパスワードが必要であり、そのパスワードを発見するのが各問題の課題という感じ。ちなみに自分は Linux は自宅用デスクトップ PC として普段使いしているので基本的なコマンドや OS の概念はだいたい分かっている。しかし、何事もあまりマニアックな使い方をしない性格なので、そういう知識を要するのがあったら詰みそう。
ではレッツゴー。
Level 0
ターミナルから ssh
コマンドを叩いてリモートサーバにログインするだけ。ユーザは bandit0
。
Level1
cat
コマンドを叩いてファイルの中身を見るとパスワードの文字列がある。これがユーザ bandit1
のパスワードになっているので再度 ssh でログインする。
Level2
パスワードは -
という名前のファイル内にある。cat -
だとコマンドオプションだと認識されるのが、ファイルのフルパスで指定すると意図通りのファイルが認識される。知らなかったがググればすぐ分かる話ではある。
Level3
パスワードを含むファイル名に空白文字(スペース)が含まれるパターン。ファイル名をエスケープして cat
すればよいが、これは tab キーでファイル名を補完できるのでなんてことない。これは Linux を普段使いしているとたまにやる操作。
Level4
パスワードは隠しファイル内にあるだけ。簡単。
Level5
パスワードが複数のファイルのうちどれかの中にある。ほとんどのファイルが空っぽなので、find . -type f | xargs wc -l
あたりでファイルごとの行数を見て発見した。
Level6
パスワードが複数のファイルのうちどれかの中にある。ファイルサイズがヒントとして与えられている。find . -type f | xargs -d '\n' wc | grep 1033
あたりでファイルサイズで調べて発見した。
Level7
パスワードが複数のファイルのうちどれかの中にある。user と group とファイルサイズがヒントとして与えられているので、find / -type f | xargs ls -l | grep bandit7
あたりでユーザ名で grep
すると1件しか見つからなかったのでそれが答えだった。find
コマンドのマニュアル読めばユーザの検索とかできそう。
Level8
パスワードが指定のファイル内にあることが分かっている。そのファイル内において millionth
という文字列の横にパスワードがあるらしい。普通に grep
したら発見。
Level9
パスワードが指定のファイル内にあることが分かっている。このファイルに含まれるユニークな文字列が正解らしい。リダイレクトしながら diff
ってみた。diff <(sort -u data.txt) <(sort data.txt | uniq -D | uniq)
で差分が1行だけになったのでこれが正解。なんか無理矢理感がある。ユニークな列だけ抽出するみたいなコマンドオプションがあればもっとスマートにできそう。
Level10
パスワードが指定のファイル内にあることが分かっている。このファイルに含まれる、人間が読めて いくつか =
が続く文字列の直後がパスワードらしい。ってことで strings
コマンドを用いて ASCII 文字列っぽいものを抽出してみた。strings data.txt | grep ==
で答えを発見。strings
コマンド初めて使った。バイナリファイルの解析とかに使えそう。
Level11
パスワードが Base64 でエンコードされている。base64 -d data.txt
みたいに base64
コマンドを使ってデコードするとパスワードを発見。
Level12
パスワードが ROT13 により暗号化されている。シーザー暗号の一種。ただし数字はそのまま。各文字を元に戻せばよいので tr
コマンドで置換した。対応する文字を愚直に列挙した。パスワードの復号に成功。
cat data.txt | tr -s 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' 'nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
Level13
パスワードを含むファイルが何らかの方式で繰り返し圧縮されている。圧縮ファイルの先頭を見れば圧縮方式が分かるようになっており xxd
コマンドで見ながら bzip2
,gzip
, tar
コマンドを繰り返し適用した。けっこうダルかった。結果的にパスワードを含むテキストファイルが出てきた。
圧縮ファイルの方式は以下を参考にした。よく見ると2つ目の回答の file
コマンドをたたくやり方の方が楽そう。
Level14
ssh
コマンドを bandit14
でログインするが、このときプライベートキーを食わるだけ。
Level15
telnet
コマンドでポート 30000
に現在のパスワードを送信する。具体的には telnet localhost 30000
で接続したあとパスワードを貼り付ければオッケー。
Level16
SSL 通信でポート 30001
に接続する。openssl
の s_client
を使うと SSL 通信ができる。openssl s_client -connect localhost:30001
を実行すればオッケー。このあたりは使い慣れてないのでググりながらやった。
Level17
localhost のポートの範囲 31000
- 32000
のどれかに SSL 通信を受け継いているものがあるらしい。nmap
コマンドを使って nmap -p31000-32000 localhost
のようにスキャン。いくつか有効なポートが見つかるのでひとつずつ opensll s_client -connect
で接続できるか試した。ひとつだけ秘密鍵を返すものがあたのでそれを次の SSH に食わせた。
nmap
コマンドはよく知らなかったので man
コマンドでマニュアルを見た。
Level18
diff
コマンド叩くだけ。
Level19
パスワードは readme
ファイルにあるが、.bashrc
の設定により、ssh
コマンドでログインすると即座にログアウトされてしまうらしい。ってことで ssh
コマンドを叩くときに cat readme
することでパスワードを取得できた。ssh って Docker 動かすときみたいにコマンド叩けるんだ。知らなかった。
Level20
/etc/bandit_pass/bandit20
にパスワードが書かれているが、現在のユーザ bandit19
では読み取り権限がない。そこで、bandit20-do
コマンドを使って一時的に bandit20
の権限を獲得したうえでパスワードが書かれたファイルへアクセスすればよい。具体的には ./bandit20-do cat /etc/bandit_pass/bandit20
というコマンドを実行した。
こういう権限を一時的に獲得するような仕組みは setuid と呼ばれている。実行ファイルに対して chmod
コマンドで設定できるらしい。
Level21
tmux
コマンドでターミナルを2画面開く。片方のターミナルで nc -l -p 1234
のようにサーバを起動して接続待ちをする。それに対して、もう片方のターミナルで ./suconnect 1234
のようにアクセスすることで接続が確立される。nc
コマンドを実行している方で前回のパスワードを送信すると次のパスワードが返される。nc
コマンドの使い方がよく分かっていなかったのでけっこう時間かかった。
Level22
cron の設定ファイルが /etc/cron.d/
の中にいくつかある。それらはスクリプトファイル(sh
ファイル)を実行するように設定されているが、その中に現在のユーザ bandit21
でも読み取り権限があるスクリプトがある。それの中を見るとパスワードの書かれた /etc/bandit_pass/bandit22
を cat
していることが分かるので、そのリダイレクト先のファイルを見ればパスワードが手に入る。
ちなみに cron の設定ファイルである crontab ファイルの5つのアスタリスク * * * * *
は指定されたコマンドを毎分実行するようなスケジュールを意味する。
Level23
前の問題と同様に現在のユーザ bandit22
で読み取り権限のあるスクリプトが1つだけある。その中身を見ると、whoami
コマンドの実行結果をもとに計算したハッシュ値をファイル名としてパスワードを書き込んでいることが分かる。cron によってこのスクリプトが実行されるときのユーザは bandit23
なので bandit23
という文字列を与えてこのハッシュ値を計算してみる。すると書き込まれたファイル名が分かるのでパスワードを入手できる。
Level24
bandit24
によって定期実行される /usr/bin/cronjob_bandit24.sh
のスクリプトの中身を見ると /var/spool/bandit24
の中のスクリプトが実行されることが分かる。よってパスワードを出力する cat
コマンドをこのディレクトリ内に仕込めばよい。具体的には、結果を /tmp
配下にリダイレクトする cat
コマンドをもつスクリプトを作成し bandit24
が実行できるように chmod
し、cp
コマンドによってコピーした。1分ほど待てばパスワードがリダイレクト先のファイルに書き込まれる。
Level25
brute-force で 0000
から 9999
を 30002
番ポートに送り続ける必要がある。そこで for i in {0000..9999}; do echo (省略) $i; done | nc localhost 30002 | tail
のように for
文を書いて入力候補をすべて作ったあとで nc
コマンドでポートに送信。やがて答えが見つかった。
Level26
getent passwd | grep bandit26
するとユーザ bandit26
のログインシェルが bash ではなく/usr/bin/showtext
になっていることが分かる。このなかでは more
コマンドが実行されている。このため bandit26
にログインしてもすぐにログアウトされてしまう。
ここからどう打開するか分からずこの問題の正解をググった。どうやら、ターミナルの画面サイズを小さくしておくことで more
の画面がコマンドを受け付ける状態で止まり、ここで v
を押すと vi が立ち上がるらしい。なるほど。vi 内で :set shell=/bin/bash
に続けて :shell
を実行すればシェルが起動する。これで bandit26
としてログインできたことになる。
Level27
前の手順に続き、bandit27-do
なる実行ファイルがあるため、これに cat
を引数として与えるとパスワードを表示できる。
Level28
/tmp
ディレクトリに移動して git clone
するだけ。clone したディレクトリにパスワードが書かれている。
Level29
/tmp
ディレクトリに移動して git clone
する。なぜかパスワードがマスキングされているが、git log
を見るとマスキング前のデータがありそうなことが分かる。そこで git diff (前のバージョンのハッシュ値)
してパスワードゲット。
Level30
/tmp
ディレクトリに移動して git clone
する。パスワードは not in production らしい。リモートブランチを見てみると dev
ブランチとかがあって怪しいのでこれを pull してきて中身をみるとパスワード発見。
Level31
git tag
で secret という名前のタグを発見できる。これを git show
するとパスワードの文字列を発見。これはなかなか時間かかった。タグという発想はなかった。
Level32
.gitignore
に注意しながら push
するだけ。ここに来て簡単。
Level33
打った文字が大文字になって実行されるシェルがいきなり起動する。大文字に変換されても問題なく実行できるコマンドが必要そう。しかし思いつかずこの問題の解法をググった。どうやら $0
で sh
が呼ばれるらしい。これでコマンドが叩けるようになったのでパスワードを cat
できるようになった。
2021年8月現在ではこれにてすべての課題クリア。めでたし。
所感
初めて CTF 系の問題をやってみたが、各問題が上手く作られた感じがあって飽きずに楽しめた。普段はネットワーク系など低めのレイヤに触れることがあまりないので今回はよい勉強になった。それにしても、手がかりが見つからないときは本当に何をしてよいのか分からない。CTF が強い人はたくさんの攻めパターンを知っていて、それを順番に調べてみるみたいなことをするんだろうと思う。これぞハッカーの道だ。また気が向いたらこういうのやろう。