BlackHat MEA 23 CTF Qualifiers

Hi, this is Rehan. These are the web challenges I solved in the Web category in BLACKHAT MEA 23 CTF Qualifiers
Web writeups
Authy:WEB:50pts
This challenge is about registering and login with the same registered user. Having to do so will get you the flag. It looked simple but here is a catch
- The password at the time of user registration must be 6 or more characters, but the flag will only be displayed if you log in with a password of less than 6 characters.
We were provided with a zip of challenge. Below is the code snippet of the functionality :The interesting part I found was
func Registration(c echo.Context) error {
var user models.Users
body, _ := io.ReadAll(c.Request().Body)
err := json.Unmarshal(body, &user)
if err != nil {
return err
}
if len(user.Password) < 6 {
log.Error("Password too short")
resp := c.JSON(http.StatusConflict, helper.ErrorLog(http.StatusConflict, "Password too short", "EXT_REF"))
return resp
}
DB := db.DB()
var count int
sqlStatement := `Select count(username) from users where username=?`
err = DB.QueryRow(sqlStatement, user.Username).Scan(&count)
if err != nil {
log.Error(err.Error())
}
if count > 0 {
log.Error("username already used")
resp := c.JSON(http.StatusConflict, helper.ErrorLog(http.StatusConflict, "username already used", "EXT_REF"))
return resp
}
//hashing password (even it's a CTF, stick to the good habits)
hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), 5)
if err != nil {
resp := c.JSON(http.StatusInternalServerError, helper.ErrorLog(http.StatusInternalServerError, " Error While Hashing Password", "EXT_REF"))
return resp
}
user.Password = string(hash)
user.DateCreated = helper.DateTime()
user.Token = helper.JwtGenerator(user.Username, user.Firstname, user.Lastname, os.Getenv("SECRET"))
stmt, err := DB.Prepare("Insert into users (username,firstname,lastname,password,token,datecreated) VALUES (?,?,?,?,?,?)")
if err != nil {
resp := c.JSON(http.StatusInternalServerError, helper.ErrorLog(http.StatusInternalServerError, "Error when prepare statement : "+err.Error(), "EXT_REF"))
return resp
}
_, err = stmt.Exec(user.Username, user.Firstname, user.Lastname, user.Password, user.Token, user.DateCreated)
if err != nil {
log.Error(err)
resp := c.JSON(http.StatusInternalServerError, helper.ErrorLog(http.StatusInternalServerError, "Error when execute statement : "+err.Error(), "EXT_REF"))
return resp
}
resp := c.JSON(http.StatusOK, user)
log.Info()
return resp
}
type Flag struct {
Flag string `json:"flag"`
}
func LoginController(c echo.Context) error {
var user models.Users
payload, _ := io.ReadAll(c.Request().Body)
err := json.Unmarshal(payload, &user)
if err != nil {
log.Error(err)
return err
}
var result models.Users
DB := db.DB()
sqlStatement := "select * from users where username=?"
err = DB.QueryRow(sqlStatement, user.Username).Scan(&result.Username, &result.Firstname, &result.Lastname, &result.Password, &result.Token, &result.DateCreated)
if err != nil {
log.Error(err)
resp := c.JSON(http.StatusInternalServerError, helper.ErrorLog(http.StatusInternalServerError, "Invalid Username", "EXT_REF"))
return resp
}
err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(user.Password))
if err != nil {
log.Error("Invalid Password :", err)
resp := c.JSON(http.StatusInternalServerError, helper.ErrorLog(http.StatusInternalServerError, "Invalid Password", "EXT_REF"))
return resp
}
password := []rune(user.Password)
result.Token = helper.JwtGenerator(result.Username, result.Firstname, result.Lastname, os.Getenv("SECRET"))
if len(password) < 6 {
flag := os.Getenv("FLAG")
res := &Flag{
Flag: flag,
}
resp := c.JSON(http.StatusOK, res)
log.Info()
return resp
}
resp := c.JSON(http.StatusOK, result)
log.Info()
return resp
}
Important thing to note is during registration, the password string is directly compared, whereas during login, the code utilizes the rune function.
So lets find how rune works, rune is used to handle Unicode characters properly. Like for any ASCII character it will be one byte but for chinese one it will be two bytes. Now Go directly compares a password containing a Chinese character, it might consider it as 2 characters. However, using rune(), it treats it as a single character. lets use a 3 Chinese character password, it will meet both the registration and login flag criteria.


Here we got our flag
BHFlagY{43ef8a7241d47ce611eb5d42f1672b6b}
Warm Me Up 60pts
This challenge is related to the login functionality having to bypass the login page in order to retrieve the flag.
However its quite simple but a little enumeration to be done first

This is the login page where OTP needs to be filled in order to login.
SQli is not working in either fields, so our first task is to find the OTP first lets check out the HttpHistory tab in burp

We find the jwt token assigned in the very first request lets decode and insert the OTP in the field.
Trying SQLi now;

I was redirected to /flag page with new session cookie where i got the flag :)
BHFlagY{fe13fed56e14825120b961f3228edc12}
This is all from my side.
Thanks for reading.
Happy hacking!