Arang.dev
検索
TSG CTF 2020🏁 CTF🌐 翻訳済み

2020 TSG CTF - Slick Logger Writeup

Time-based Blind Regex Injectionでフラグを奪取

#tsg-ctf#regex-injection#blind#golang

この記事はAIによって韓国語から機械翻訳されています。原文と表現が異なる場合があります。

原文(韓国語)を読む

slick-logger``web``5 solvers

func searchHandler(w http.ResponseWriter, r *http.Request) {
 channelID, ok := r.URL.Query()["channel"]
 if !ok || !validateParameter(channelID[0]) {
 http.Error(w, "channel parameter is required", 400)
 return
 }
 
 queries, ok := r.URL.Query()["q"]
 if !ok || !validateParameter(queries[0]) {
 http.Error(w, "q parameter is required", 400)
 return
 }
 
 users := []User{}
 readJSON("/var/lib/data/users.json", &users)
 
 dir, _ := strconv.Unquote(channelID[0])
 query, _ := strconv.Unquote(queries[0])
 
 if strings.HasPrefix(dir, "G") {
 http.Error(w, "You cannot view private channels, sorry!", 403)
 return
 }
 
 re, _ := regexp.Compile("(?i)" + query)
 
 messages := []Message{}
 filepath.Walk("/var/lib/data/", func(path string, _ os.FileInfo, _ error) error {
 if strings.HasPrefix(path, "/var/lib/data/"+dir) && strings.HasSuffix(path, ".json") {
 newMessages := []Message{}
 readJSON(path, &newMessages)
 for _, message := range newMessages {
 if re.MatchString(message.Text) {
 // Fill in user info
 for _, user := range users {
 if user.ID == message.UserID {
 messages = append(messages, Message{
 Text: re.ReplaceAllString(message.Text, "<em>$0</em>"),
 UserID: message.UserID,
 UserName: user.Name,
 Icon: user.Profile.Image,
 Timestamp: message.Timestamp,
 })
 break
 }
 }
 }
 }
 }
 return nil
 })
 
 result, _ := json.Marshal(messages)
 
 w.WriteHeader(http.StatusOK)
 header := w.Header()
 header.Set("Content-type", "application/json")
 fmt.Fprint(w, string(result))
}

検索機能では、channelとqという入力を受け取ります。

しかし、これらは"value"のような特定のパラメータ形式で使用され、アンクォート(引用符解除)されます。

そのため、"""を入力すると空文字扱いとなり、MySQLのlike '%'のように(全件)検索できるようになります。

(@Payload at GONに感謝)

これにより、

filepath.Walk("/var/lib/data/", func(path string, _ os.FileInfo, _ error) error {
 if strings.HasPrefix(path, "/var/lib/data/"+dir) && strings.HasSuffix(path, ".json") {
 newMessages := []Message{}
 readJSON(path, &newMessages)

秘密チャンネルの管理者メッセージを取得できるようになります。

users := []User{}
readJSON("/var/lib/data/users.json", &users)
 
...
 
for _, user := range users {
 if user.ID == message.UserID {

しかし、この条件があるため、users.jsonにはUSLACKBOTというuseridが存在しません。

for _, message := range newMessages {
>>> if re.MatchString(message.Text) {
 // Fill in user info
 for _, user := range users {

ところが、検索ワードであるqueryはregexp.Compileの引数に渡されており、これはuseridのマッチング処理の前に使用されます。

つまり、Blind Regex Injectionが可能ということです。 (https://portswigger.net/daily-swig/blind-regex-injection-theoretical-exploit-offers-new-way-to-force-web-apps-to-spill-secrets)

検索ワードが長くなると、Blind Regex Injectionの精度が低下します。

検索ワードを適度に分割してフラグを取得しましょう!

また、精度が少し低いため、同じペイロードを数回送信し、最も遅延が発生したワードの統計を取るようにします! XD

[*] 5 : 0.06300497055053711
[*] } : 0.062014102935791016
[*] N : 0.05901360511779785
---------------------
[*] } : 0.06202411651611328
[*] 0 : 0.060013771057128906
[*] W : 0.058012962341308594
---------------------
[*] U : 0.09402132034301758
[*] B : 0.0660254955291748
[*] } : 0.06601500511169434
---------------------
[*] } : 0.06301426887512207
[*] Z : 0.06101393699645996
[*] Y : 0.060013532638549805
---------------------
[*] } : 0.06601476669311523
[*] H : 0.06502485275268555
[*] 6 : 0.05902361869812012
---------------------
[Finished in 13.1s]
 
## this could be `}` is the currect word

エクスプロイトコードを確認してください。

https://github.com/JaewookYou/ctf-writeups/blob/master/2020TSGCTF/slick-logger/ex.py

コメント

コメントを読み込み中...
2020 TSG CTF - Slick Logger Writeup | TSG CTF 2020 | Arang