2020 TSG CTF - Slick Logger Writeup
Time-based Blind Regex Injection으로 플래그 탈취
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 search function, they get input from us,channelandq
but they use specific parameter form like"value", and unquote it.
so if we give""", it is going to blank, we could search likelike '%'in mysql db.
(thanks for @Payload at GON)
from now,
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 could get secret channel's admin message,
users := []User{}
readJSON("/var/lib/data/users.json", &users)
...
for _, user := range users {
if user.ID == message.UserID {but because of this condition, there is no useridUSLACKBOTatusers.json
for _, message := range newMessages {
>>> if re.MatchString(message.Text) {
// Fill in user info
for _, user := range users {but our searching word,query, is going to argument ofregexp.Compile, it is used beforeuseridmatching.
so we could give it blind regex injection. (https://portswigger.net/daily-swig/blind-regex-injection-theoretical-exploit-offers-new-way-to-force-web-apps-to-spill-secrets)
as searching words' length is growing, accuracy of blind regex injection decreases.
moderately slice our searching words to get flag!
and accuracy is little bit low, so we send same payload for several time, and get statistics of 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 wordcheck my exploit
https://github.com/JaewookYou/ctf-writeups/blob/master/2020TSGCTF/slick-logger/ex.py
댓글