Performing a Log Poisoning Attack

Angel Mercado
Learning CyberSecurity
5 min readOct 22, 2023

Today we will be looking at the natas25 challenge from overthewire. We will be exploring how malicious attackers might gain remote code execution by exploiting this type of vulnerability.

Navigating to the Natas25 homepage we are presented with a simple page with a message. The page does not seem to offer much functionality, only allowing us to change the language from English to German.

Lets take a look at the source code to see if we can find anything interesting.

Natas25 source code:

<?php  
// cheers and <3 to malvina
// - morla

function setLanguage(){
/* language setup */
if(array_key_exists("lang",$_REQUEST))
if(safeinclude("language/" . $_REQUEST["lang"] ))
return 1;
safeinclude("language/en");
}

function safeinclude($filename){
// check for directory traversal
if(strstr($filename,"../")){
logRequest("Directory traversal attempt! fixing request.");
$filename=str_replace("../","",$filename);
}
// dont let ppl steal our passwords
if(strstr($filename,"natas_webpass")){
logRequest("Illegal file access detected! Aborting!");
exit(-1);
}
// add more checks...

if (file_exists($filename)) {
include($filename);
return 1;
}
return 0;
}

function listFiles($path){
$listoffiles=array();
if ($handle = opendir($path))
while (false !== ($file = readdir($handle)))
if ($file != "." && $file != "..")
$listoffiles[]=$file;

closedir($handle);
return $listoffiles;
}

function logRequest($message){
$log="[". date("d.m.Y H::i:s",time()) ."]";
$log=$log . " " . $_SERVER['HTTP_USER_AGENT'];
$log=$log . " \"" . $message ."\"\n";
$fd=fopen("/var/www/natas/natas25/logs/natas25_" . session_id() .".log","a");
fwrite($fd,$log);
fclose($fd);
}
?>

Looking at the source code we immediately see a potential vulnerability. The setLanguage() function which is responsible for setting the language of the message checks to see if the if the language file exists in the language/ directory. If we can inject a different filename into the lang parameter we may be able to include local files on the server.

The use of include() in PHP without validation of user input can lead to a Local File Inclusion (LFI) vulnerability. A LFI vulnerability occurs when an attacker is able to access files on the server. Attackers typically exploit this vulnerability to access sensitive files such /etc/passwd or /etc/shadow.

How could this be used in the context of this challenge?

The overthewire challenges requires the attacker to gain access to the next users password, in this case the natas26 password. If we check the homepage of the natas challenges we see that natas passwords are stored in the following directory:
/etc/natas_webpass
We could try to use the LFI vulnerability to access this password, but there are two problems with this method.

Problem 1

First and foremost we are not in the root directory, from the source code we can assume we are in the /var/www/natas/natas25 directory. This means we would need to go back a few directories before accessing any files that would be of use to us. In the context of our LFI we would need to inject the following http://natasurl/lang?=../../../../etc/natas_webpass/natas26 . The problem with this is that the safeinclude() function checks for ../ and replaces it with nothing. As an example, if we were to use the payload shown above, then after being run through the safeinclude funtion, the $filename variable would simply be /var/www/natas/natas25/language/etc/natas_webpass/natas26, which does not exist , resulting in an error.

How can this problem be addressed?

Because we have access to the source code we can simply copy and paste the code in an IDE and check to see how the filter works. In my case I used the following online IDE https://onlinephp.io/

After experimenting with the code a bit we discover that if we use ….// instead of ../ we can succesfully traverse directories.

Why does the code behave this way?

While the intended use of this code is to prevent any directory traversal by removing ../ found in the $filename string, it is only performed once. This means that the string ….//….//….//….//….//etc/passwd becomes ../../../../../etc/passwd after the operation is performed.

Problem 2

The second problem we have is that the $filename variable is run through yet another check. In this check the if statement searches for the following string “natas_webpass”. If this string is found in the variable then the exit() function is used to terminate execution. This means we will be unable to include this string and will therefore be unable to read the password from the /etc/natas_webpass/natas26 file.

Solution

Our solution to these two problems lies in the logrequest function. This function is executed when the script detects the illegal characters in the first problem. If these characters exist then a log file is generated in the following file: /var/www/natas/natas25/logs/natas25_$SESSSID.log where $SESSID= our PHP session id. Most importantly, this function also logs the HTTP user-agent of the request. Because we can use the LFI vulnerability to access this log file, and we can inject code into this logfile via the user-agent, we can perform an attack called Log Poisoning.

What is a Log Poisoning attack?
A Log Poisoning attack allows attackers to inject code into a log file. This log file is then called via LFI and is subsequently executed by the server. In the case of this challenge we can inject PHP code via the user-agent which is stored in the log file. We can then call this log file via LFI and execute said PHP code.

Getting Remote Code Execution on the server

To get RCE we need to capture the request with burpsuite, alter the user agent and call the log file via the LFI.

User-Agent value:

Medium doesn’t let you post this php code so it’s an image :)

Lang parameter value: ….//….//….//….//….//var/www/natas/natas25/logs/natas25_h058h9b4u5pdcs5g1c2vl1c029.log&cmd=id

Reading the natas password

User-Agent value:

Medium doesn’t let you post this php code so it’s an image :)

Lang parameter value: ….//….//….//….//….//var/www/natas/natas25/logs/natas25_h058h9b4u5pdcs5g1c2vl1c029.log

Finally we get the password for the Natas26 user! natas26:8A506rfIAXbKKk68yJeuTuRq4UfcK70k

--

--