Hacking Insomnia (HTB Challenge)
Initial thoughts
We are presented with a website that has a few pages, index
, sign up
, and login
. The source code of the application is written in PHP, and uses Firebase, CodeIgniter, and SQLite3.
Upon signing up with admin:admin
credentials, there is a basic page with no other actions to perform.
We should search the codebase for any references to flag
.
public function index()
{
$token = (string) $_COOKIE["token"] ?? null;
$flag = file_get_contents(APPPATH . "/../flag.txt");
if (isset($token)) {
$key = (string) getenv("JWT_SECRET");
$jwt_decode = JWT::decode($token, new Key($key, "HS256"));
$username = $jwt_decode->username;
if ($username == "administrator") {
return view("ProfilePage", [
"username" => $username,
"content" => $flag,
]);
} else {
$content = "Haven't seen you for a while";
return view("ProfilePage", [
"username" => $username,
"content" => $content,
]);
}
}
}
HMM...
How can we access the administrator account? Let's look at the login code.
Understanding The Authentication Flow
The login request is a json object with a username
and password
field.
{
"username": "admin",
"password": "admin"
}
The login
Function
public function login()
{
$db = db_connect();
$json_data = request()->getJSON(true);
if (!count($json_data) == 2) {
return $this->respond("Please provide username and password", 404);
}
$query = $db->table("users")->getWhere($json_data, 1, 0);
$result = $query->getRowArray();
if (!$result) {
return $this->respond("User not found", 404);
} else {
// ... omited for brevity
$payload = [
"iat" => $iat,
"exp" => $exp,
"username" => $result["username"],
];
$token = JWT::encode($payload, $key, "HS256");
$response = [
"message" => "Login Succesful",
"token" => $token,
];
return $this->respond($response, 200);
}
}
Vulnerability detected
There isn't a strong check for username
and password
, rather the server only makes sure there are two keys in the data sent by the server.
Exploiting The Vulnerability
We can try to send an different second key in our json login object, so that the requirement for two keys is met. We can see in the source code that the User
database has two columns: username
and password
. By modifying the request to contain two username
keys with the value of the account we want to log into, we may be able to trick the server into viewing our login attempt as valid, without using a password.
By using Burpsuite to modify the login request, we will see that this method returns a response indicating a valid login.
JSON Code
{
"username": "administrator",
"username": "administrator"
}
Getting The Flag
In Burpsuite, we can go to the login page, turn on intercepts, and try to log in with administrator:password
. Once we intercept the request, we will replace the initial json with our "malicious" json. Finally, we can turn off intercepts and browse the site normally.
🎉 We got our flag!