Arang.dev
Search
TSG CTF 2020🏁 CTF🌐 Translated

2020 TSG CTF - Slick Logger Writeup

Flag exfiltration via Time-based Blind Regex Injection

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

This post was machine-translated from Korean by AI. Some expressions may differ from the original.

Read the original (Korean)

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))
}

In the search function, the application accepts user input via channel and q.

However, it uses a specific parameter format resembling "value", which is then unquoted.

Therefore, if we submit """, it results in a blank value, enabling us to perform a search similar to a like '%' query in a MySQL database.

(Thanks to @Payload at GON)

Moving on,

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)

We can retrieve the admin message from the secret channel,

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

However, due to this condition, the userid USLACKBOT does not exist in users.json.

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

Crucially, our search term, query, is passed as an argument to regexp.Compile. This occurs before the userid matching process.

This means we can perform a Blind Regex Injection attack. (https://portswigger.net/daily-swig/blind-regex-injection-theoretical-exploit-offers-new-way-to-force-web-apps-to-spill-secrets)

As the length of the search string increases, the accuracy of the Blind Regex Injection decreases.

We need to slice the search terms into moderate lengths to successfully retrieve the flag!

Since the accuracy is slightly low, we send the same payload multiple times and analyze the statistics to find the most delayed word! 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

Here is my exploit script:

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

Comments

Loading comments...
2020 TSG CTF - Slick Logger Writeup | TSG CTF 2020 | Arang