DownUnderCTF 2023 Writeup
DownUnderCTF 2023に0nePaddingというチームで参加して124 / 2549位でした。
今回は主にOSINTに取り組み、5 / 6問解けました。
[OSINT:Begginer] Excellent Vista!
OSINTによくある、写真を撮影した場所を答える問題です。
JPG画像が与えられます。
JPGなのでEXIFを確認すると、緯度経度が載っているのでGoogle Mapでその場所の地名を探すだけです。
exiftool ~/Downloads/ExcellentVista.jpg
下記の文字列をGoogle Mapで検索するだけですが、S
とE
を忘れるとそれぞれ北緯、西経となり北太平洋に放置されるので注意です。
29°30'34.33"S,153°21'34.46E
DUCTF{Durrangan_Lookout}
[OSINT:Begginer] Bridget's Back!
同じく写真の撮影場所を答える問題です。
見える橋がゴールデンゲートブリッジということがわかったので周辺を探します。
ストリートビューで周辺を探索すると橋の見え方が同じビュースポットを発見しました。
この場所の名前がフラグになっていました。
DUCTF{H._Dana_Bowers_Rest_Area}
[OSINT:Easy] Comeacroppa
またまた写真の場所を特定する問題です。
画像の右上に4桁の数字(1800 or 1866)っぽいものが見えたのでAustralia 1800
とAustralia 1866
で検索してみました。
(このCTFはオーストラリアに関する問題の傾向があったので)
すると検索結果に似た画像が出ており、この建物がScotch Pie House
という名前であることがわかります。
Australia Scotch Pie House
で検索するとこの建物が存在する地名がわかります。
DUCTF{maldon}
ちなみにGoogle Lensにアップすることでも地名がわかります。
[OSINT:Medium] faraday
電話番号を基に用意されたAPIを使用して場所を特定する問題です。
オーストラリアのヴィクトリア内に当該電話番号を持った電話が存在するらしいので、
その町名を答える必要があります。
APIにはドキュメントが用意されていたのでドキュメントに沿ってAPIを使用します。
このAPIは緯度経度と検索範囲の半径を与えて、その円の中に該当の電話番号を持った電話が存在するかを返すAPIのようでした。
最初に試行した解法は、ヴィクトリアの町名と緯度経度の対応したリストを使用して総当りをする、でした。
下記のサイトからヴィクトリアの町のみを引っ張ってきてPythonスクリプトを書き、総当りしました。
ですが、ヒットする町が一意に絞れず、ヒットする町の全てをフラグとして提出してもIncorrectと言われ誤答をむやみに増やす結果になりました…。
なので方針を変更し、検索半径を徐々に絞っていき対象に到達するスクリプトを書きました。
与えた緯度経度周辺を探索し、ヒットした円の中心を新しい緯度経度に設定して半径を徐々に小さくしていきます。
import requests import json import math import time import urllib3 from urllib3.exceptions import InsecureRequestWarning urllib3.disable_warnings(InsecureRequestWarning) URL = "https://osint-faraday-9e36cbd6acad.2023.ductf.dev/verify" # Victoria lat = -37.036970870314754 long = 144.0646040878664 post_data = { "device": { "phoneNumber": "+61491578888" }, "area": { "areaType": "Circle", "center": { "latitude": 0, "longitude": 0 }, "radius": 200000 }, "maxAge": 120 } rad = 200000 while rad >= 2000: new_x_y = [(0,0),(rad/2,0),(0,rad/2),(rad/2,rad/2),(-rad/2,0),(0,-rad/2),(-rad/2,-rad/2)] for (x, y) in new_x_y: new_lat, new_long = (lat + x/111111, long + y/(111111 * math.cos(lat))) post_data["area"]["center"]["latitude"] = new_lat post_data["area"]["center"]["longitude"] = new_long post_data["area"]["radius"] = rad print(f"lat: {new_lat}, long: {new_long}, rad: {rad}") res = requests.post( URL, json.dumps(post_data), proxies={"http":"http://localhost:8080","https":"http://localhost:8080"}, verify=False ) if res.status_code == 200: res_data = res.json() if res_data["verificationResult"] == "TRUE": lat = new_lat long = new_long rad = int(rad / 1.75) time.sleep(10)
この際、緯度経度とメートル単位の計算があり、 1mを緯度経度換算する際に参考になったのが以下のサイトです。
緯度の1度と経度の1度は長さが違う。売上予測の基礎の基礎(2) | 売上予測 30年の実績
このサイトいわく精度を気にしないのであれば緯度経度は以下のように変換できるそうです。
- 緯度
1° = 111111m
- 経度
1° = 111111m * cos(緯度)
このスクリプトを実行すると最終的に以下の座標が得られます。
-36.46734230068619, 146.4276475126464
この座標をGoogle Mapで表示するとMilawa
という地名だと言うことがわかります。
この地名がフラグになっていました。
DUCTF{milawa}
ちなみにMilawa
は最初に使用した町名リストに載っていませんでした。
完全に時間の無駄…
[OSINT:Medium] monke bars
作問者がラップをリリースしたそうなのでその曲を探す問題です。
曲名が「monke bars」ということがわかっています。
しばらく調査をしていて、SoundCloudというサイトに該当する曲が存在することがわかりました。
monke bars results on SoundCloud - Listen to music
この曲のコメント欄を見るとフラグっぽい文言が投稿されていました。
これをフラグのフォーマットに沿って整形したものがフラグでした。
DUCTF{smackithackitdropthatpacketcrackthistrack}
[WEB:Easy] static file server
Python製のWebファイルサーバーだそうです。
アクセスすると、not_the_flag
ファイルが目に付きますのでアクセスするとflagの場所を教えてくれます。
この問題はソースコードが与えられるので読みます。
aiohttp
のweb.static()
という関数にヒントがありそうです。
from aiohttp import web async def index(request): return web.Response(body=''' <header><h1>static file server</h1></header> Here are some files: <ul> <li><img src="/files/ductf.png"></img></li> <li><a href="/files/not_the_flag.txt">not the flag</a></li> </ul> ''', content_type='text/html', status=200) app = web.Application() app.add_routes([ web.get('/', index), # this is handled by https://github.com/aio-libs/aiohttp/blob/v3.8.5/aiohttp/web_urldispatcher.py#L654-L690 web.static('/files', './files', follow_symlinks=True) ]) web.run_app(app)
コメントに記載されているURLにアクセスし、内部の処理を見ると、ディレクトリトラバーサルに脆弱っぽいです。
joinpath(foo).resolve()
のfoo
に/../../../../../../flag.txt
のような文字列を与えると/flag.txt
が返ってきます。
あとはペイロードを送信するだけでフラグが取得できます。