初心者が挑むCTF入門 | OverTheWire: Bandit Level 0~20

CTF入門として評判のOverTheWire: Banditを、前提知識のほとんどない状態から挑んでみました。 始め方から、問題を解く際の試行錯誤までを詳細に記録します。

まずはLevel0からLevel10までを解いてみました。

※Level20まで追記しました。



Introduction

CTFをやってみたいと思い立ちました。 きっかけはこのLiveOverfow氏の動画です。

youtu.be

彼のリバースエンジニアリング入門動画などは好きで見ていたので1、彼の勧めるCTFには以前から興味がありました。

CTF (Capture The Flag)とは、その名の通り旗取り合戦のことです。 FPSゲームでの陣取り合戦もこれに当たるようですが、ここではコンピュータセキュリティにおけるCTFを指しています。 CTF用に用意されたサーバーに入ったり、プログラムを解析したりして、Flagと呼ばれる文字列の発見を目指すクイズ形式の競技のようなものだそうです。

キャプチャー・ザ・フラッグ - Wikipedia

正直あまりイメージが掴めませんが、とても面白そうな香りがします。 私はネットワークも全くわからない初心者なので、とりあえず初心者向けのCTFに挑戦してみたいと思います。

CTFには制限時間がある競技形式のものと、常に開かれている常設CTFがあります。 競技形式のものは初心者にはハードルが高いので、常設CTFをやってみることにしました。

上の動画でもおすすめされている、OverTheWireというサイトで開かれているCTFに挑んでみることにします。

overthewire.org

このサイトのWargamesというCTF集のうち、もっとも初心者向けのBanditをやっていきます。

右も左もわからない状態なので、ひとつひとつ確認していきながら、試行錯誤の記録を残します。


Material

OSについては注意が必要です。 ターミナルからのUnixコマンド操作を前提としているそうなので、Windowsでやろうとすると何かと厄介でしょう。

私はUbuntu18.04.1 LTS を
Windows10の上に、VMwareによって構築した仮想環境で起動しています。
www.bioerrorlog.work


Results


Level 0

sshの使い方

OverTheWire: Bandit Level 0

それではLevel0からやっていきます。 問題文はこれです。

The goal of this level is for you to log into the game using SSH. The host to which you need to connect is bandit.labs.overthewire.org, on port 2220. The username is bandit0 and the password is bandit0. Once logged in, go to the Level 1 page to find out how to beat Level 1.

sshなるものを用いて、このサイトにログインするのが一番最初のLevel 0 の目的のようです。

ログインするホスト名は bandit.labs.overthewire.org
ポート番号は 2220
ユーザーネームは bandit0
パスワードは bandit0
となっています。

ログインという操作は日常的に慣れ親しんでいますが、ここで出てきたsshコマンドでのログインには経験がありません。 少し調べることにします。

まずはsshのマニュアルを読みます。

$ man ssh
NAME
 ssh — OpenSSH SSH client (remote login program)
~
DESCRIPTION
 ssh (SSH client) is a program for logging into a remote machine and for
 executing commands on a remote machine. 

sshは、遠隔マシンにログインしてコマンドを実行するためのプログラムのようです。 今回の私のケースだとbandit.labs.overthewire.org にログインして、そこでコマンド操作が行えるようになる、ということでしょう。

マニュアルを読み進めて、sshコマンドの使い方を調べます。

SYNOPSIS
 ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]
   [-D [bind_address:]port] [-E log_file] [-e escape_char]
   [-F configfile] [-I pkcs11] [-i identity_file]
   [-J [user@]host[:port]] [-L address] [-l login_name] [-m mac_spec]
   [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]
   [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]
   [user@]hostname [command]

膨大なオプションの記述に圧倒されそうですが、落ち着いて今回必要な部分を抽出します。 今回ログインに使う情報は、ホスト名、ポート番号、ユーザー名、パスワードでした。 これらを上のオプションから読み出すと、使い方は次のようになるはずです。

ssh hostname [-l login_name] [-p port] 

パスワードを指定するオプションが見当たりませんが、後で接続時に要求されるのでしょうか。

とりあえずこれに従うなら、

ssh bandit.labs.overthewire.org -l bandit0 -p 2220 

とすれば上手くいきそうです。

※次のように記述しても上手くいきました。
ssh bandit0@bandit.labs.overthewire.org -p 2220

コマンドを実践する前に、もう一点確認したいことがあります。 sshで接続を確立した後、どのようにして接続を切ればいいのでしょうか。 再びマニュアルを確認すると、

~.      Disconnect.

接続を切るには ~. と入力すれば良いようです。

exitと入力しても、接続を終了することができました。


以上でだいたい使い方は分かりました。
さっそく実践してみます。


sshログイン

それでは上記コマンドを実行します。

$ ssh bandit.labs.overthewire.org -l bandit0 -p 2220
 
The authenticity of host '[bandit.labs.overthewire.org]:2220 ([176.9.9.172]:2220)'
can't be established.ECDSA key fingerprint is 
SHA256:98UL0ZWr85496EtCRkKlo20X3OPnyPSB5tB5RPbhczc.
Are you sure you want to continue connecting (yes/no)? 

何やら警告を吐かれました。 ホストの信憑性が確立できませんでしたが、接続を続けていいですか?という感じのことを聞かれています。

よくわからなかったので検索をかけてみると、これはログインしたことのないホストにアクセスする際に出る警告だそうです。

yesとして先へ進みます。

yes

Warning: Permanently added '[bandit.labs.overthewire.org]:2220,[176.9.9.172]:2220' (ECDSA) to the list of known hosts.
This is a OverTheWire game server. More information on http://www.overthewire.org/wargames

bandit0@bandit.labs.overthewire.org's password: 

パスワードを要求されました。
bandit0を入力すると、

Linux bandit 4.18.12 x86_64 GNU/Linux
               
      ,----..            ,----,          .---. 
     /   /   \         ,/   .`|         /. ./|
    /   .     :      ,`   .'  :     .--'.  ' ;
   .   /   ;.  \   ;    ;     /    /__./ \ : |
  .   ;   /  ` ; .'___,/    ,' .--'.  '   \' .
  ;   |  ; \ ; | |    :     | /___/ \ |    ' ' 
  |   :  | ; | ' ;    |.';  ; ;   \  \;      : 
  .   |  ' ' ' : `----'  |  |  \   ;  `      |
  '   ;  \; /  |     '   :  ;   .   \    .\  ; 
   \   \  ',  /      |   |  '    \   \   ' \ |
    ;   :    /       '   :  |     :   '  |--"  
     \   \ .'        ;   |.'       \   \ ;     
  www. `---` ver     '---' he       '---" ire.org     
               
              
Welcome to OverTheWire!

   ・
   ・ 中略
   ・

  Enjoy your stay!

bandit0@bandit:~$ 
  #  bandit0にログイン完了

見事、bandit0へのログインに成功しました。
Level0の目的達成です。


Level 0 → Level 1

次の問題です。

The password for the next level is stored in a file called readme located in the home directory. Use this password to log into bandit1 using SSH. Whenever you find a password for a level, use SSH (on port 2220) to log into that level and continue the game.

次のレベルに行くためのパスワードは、ホームディレクトリにあるreadmeというファイルに書かれている、とあります。 そのパスワードを用いてbandit1にログインせよ、とのことです。

さっそく調べます。

$ ls    #カレントディレクトリのファイルを表示
readme
$ cat readme    #readmeの中身を表示
boJ9jbbUNNfktd78OOpsqOltutMc3MY1

readmeファイルの中にパスワードboJ9jbbUNNfktd78OOpsqOltutMc3MY1を見つけました。

exitでbandit0への接続を終了してから、見つけたパスワードを使ってbandit1にログインします。

$ ssh bandit.labs.overthewire.org -l bandit1 -p 2220
This is a OverTheWire game server. More information on http://www.overthewire.org/wargames

bandit1@bandit.labs.overthewire.org's password: 
    # boJ9jbbUNNfktd78OOpsqOltutMc3MY1を入力
   ・
   ・ 中略
   ・

  Enjoy your stay!

bandit1@bandit:~$ 

bandit1へのログインに成功しました。 Level1達成です。


Level 1 → Level 2

次の問題です。

The password for the next level is stored in a file called - located in the home directory

パスワードは-というファイルに入っている、とのことです。 さっそく調べてみます。

$ ls
-
$ cat -

  # コマンドが実行されない

ここで問題が生じました。 -ファイルの中身を見るためにcat -を打ち込んだのですが、コマンドが実行されませんでした。

これは考えてみれば当然のことです。 コマンドラインでは-という文字はオプションの指定に使われます。 なので、cat -と打ってしまうと、ターミナルは次に続くオプションの入力を待ってしまうわけです。

そこで、まず思いついたのはエスケープ記号を使うことです。 調べてみると、bashでは3つのエスケープ方法があるようです。 \を打つやり方、シングルクオーテーション' 'で囲むやり方、ダブルクオーテーション" "で囲むやり方です。

しかし、このどれを実行しても今回の問題は解決されませんでした。

そこで、別の方法を考えてみます。 思いついたのは、もう少し丁寧にファイル名を指定してあげることです。 つまり、パスを含めてファイルを指定します。

$ cat ./-
CV1DtqXWVFXTvM2F0k09SHz0YwRINYA9

見事、パスワードを読み出すことができました。

このパスワードを使ってLevel2にログインすれば、Level1達成です。


Level 2 → Level 3

次の問題です。

The password for the next level is stored in a file called spaces in this filename located in the home directory

spaces in this filenameというファイルの中に、次のパスワードが入っているようです。

注意したいのは、ファイル名にスペースが含まれていることです。 そのままのファイル名をcatコマンドに渡すと、次のようにspacesinthisfilenameそれぞれが別のファイルとみなされてしまいます。

$ ls
spaces in this filename
$ cat spaces in this filename
cat: spaces: No such file or directory
cat: in: No such file or directory
cat: this: No such file or directory
cat: filename: No such file or directory

そこで、Level1でも言及したエスケープ文字を使います。 spaces in this filenameを、シングルクォーテーション' 'で囲んであげる訳です。

$ cat 'spaces in this filename'
UmHadQclWmgdLOKQ3YNgjWxGoRMb5luK

これで、パスワードが手に入りました。


Level 3 → Level 4

次の問題です。

The password for the next level is stored in a hidden file in the inhere directory.

inhereディレクトリの中にある隠しファイルに、パスワードが書かれているようです。

まずはinhereディレクトリに移動し、そこにあるファイルをlsコマンドで見てみます。

$ ls
inhere
$ cd inhere    # inhereに移動
$ ls
  #  ファイルが一つも表示されない

lsコマンドでは、ファイルが表示されませんでした。

そこで、lsコマンドのオプション-aを使うことにします。 -aオプションは、マニュアルによると、

-a, --all
 do not ignore entries starting with .

.からはじまる隠しファイルを無視せず表示することができます。

さっそくやってみます。

$ ls -a
.  ..  .hidden

.hiddenという隠しファイルが現れました。 中身を見ます。

$ cat .hidden
pIwrPrtPN36QITSp3EQaw936yaFoFgAB

みごとパスワードがありました。


Level 4 → Level 5

The password for the next level is stored in the only human-readable file in the inhere directory. Tip: if your terminal is messed up, try the “reset” command.

inhereディレクトリの中には"人間が読める"ファイルがあり、そこにパスワードが書いてある、とあります。

さっそくinhereディレクトリに行き、ファイルを見てみます。

$ cd inhere
$ ls -la  #すべてのファイルをリストで表示
total 48
drwxr-xr-x 2 root    root    4096 Oct 16  2018 .
drwxr-xr-x 3 root    root    4096 Oct 16  2018 ..
-rw-r----- 1 bandit5 bandit4   33 Oct 16  2018 -file00
-rw-r----- 1 bandit5 bandit4   33 Oct 16  2018 -file01
-rw-r----- 1 bandit5 bandit4   33 Oct 16  2018 -file02
-rw-r----- 1 bandit5 bandit4   33 Oct 16  2018 -file03
-rw-r----- 1 bandit5 bandit4   33 Oct 16  2018 -file04
-rw-r----- 1 bandit5 bandit4   33 Oct 16  2018 -file05
-rw-r----- 1 bandit5 bandit4   33 Oct 16  2018 -file06
-rw-r----- 1 bandit5 bandit4   33 Oct 16  2018 -file07
-rw-r----- 1 bandit5 bandit4   33 Oct 16  2018 -file08
-rw-r----- 1 bandit5 bandit4   33 Oct 16  2018 -file09

-file00から-file09までの9つのファイルがあります。

どのファイルが"人間が読める"ファイルなのかを確認するために、fileコマンドでファイルタイプを確認します。

ここで、-がそれぞれのファイル名の先頭にあることに注意です。 次のように安易にfileコマンドを使ってしまうと、

$ file *    #  すべてのファイルにfileコマンドを実行
file: Cannot open `ile00' (No such file or directory).
file: Cannot open `ile01' (No such file or directory).
file: Cannot open `ile02' (No such file or directory).
file: Cannot open `ile03' (No such file or directory).
file: Cannot open `ile04' (No such file or directory).
file: Cannot open `ile05' (No such file or directory).
file: Cannot open `ile06' (No such file or directory).
file: Cannot open `ile07' (No such file or directory).
file: Cannot open `ile08' (No such file or directory).
file: Cannot open `ile09' (No such file or directory).

-をオプション記号と捉えられ、うまく実行できません。 そういうときは、Level2で出てきたように、パスから指定してあげれば上手くいきそうです。

$ file ./*
./-file00: data
./-file01: data
./-file02: data
./-file03: data
./-file04: data
./-file05: data
./-file06: data
./-file07: ASCII text
./-file08: data
./-file09: data

まさしく、-file07のみがASCIIテキストファイルであることが分かりました。 中身を見ると、

$ cat ./-file07
koReBOKuIDDepwhWk7jZC0RTdopnAYKh

パスワードが見つかりました。

ちなみに-file07以外のファイルを見ようとすると、

$ cat ./-file01
���U"7�w���H��ê�Q����(���#���

まさに、"人間には理解できない"文字列が入っていました。


Level 5 → Level 6

The password for the next level is stored in a file somewhere under the inhere directory and has all of the following properties:
human-readable
1033 bytes in size
not executable

inhereディレクトリ下のどこかに、次の条件を満たすファイルがあるとのことです。
・"人間が読める"
・1033バイトのファイルサイズ
・実行可能でない

まずはとりあえず、inhereディレクトリのファイルを見てみます

$ cd inhere/
$ ls -la
total 88
drwxr-x--- 22 root bandit5 4096 Oct 16  2018 .
drwxr-xr-x  3 root root    4096 Oct 16  2018 ..
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere00
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere01
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere02
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere03
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere04
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere05
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere06
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere07
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere08
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere09
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere10
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere11
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere12
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere13
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere14
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere15
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere16
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere17
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere18
drwxr-x---  2 root bandit5 4096 Oct 16  2018 maybehere19

maybehere00からmaybehere19までの20個のファイルがありました。 これらのファイルタイプを確認してみると、

$ file *
maybehere00: directory
maybehere01: directory
maybehere02: directory
maybehere03: directory
maybehere04: directory
maybehere05: directory
maybehere06: directory
maybehere07: directory
maybehere08: directory
maybehere09: directory
maybehere10: directory
maybehere11: directory
maybehere12: directory
maybehere13: directory
maybehere14: directory
maybehere15: directory
maybehere16: directory
maybehere17: directory
maybehere18: directory
maybehere19: directory

すべてがディレクトリでした。 これらの中に入っているファイルのうち、上記3つの条件を満たしているものを探します。

findコマンドを用いて、「1033バイトのファイルサイズ」かつ「実行可能でない」ものを検索します。 まずはfindコマンドのマニュアルから、ファイルサイズ検索に関するオプションを探しました。

-size n[cwbkMG]
    File uses n units of space, rounding up.   The  following  suffixes
    can be used:
(中略)
    `c'    for bytes

これによると、-size 1033cとすれば、1033バイトのファイルサイズを持つファイルが見つけられそうです。

次に実行可能性を検索するオプションを探すと、

-executable
    Matches files  which  are  executable  and  directories  which  are
    searchable 

-executableオプションによって、実行可能なファイルが検索できるようです。 今回私は「実行可能でない」ファイルを検索したいので、逆に! -executableとすれば良いでしょう。

この2つの条件でfindしてみます。

$ find -size 1033c ! -executable
./maybehere07/.file2

見事ひとつのファイルが検索に引っかかりました。 このmabehere07ディレクトリにある.file2のファイルタイプを確認すると、

$ file ./maybehere07/.file2
./maybehere07/.file2: ASCII text, with very long lines

ASCIIテキストファイルなので、もう一つの条件「人間が読める」も満たしそうです。 このファイルの中身を見てみます。

$ cat ./maybehere07/.file2
DXjZPULLxYr17uwoI01bNLQbtFemEgo7

見事、パスワードがありました。


Level 6 → Level 7

The password for the next level is stored somewhere on the server and has all of the following properties:
owned by user bandit7
owned by group bandit6
33 bytes in size

サーバーのどこかに、次の3つの条件を満たすファイルがあるそうです。
・ユーザーbandit7に所有されている
・グループbandit6に所有されている
・サイズが33バイト

では、とりあえずfindコマンドで33バイトのファイルを検索してみます。 「サーバーのどこかに」とあるので、ルートディレクトリから検索をかけます。

$ find / -size 33c
  #  /  はルートディレクトリを示す
find: ‘/run/lvm’: Permission denied
find: ‘/run/screen/S-bandit10’: Permission denied
find: ‘/run/screen/S-bandit4’: Permission denied
find: ‘/run/screen/S-bandit3’: Permission denied
find: ‘/run/screen/S-bandit22’: Permission denied
find: ‘/run/screen/S-bandit18’: Permission denied
find: ‘/run/screen/S-bandit17’: Permission denied
find: ‘/run/screen/S-bandit25’: Permission denied
・
・以下略
・

膨大な量のファイルがヒットしてしまいました。 やはり、ファイルサイズ以外の2つの条件を上手く使わないとダメみたいです。

ユーザーとグループによる所有権を検索するオプションがないか、findのマニュアルを調べてみると、

-user uname
    File is owned by user uname (numeric user ID allowed).
・・・
-group gname
    File belongs to group gname (numeric group ID allowed).

-user-groupによって、それぞれの所有権を指定できるようです。 さっそくやってみます。

$ find / -size 33c -user bandit7 -group bandit6
find: ‘/run/lvm’: Permission denied
find: ‘/run/screen/S-bandit10’: Permission denied
find: ‘/run/screen/S-bandit4’: Permission denied
find: ‘/run/screen/S-bandit3’: Permission denied
find: ‘/run/screen/S-bandit22’: Permission denied
find: ‘/run/screen/S-bandit18’: Permission denied
・
・以下略
・

さっきよりは検索結果が絞られましたが、まだfind: ~~~ : Permission deniedなどのエラー出力が大量に残っています。 そこで、検索結果のなかでエラー出力を非表示にする方法を調べました。

出力をリダイレクトする>を使えば、エラーを排除できるようです。 ある記事2によると、

command 2>/dev/null

This syntax redirects the command error output messages to /dev/null where it is ignored by the shell.

2>を使うことで、エラー出力をリダイレクトすることができるそうです3。 そしてリダイレクト先は/dev/nullです。 このファイルに書き込まれたデータは、システムによって破棄されます。

つまり2>/dev/nullとすることで、エラー出力を排除することができるというわけです。 さっそくやってみます。

$ find / -size 33c -user bandit7 -group bandit6 2>/dev/null
/var/lib/dpkg/info/bandit7.password

お見事、ファイルがひとつだけヒットしました。 ファイルを読み出して、目的達成です。

$ cat /var/lib/dpkg/info/bandit7.password
HKBPTKQnIay4Fw76bEy8PVxKEDQRKTzs


Level 7 → Level 8

The password for the next level is stored in the file data.txt next to the word millionth

data.txtファイルの中のmillionthという単語の隣に、次のパスワードがあるそうです。

とりあえずdata.txtを見てみます。

$ ls
data.txt
$ cat data.txt
・
・
Sutherland  GPj6IhYqUlcjb8hYdtbwpKUtIKeSHXNC
Michigan's  rjQZqJB52C0ioveSov6Wt0nLK5zZrUvw
Arthurian   HqnDL5cvz8MhI8ctfyGmQ7OoGVksICqg
matrimony's rQTEVD0A0SvNHsNqgt4GICdnJX86TSkE
tendering   5ARBlVJ1K20R1K7kYNNfp3cJ2KJWm9l1
・
・

このように、[単語] [文字列]となっている行が延々と続いています。 このなかで、millionthの単語に続く文字列がパスワードということでしょう。

grepコマンドに出力を渡し、millionthを検索します。

$ cat data.txt | grep millionth    #catの結果をgrepにパイプする
millionth   cvX2JJa4CFALtqS87jk27qwqGhBM9plV

この右の部分がパスワードです。


Level 8 → Level 9

The password for the next level is stored in the file data.txt and is the only line of text that occurs only once

data.txtの中に一度だけ現れる行がパスワードとなるようです。

一度だけ現れるといえば、uniqコマンドが使えそうです。

NAME
    uniq - report or omit repeated lines
・・・
-u, --unique
    only print unique lines

マニュアルによると、uniq -uとすることで一度だけ現れる行を抽出できるようです。 さっそくやってみます。

$ uniq -u data.txt
KerqNiDbY0zV2VxnOCmWX5XWxumldlAe
MsxcvOe3PGrt78wpZG2bBNF5wfXpZhET
L0nxAwlfV9V3J5onKIT8KYQ9InTcQ7yE
4c7EsUtqLnLR9hiepV5EQVhdMgyi8onL
1drBmDT7PYS7hVgoTWkJSjUZUK7ZAIAa
L0nxAwlfV9V3J5onKIT8KYQ9InTcQ7yE
・
・以下略
・

予想外にも、膨大な行が抽出されてしまいました。 そこで、もう一度真面目にuniqマニュアルを読んでみると、次のような記述がありました。

Note: 'uniq' does not detect repeated lines unless they  are  adjacent.
You  may want to sort the input first, or use 'sort -u' without 'uniq'.

uniqコマンドは、隣り合った行でないと繰り返しを認識しないため、ソートしてから使いなさい、とあります。

そこで、今度はsortコマンドでソートしてからuniqコマンドに渡してみます。

$ sort data.txt | uniq -u
UsvVyFSfZZWbi6wgC7dAFyFuR6jQQUhR

見事、検出された行がひとつに絞られました。 これがパスワードです。


Level 9 → Level 10

The password for the next level is stored in the file data.txt in one of the few human-readable strings, beginning with several ‘=’ characters.

data.txtの中にある"人間が読める"文字列のうち、いくつかの=文字からはじまるものが次のパスワードのようです。

まず、data.txtファイルの中の"人間が読める"文字列を探すために、stringsコマンドを使いました。

$ strings data.txt
.MBB
`B6ha
nK)U2u
&y@@2
5Lo%
ru@n
・
・
・

この表示された大量のテキスト中から、先頭に=を持つ行を検索すれば良いわけです。

検索には、grepコマンドを正規表現と組み合わせて使いました。 つまり、行の先頭を指定する正規表現^を組み合わせて、=を検索するのです。

$ strings data.txt | grep ^=
========== password
========== isa
=FQ?P\U
=   F[
=)$=
========== truKLdjsbJ5g7yyJ2X2R0o3a5HQJFuLk

見事、一番下に出たtruKLdjsbJ5g7yyJ2X2R0o3a5HQJFuLkこそがパスワードです。


Level 10 → Level 11

The password for the next level is stored in the file data.txt, which contains base64 encoded data

次のパスワードは、base64エンコードされたデータを含むdata.txtのなかにあるそうです。

base64とは、wikipediaによると4

Base64は、データを64種類の印字可能な英数字のみを用いて、それ以外の文字を扱うことの出来ない通信環境にてマルチバイト文字やバイナリデータを扱うためのエンコード方式である。 (中略) 具体的には、A–Z, a–z, 0–9 までの62文字と、記号2つ (+, /)、さらにパディング(余った部分を詰める)のための記号として = が用いられる。

A–Z, a–z, 0–9と、+、/そして余った部分に埋められる=を用いて行われるエンコード方式のようです。 これを読み出すには、base64方式でデコードする必要があるということでしょう。

試しに、まずは単純にstringsコマンドでテキストを読み込んでみます。

$ strings data.txt 
VGhlIHBhc3N3b3JkIGlzIElGdWt3S0dzRlc4TU9xM0lSRnFyeEUxaHhUTkViVVBSCg==

この文末の==が、余った部分に埋められるパディングということでしょう。 なので読み出した文字列はVGhlIHBhc3N3b3JkIGlzIElGdWt3S0dzRlc4TU9xM0lSRnFyeEUxaHhUTkViVVBSCgということになります。

しかし、案の定この文字列では次のLevel11にログインすることができませんでした。 base64でデコードしなきゃいけないわけでしょう。

そこでbase64コマンドを使います。 マニュアルによると、

NAME
    base64 - base64 encode/decode data and print to standard output
・・・
-d, --decode
    decode data

base64コマンドの-dオプションを使えば、デコードできるようです。

$ base64 -d data.txt 
The password is IFukwKGsFW8MOq3IRFqrxE1hxTNEbUPR

これでパスワードを見つけました。


Level 11 → Level 12

The password for the next level is stored in the file data.txt, where all lowercase (a-z) and uppercase (A-Z) letters have been rotated by 13 positions

パスワードは、小文字(a-z)と大文字(A-Z)を13個ローテーションさせてあるdata.txtにあるそうです。

文字を13こローテーションさせるとは、どういうことでしょうか。 検索してみると、これは「ROT13」という暗号のようです。 wikipediaによると5

ROT13 または ROT-13、rot13 は単換字式暗号(シーザー暗号)の一つである。アルファベットを一文字毎に13文字後のアルファベットに置き換える。Aは Nに、 B は O に置き換えられ、以下同様である。英語の "Rotate by 13 places" の略。

それではこの暗号を解くために、trコマンドを使います。 trコマンドは、マニュアルによると、

NAME
    tr - translate or delete characters
・・・
SYNOPSIS
    tr [OPTION]... SET1 [SET2]

例えばtr abc 127とすれば、aは1、bは2、cは3と翻訳されるということです。

$ echo abc | tr abc 123
123

つまりROT13を解くためには、それぞれの文字に対応する13個ローテーションさせた翻訳を指定してあげればいいでしょう。 具体的には、次のようにしました。

$ cat data.txt | tr A-Za-z N-ZA-Mn-za-m
The password is 5Te8Y4drgCRfCx8ugdwuEX8KFC6k2EUu

これで、パスワードを割り出すことができました。


Level 12 → Level 13

The password for the next level is stored in the file data.txt, which is a hexdump of a file that has been repeatedly compressed. For this level it may be useful to create a directory under /tmp in which you can work using mkdir. For example: mkdir /tmp/myname123. Then copy the datafile using cp, and rename it using mv (read the manpages!)

パスワードはdata.txtの中に、繰り返し圧縮されたhexdumpとして記述されているようです。 そして、/tmpディレクトリ下にmkdirコマンドで作業用のディレクトリを作り、そこにcpコマンドでデータをコピーするのがいいですよ、と助言しています。

これはどういうことでしょうか。
とりあえずdata.txtの中を見てみます。

$ ls 
data.txt
$ cat data.txt 
00000000: 1f8b 0808 d7d2 c55b 0203 6461 7461 322e  .......[..data2.
00000010: 6269 6e00 013c 02c3 fd42 5a68 3931 4159  bin..<...BZh91AY
00000020: 2653 591d aae5 9800 001b ffff de7f 7fff  &SY.............
00000030: bfb7 dfcf 9fff febf f5ad efbf bbdf 7fdb  ................
00000040: f2fd ffdf effa 7fff fbd7 bdff b001 398c  ..............9.
00000050: 1006 8000 0000 0d06 9900 0000 6834 000d  ............h4..
00000060: 01a1 a000 007a 8000 0d00 0006 9a00 d034  .....z.........4
00000070: 0d1a 3234 68d1 e536 a6d4 4000 341a 6200  ..24h..6..@.4.b.
00000080: 0069 a000 0000 0000 d003 d200 681a 0d00  .i..........h...
00000090: 0001 b51a 1a0c 201e a000 6d46 8068 069a  ...... ...mF.h..
000000a0: 6834 340c a7a8 3406 4000 0680 0001 ea06  h44...4.@.......
000000b0: 8190 03f5 4032 1a00 0343 4068 0000 0686  ....@2...C@h....
000000c0: 8000 0320 00d0 0d00 0610 0014 1844 0308  ... .........D..
000000d0: 04e1 c542 9ab8 2c30 f1be 0b93 763b fb13  ...B..,0....v;..
000000e0: 50c4 c101 e008 3b7a 92a7 9eba 8a73 8d21  P.....;z.....s.!
000000f0: 9219 9c17 052b fb66 a2c2 fccc 9719 b330  .....+.f.......0
00000100: 6068 8c65 e504 5ec0 ae02 fa6d 16bc 904b  `h.e..^....m...K
00000110: ba6c f692 356e c02b 0374 c394 6859 f5bb  .l..5n.+.t..hY..
00000120: 0f9f 528e 4272 22bb 103c 2848 d8aa 2409  ..R.Br"..<(H..$.
00000130: 24d0 d4c8 4b42 7388 ce25 6c1a 7ec1 5f17  $...KBs..%l.~._.
00000140: cc18 ddbf edc1 e3a4 67f1 7a4d 8277 c823  ........g.zM.w.#
00000150: 0450 2232 40e0 07f1 ca16 c6d6 ef0d ecc9  .P"2@...........
00000160: 8bc0 5e2d 4b12 8586 088e 8ca0 e67d a55c  ..^-K........}.\
00000170: 2ca0 18c7 bfb7 7d45 9346 ea5f 2172 01e4  ,.....}E.F._!r..
00000180: 5598 673f 45af 69b7 a739 7814 8706 04ed  U.g?E.i..9x.....
00000190: 5442 1240 0796 6cc8 b2f6 1ef9 8d13 421d  TB.@..l.......B.
000001a0: 461f 2e68 4d91 5343 34b5 56e7 46d0 0a0a  F..hM.SC4.V.F...
000001b0: 72b7 d873 71d9 6f09 c326 402d dbc0 7cef  r..sq.o..&@-..|.
000001c0: 53b1 df60 9ec7 f318 00df 3907 2e85 d85b  S..`......9....[
000001d0: 6a1a e105 0207 c580 e31d 82d5 8646 183c  j............F.<
000001e0: 6a04 4911 101a 5427 087c 1f94 47a2 270d  j.I...T'.|..G.'.
000001f0: ad12 fc5c 9ad2 5714 514f 34ba 701d fb69  ...\..W.QO4.p..i
00000200: 8eed 0183 e2a1 53ea 2300 26bb bd2f 13df  ......S.#.&../..
00000210: b703 08a3 2309 e43c 44bf 75d4 905e 5f96  ....#..<D.u..^_.
00000220: 481b 362e e82d 9093 7741 740c e65b c7f1  H.6..-..wAt..[..
00000230: 5550 f247 9043 5097 d626 3a16 da32 c213  UP.G.CP..&:..2..
00000240: 2acd 298a 5c8a f0c1 b99f e2ee 48a7 0a12  *.).\.......H...
00000250: 03b5 5cb3 0037 cece 773c 0200 00         ..\..7..w<...

このように、データはhexdump形式で記述されています。 hexdumpとは、データを16進数で表現したもので、ちょうど上のような表示形式を取るものです。

このhexdumpで記述されたデータを、xxdコマンドを使って読み出します。

NAME
  xxd - make a hexdump or do the reverse.
・・・
-r | -revert
  reverse operation

xxdとは、hexdumpを作成したり解読(リバース)したりするコマンドです。 -rオプションを使うとリバースすることができるようです。 さっそくやってみます。

$ xxd -r data.txt 
���6��@4bi���hBZh91AY&SY����������ϟ���������������׽��9��
     �mF�h�h44
D��B��,0�� ��4@�����@2C@h�� �
               �v;�P��;z�����s�!��+�f���̗�0`h�e�^���m��K�l��5n�+tÔhY���R�ɋ�^-K�����}�\,�ǿ�}E�F�_!r�U�g?E�i��9x��TB@�lȲ���BF.hM�SC4�V�F�

��\��WQO4�p�i�����S�#&��/߷�#ŀ��ՆF�<D�uԐ^_�H6.�-��wAt
                                                            �[��UP�G�CP��&:�2�*�)�\�������H�
�\�7��w<

このように、"人間には読めない"文字列が出てきてしまいました。 何が記述されているのか、検討もつきません。

そこで、この文字ファイルがどのようなファイルタイプなのか、調べることにします。 xxdコマンドで読み出した結果を別ファイルに出力し、fileコマンドでファイルタイプを見れば良いでしょう。

問題文で推奨されているように、新しい作業用ディレクトリ(/tmp/lain) を作成してdata.txtをコピーし、そこで作業することにします。

~$ mkdir /tmp/lain
~$ cp data.txt /tmp/lain
~$ cd /tmp/lain
/tmp/lain$ ls
data.txt

それでは、xxdコマンドで読み出し、ファイルタイプを調べます。

$ xxd -r data.txt > data_rev
$ file data_rev
data_rev: gzip compressed data, was "data2.bin", last modified: Tue Oct 16 12:00:23 2018, max compression, from Unix

どうやら、gzip圧縮されたファイル形式だったようです。 -d(decompress)オプションでgzipコマンドを実行し、ファイルを解凍します。

$ gzip -d data_rev
gzip: data_rev: unknown suffix -- ignored

接尾字がおかしい、と怒られてしましました。 そこで、gzipファイルの拡張子.gzをつけてから実行してみます。

$ cat data_rev > data_gz.gz
$ gzip -d data_gz.gz
$ ls
data_gz  data_rev  data.txt

解凍ファイルdata_gzが作成されました。 またファイルタイプを確認します。

$ file data_gz
data_gz: bzip2 compressed data, block size = 900k

今度はbzip2方式で圧縮されているようです。

まさに問題文にあったように、繰り返し圧縮されている、ということでしょう。 ここからは根気強く、ファイルタイプを調べては必要に応じて拡張子を変更し、圧縮方式にあった解凍を施していきます。

## 解凍2回目
$ cat data_gz > data_bz2.bz2    # bzip2の拡張子は .bz2
$ bzip2 -d data_bz2.bz2    # bzip2解凍
$ ls
data_bz2  data_gz  data_rev  data.txt

## 解凍3回目
$ file data_bz2
data_bz2: gzip compressed data, was "data4.bin", last modified: Tue Oct 16 12:00:23 2018, max compression, from Unix
$ cat data_bz2 > data_gz-2.gz
$ gzip -d data_gz-2.gz    # gzip2解凍
$ ls
data_bz2  data_gz  data_gz-2  data_rev  data.txt

## 解凍4回目
$ file data_gz-2
data_gz-2: POSIX tar archive (GNU)
$ cat data_gz-2 > data_tar.tar    # tarの拡張子は .tar
$ tar -xvf data_tar.tar    # tar解凍
data5.bin
$ ls
data5.bin  data_bz2  data_gz  data_gz-2  data_rev  data_tar.tar  data.txt

## 解凍5回目
$ file data5.bin
data5.bin: POSIX tar archive (GNU)
$ tar -xvf data5.bin     # tar解凍 (.binのままでも解凍できた)
data6.bin
$ ls
data5.bin  data_bz2  data_gz-2  data_tar.tar
data6.bin  data_gz   data_rev   data.txt

## 解凍6回目
$ file data6.bin
data6.bin: bzip2 compressed data, block size = 900k
$ cat data6.bin > data_bz2-2.bz2
$ bzip2 -d data_bz2-2.bz2     # bzip2解凍
$ ls
data5.bin  data_bz2    data_gz    data_rev      data.txt
data6.bin  data_bz2-2  data_gz-2  data_tar.tar

## 解凍7回目
$ file data_bz2-2
data_bz2-2: POSIX tar archive (GNU)
$ cat data_bz2-2 > data_tar2.tar
$ tar -xvf data_tar2.tar    # tar解凍
data8.bin
$ ls
data5.bin  data8.bin  data_bz2-2  data_gz-2  data_tar2.tar  data.txt
data6.bin  data_bz2   data_gz     data_rev   data_tar.tar

## 解凍8回目
$ file data8.bin
data8.bin: gzip compressed data, was "data9.bin", last modified: Tue Oct 16 12:00:23 2018, max compression, from Unix
$ cat data8.bin > data_gz-3.gz
$ gzip -d data_gz-3.gz    # gzip解凍
$ ls
data5.bin  data8.bin  data_bz2-2  data_gz-2  data_rev       data_tar.tar
data6.bin  data_bz2   data_gz     data_gz-3  data_tar2.tar  data.txt
$ file data_gz-3
data_gz-3: ASCII text

計8回の解凍を経て、ついに生のASCII textにたどり着くことができました。

$ cat data_gz-3
The password is 8ZjyCRiBWFYkneahHwxCv3wb2a1ORpYL

長い道のりでしたが、ようやくパスワードにありつきました。


Level 13 → Level 14

The password for the next level is stored in /etc/bandit_pass/bandit14 and can only be read by user bandit14. For this level, you don’t get the next password, but you get a private SSH key that can be used to log into the next level. Note: localhost is a hostname that refers to the machine you are working on

次のパスワードは、ユーザーbandit14にしか読み込めない/etc/bandit_pass/bandit14に入っています。 このレベルではパスワードが手に入らない代わりに、次のレベルにログインするためのSSH秘密鍵が手に入るそうです。

「次のレベルにログインするためのSSH秘密鍵」というのが、何を言っているのか私には分かりません。 問題文とともにヒントとして掲載してある次のページで、SSH秘密鍵でのログインについて調べてみます。

SSH/OpenSSH/Keys - Community Help Wiki

これによると、SSH鍵でのログインは、パスワードログインよりもより安全なログイン方法だそうです。

具体的に言うと、ログイン先PCの~/.ssh/authorized_keysにSSH公開鍵が登録され、それと対になるSSH秘密鍵が自身の~/.ssh/id_rsaに入っていれば、ログインが成功するという仕組みです。

つまり、SSH秘密鍵が手に入ったなら、~/.ssh/id_rsaを作成し、それに書き込めば良さそうです。

それではやっていきます。

$ ls
sshkey.private
$ cat sshkey.private 
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAxkkOE83W2cOT7IWhFc9aPaaQmQDdgzuXCv+ppZHa++buSkN+
gg0tcr7Fw8NLGa5+Uzec2rEg0WmeevB13AIoYp0MZyETq46t+jk9puNwZwIt9XgB
・
・中略
・
kAWpXbv5tbkkzbS0eaLPTKgLzavXtQoTtKwrjpolHKIHUz6Wu+n4abfAIRFubOdN
/+aLoRQ0yBDRbdXMsZN/jvY44eM+xRLdRVyMmdPtP8belRi2E2aEzA==
-----END RSA PRIVATE KEY-----

さっそくSSH秘密鍵が見つかりました。

自分のPC側に戻り、~/.ssh/id_rsaを作成してSSH秘密鍵をコピーペーストで追加します。

$ exit
logout
Connection to bandit.labs.overthewire.org closed.
$ cd .ssh
$ ls
known_hosts    # id_rsaはまだ存在しない
$ vim id_rsa
           # id_rsaを作成し、上記SSH秘密鍵をコピーペースト
$ ls
id_rsa  known_hosts
$ file id_rsa 
id_rsa: PEM RSA private key      # 秘密鍵として登録された

これで、~/.ssh/id_rsaにSSH秘密鍵が登録されたはずです。

bandit14へのログインを試みます。

$ ssh bandit14@bandit.labs.overthewire.org -p 2220
This is a OverTheWire game server. More information on http://www.overthewire.org/wargames

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/<user name>/.ssh/id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.

秘密鍵が守られていない、という警告が出され、秘密鍵が認証されませんでした。

パーミッションを確認してみると、

$ ls -l id_rsa 
-rw-r--r-- 1 user user 1680  5月  2 12:13 id_rsa

たしかに、オーナー以外にもファイルの読み込みが許可されています。

※パーミッションの読み方については、以前別記事に記録しました。 www.bioerrorlog.work

そこでchmodコマンドを用いて、オーナー以外のパーミッションを拒否します。

$ chmod 600 id_rsa      # オプションに600を与え、オーナー以外のパーミッションを拒否 (オーナーはrw)
$ ls -l id_rsa
-rw------- 1 user user 1680  5月  2 12:13 id_rsa

これでパーミッションも設定できました。

bandit14のログインにリベンジします。

$ ssh bandit14@bandit.labs.overthewire.org -p 2220
This is a OverTheWire game server. More information on http://www.overthewire.org/wargames
・
・
・
  Enjoy your stay!

bandit14@bandit:~$ 

みごと、ログインに成功しました。


Level 14 → Level 15

The password for the next level can be retrieved by submitting the password of the current level to port 30000 on localhost.

このレベルのパスワードを、ローカルホストのポート30000に送ることで、次のレベルのパスワードを回収することができる、とあります。

まずこのレベルのパスワードですが、Level13の問題文によると/etc/bandit_pass/bandit14にあるようです。

$ cat /etc/bandit_pass/bandit14
4wcYUJFw0k0XLShlDzztnTBHiqxU3b3e

あとはこのパスワードを、ローカルホストのポート30000に送ればいいのでしょう。 ちなみにローカルホストとは、いま作業しているPCのことです。

データを送るには、今回ncコマンドを使います。 マニュアルによると、

nc [destination] [port]       # destinationは"送り先"

この使い方で接続が確保できるようです。

このnc接続にパスワードを渡すことで、ローカルホスト/ポート30000にパスワードを送りつけます。

$ cat /etc/bandit_pass/bandit14 | nc localhost 30000
Correct!
BfMYroe26WYalil77FoDi9qh59eK5xNr

これで次のパスワードが入手できました。


Level 15 → Level 16

The password for the next level can be retrieved by submitting the password of the current level to port 30001 on localhost using SSL encryption.

このレベルのパスワードを、SSL暗号化した上でローカルホストのポート30001に送ることで、次のレベルのパスワードを回収することができる、とあります。

先程の問題と似ていますが、今度はSSL暗号をかける必要があるようです。

そこで今回はopenssl s_clientコマンドを使います。 マニュアルによると、

The s_client command implements a generic SSL/TLS client which connects
to a remote host using SSL/TLS. 

遠隔ホストにSSL/TLSを使って接続する、クライアントとして振る舞ってくれるようです。

使い方は、

openssl s_client [-connect host:port]

となっていました。

それでは、これでパスワードを渡してみます。

$ echo BfMYroe26WYalil77FoDi9qh59eK5xNr | openssl s_client -connect localhost:30001
CONNECTED(00000003)
・
・中略
・
---
DONE

接続には成功したようですが、何もこちらに返さずに終了してしまいました。

ここで問題文に付記してある注意書きを見てみると、

Helpful note: Getting “HEARTBEATING” and “Read R BLOCK”? Use -ign_eof and read the “CONNECTED COMMANDS” section in the manpage. Next to ‘R’ and ‘Q’, the ‘B’ command also works in this version of that command…

-ign_eofオプションを使いなさい、というアドバイスが載っています。 -ign_eofとは、マニュアルによると、

-ign_eof
  inhibit shutting down the connection when end of file is reached in
  the input.

入力まで処理が届いたときに、接続を切断するのを防ぐ、とあります。

入力に対して何か反応があるときには、-ign_eofを指定することでその反応を見ることができる、ということでしょうか。 さっそくやってみます。

$ echo BfMYroe26WYalil77FoDi9qh59eK5xNr | openssl s_client -connect localhost:30001 -ign_eof
CONNECTED(00000003)
・
・中略
・
---
Correct!
cluFn7wTiGryunymYOu4RcffSxQluehd

closed

見事、次のパスワードが返ってきました。


Level 16 → Level 17

The credentials for the next level can be retrieved by submitting the password of the current level to a port on localhost in the range 31000 to 32000. First find out which of these ports have a server listening on them. Then find out which of those speak SSL and which don’t. There is only 1 server that will give the next credentials, the others will simply send back to you whatever you send to it.

このレベルのパスワードをローカルホストに送りつければ、次の認証が得られるようです。 ただし、31000~32000の範囲の開いているポートを使う必要があります。 まず開いているポートを見つけ出してから、SSLを受け付けるポートを探し、それを使ってパスワードを送ります。

31000~32000の範囲の開いているポートを探すために、nmapコマンドを使いました。 マニュアルによると、

NAME
  nmap - Network exploration tool and security / port scanner
・・・
-p <port ranges>: Only scan specified ports
  Ex: -p22; -p1-65535;

nmapはポートスキャナーとしての機能を持っており、-pオプションでそのパート番号の範囲を指定できるようです。 さっそくやってみます。

$ nmap -p31000-32000 localhost

Starting Nmap 7.40 ( https://nmap.org ) at 2019-05-02 09:49 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00020s latency).
Not shown: 998 closed ports
PORT      STATE SERVICE
31046/tcp open  unknown
31790/tcp open  unknown
31960/tcp open  unknown

開いているポートが3つ検出できました。

つぎは、この3つのポートのうちSSL対応しているものを探します。 これには前のレベルで使ったopenssl s_clientを利用しました。 SSLに対応できないポートなら、openssl s_clientでは接続できないはずです。 ポートを一つずつ試していきます。

$ openssl s_client -connect localhost:31046
CONNECTED(00000003)
140211373733120:error:141A10F4:SSL routines:ossl_statem_client_read_transition:unexpected message:../ssl/statem/statem_clnt.c:269:
---
no peer certificate available
---
No client certificate CA names sent
・
・以下略
・

1つめはエラーを吐きました。 SSL対応でなかったのでしょう。

次のポートを試します。

$ openssl s_client -connect localhost:31790
CONNECTED(00000003)
depth=0 CN = localhost
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = localhost
verify return:1
---
Certificate chain
 0 s:/CN=localhost
   i:/CN=localhost
---
Server certificate
・
・中略
・
---

今度は接続に成功しました。 そして入力待機状態なので、このレベルのパスワードを打ち込みます。

cluFn7wTiGryunymYOu4RcffSxQluehd
Correct!
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAvmOkuifmMg6HL2YPIOjon6iWfbp7c3jx34YkYWqUH57SUdyJ
imZzeyGC0gtZPGujUSxiJSWI/oTqexh+cAMTSMlOJf7+BrJObArnxd9Y7YT2bRPQ
Ja6Lzb558YW3FZl87ORiO+rW4LCDCNd2lUvLE/GL2GWyuKN0K5iCd5TbtJzEkQTu
・
・中略
・
blh9elyZ9FsGxsgtRBXRsqXuz7wtsQAgLHxbdLq/ZJQ7YfzOKU4ZxEnabvXnvWkU
YOdjHdSOoKvDQNWu6ucyLRAWFuISeXw9a/9p7ftpxm0TSgyvmfLF2MIAEwyzRqaM
77pBAoGAMmjmIJdjp+Ez8duyn3ieo36yrttF5NSsJLAbxFpdlc1gvtGCWW+9Cq0b
dxviW8+TFVEBl1O4f7HVm6EpTscdDxU+bCXWkfjuRb7Dy9GOtt9JPsX8MBTakzh3
vBgsyi/sN3RqRBcGU40fOoZyfAMT8s1m/uYv52O6IgeuZ/ujbjY=
-----END RSA PRIVATE KEY-----

こうして秘密鍵が手に入りました。

後は、この秘密鍵を用いて次のレベルにログインします。

私の場合~/.ssh/id_rsaにはLevel14の秘密鍵を書き込んであるので、今度は別名で秘密鍵を保存し、SSH接続時に-iオプションで指定するやり方をとってみます。

$ vim .ssh/bandit17_rsa
          # 入手した秘密鍵を記入
$ ssh bandit17@bandit.labs.overthewire.org -p 2220 -i .ssh/bandit17_rsa
                                                                                 # -i オプションで秘密鍵を指定
・
・中略
・

  Enjoy your stay!

bandit17@bandit:~$

これで、Level17へのログインに成功しました。


Level 17 → Level 18

There are 2 files in the homedirectory: passwords.old and passwords.new. The password for the next level is in passwords.new and is the only line that has been changed between passwords.old and passwords.new

passwords.newの中にある文字列のうち、passwords.oldとの差分がパスワードだそうです。

diffコマンドで差分を見ていきます。

$ ls
passwords.new  passwords.old
$ diff passwords.new passwords.old 
42c42
< kfBf3eYk5BPBRzwjqutbbfE887SVc5Yd
---
> hlbSBPAWJmL6WFDb06gpTx1pPButblOA

42c42とあるので、42行目が両者の違いとなっているようです。

そのうち1つめの引数に渡したpasswords.newにあった文字列は、---の上側にでてきた方となります。

つまり、kfBf3eYk5BPBRzwjqutbbfE887SVc5Ydがパスワードです。


Level 18 → Level 19

The password for the next level is stored in a file readme in the homedirectory. Unfortunately, someone has modified .bashrc to log you out when you log in with SSH.

次のパスワードはホームディレクトリのreadmeファイルの中にあります。 しかし、誰かが.bashrcファイルを書き換えてしまい、SSHでログインすると同時にログアウトするようになってしまいました、とのことです。

.bashrcとは、bash起動時に実行されるシェルスクリプトです。 たしかに、このLevel18にログインすると、次のように勝手にログアウトされてしまいます。

$ ssh bandit18@bandit.labs.overthewire.org -p 2220
・
・中略
・
  Enjoy your stay!

Byebye !
Connection to bandit.labs.overthewire.org closed.

そこで、sshコマンドを使って、ログインすることなくreadmeの中身を見ます。

sshコマンドは文末に別のコマンドを指定すると、ログインすることなく遠隔でそのコマンドを実行することができます。

ssh [user@]hostname [command]
・・・
If command is specified, it is executed on the remote host instead of a login shell.

さっそく試します。

$ ssh -p 2220 bandit18@bandit.labs.overthewire.org cat readme
This is a OverTheWire game server. More information on http://www.overthewire.org/wargames

bandit18@bandit.labs.overthewire.org's password: 
IueksS7Ubh8G3DCwVzrTd8rAVOwq3M5x

するとこのように、readmeに書かれていたパスワードを読み出すことができました。


Level 19 → Level 20

To gain access to the next level, you should use the setuid binary in the homedirectory. Execute it without arguments to find out how to use it. The password for this level can be found in the usual place (/etc/bandit_pass), after you have used the setuid binary.

次のレベルにアクセスするためには、ホームディレクトリにあるsetuidバイナリを使う必要があります。 引数なしで実行してみて、使い方を調べてください。 パスワードは/etc/bandit_passにあります、とのことです。

そもそもsetuidとは何でしょうか。 wikipediaによると、

setuid と setgid は、UNIXにおけるアクセス権を表すフラグの名称であり、ユーザーが実行ファイルを実行する際にその実行ファイルの所有者やグループの権限で実行できるようにする。それぞれ、set user ID と set group ID の略。一般ユーザーが高い特権レベルでしか実行できないタスクを一時的に実行できるようにする仕組みである。

setuid - Wikipedia

要は、一時的に権限を高めるための仕組みだそうです。

本来は見ることができない/etc/bandit_passの下にあるパスワードファイルを、setuidで得た権限のもとに閲覧しようというわけです。 さっそくやっていきます。

$ ls
bandit20-do
$ file bandit20-do 
bandit20-do: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=8e941f24b8c5cd0af67b22b724c57e1ab92a92a1, not stripped
$ ./bandit20-do 
Run a command as another user.
  Example: ./bandit20-do id

他のユーザーとしてコマンドを実行するには、./bandit20-do <command>とやれば良いようです。

このsetuid下で、/etc/bandit_pass下のパスワードファイルを見ます。

$ ./bandit20-do cat /etc/bandit_pass/bandit20
GbKksEFF4yrVs6il55v6gwY5aVje5f0j

パスワードを読み出すことができました。


Discussion

OverTheWire: Banditを、Level0からLevel10まで解いてみました。

※Level20まで追記しました。

Bandit自体は、2019年4月現在Level34まであります。

sshで遠隔ログインしたことがなかったので初めは緊張しましたが、慣れてくると純粋に問題を楽しむことができました。 きれいにパスワードが特定できたときには、中々の興奮があります。

今回やったのは、コマンドの使い方を主軸に置いた入門用のCTFです。 これがもっと難しいものになれば、解いたときの快感は殊更でしょう。

ぜひこれからも遊んでいきたいものです。


See also

www.bioerrorlog.work

www.bioerrorlog.work


  1. 参考にした記事もいくつか書きました
    逆アセンブル解析 - gdb | はじめてのリバースエンジニアリング#2 - 生物系がゼロから始めるIT技術

  2. /dev/null discards unwanted output - Linux Shell Scripting Tutorial - A Beginner's handbook

  3. ちなみに>を使えば標準出力が、&>を使えば標準出力とエラー出力の両方がリダイレクトされます。

  4. Base64 - Wikipedia

  5. ROT13 - Wikipedia