CTFshow系列——PHP特性Web113-115(123)

今天继续给大家带来php特性的CTF题目讲解,说实话每次回头看写的文章,总能学到新东西;

文章目录


Web113

直接看源代码:

php 复制代码
<?php

highlight_file(__FILE__);
error_reporting(0);
function filter($file){
    if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
        die('hacker!');
    }else{
        return $file;
    }
}
$file=$_GET['file'];
if(! is_file($file)){
    highlight_file(filter($file));
}else{
    echo "hacker!";
}

通过代码,我们可以发现这个与Web112 差不多:

多了对filter关键字的过滤,其实就是禁止了我们的**php://filter/**的使用;

那接下来我们有什么协议能用呢?

代码分析

  • 程序会把 $_GET['file'] 赋给 $file
  • 先用 is_file($file) 判断:如果不是(! is_file(file))则走 **highlight_file(filter(file))** ;反之输出 hacker!
    • 也就是说:只有 目标"不是普通存在的文件" 时,代码才去 highlight_file 该值(故意让你用流/包装器来读取)。
  • filter() 会拒绝含有这些关键字(不区分大小写):filter, .../, http, https, data, rot13, base64, string。
    • 这会直接拦截 php://filter/convert.base64-encode/ 这种常见绕过,因为 filter 与 base64 被列入黑名单。
  • 漏洞类型:LFILocal File Include / read)通过流包装器绕过/利用。目标是让 highlight_file(...) 输出我们想看的目标(例如 flag 源码)。

没办法,只能使用上一关的compress.zlib://协议了:

bash 复制代码
# payload
?file=compress.zlib://flag.php

--

方法二:利用函数所能处理的长度限制进行目录溢出(官方WP)

bash 复制代码
# payload
?file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

原理:/proc/self/root代表根目录,进行目录溢出,超过is_file能处理的最大长度就不认为是个文件了。

--

Web114

页面显示如下:

php 复制代码
<?php

error_reporting(0);
highlight_file(__FILE__);
function filter($file){
    if(preg_match('/compress|root|zip|convert|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
        die('hacker!');
    }else{
        return $file;
    }
}
$file=$_GET['file'];
echo "师傅们居然tql都是非预期 哼!";
if(! is_file($file)){
    highlight_file(filter($file));
}else{
    echo "hacker!";
} 师傅们居然tql都是非预期 哼!

没想到我们的compress协议最终还是难逃一死,难道真的只能用目录溢出这种方法吗?

答案 :但是我们发现,filter关键词竟然被放出来了,那就由不得你了。


回归最朴实无华的payload:编码也不要了

bash 复制代码
# payload
?file=php://filter/resource=flag.php

(之前的目录溢出在这关失效了。。。)


Web115(新题型)

php 复制代码
<?php

include('flag.php');
highlight_file(__FILE__);
error_reporting(0);
function filter($num){
    $num=str_replace("0x","1",$num);
    $num=str_replace("0","1",$num);
    $num=str_replace(".","1",$num);
    $num=str_replace("e","1",$num);
    $num=str_replace("+","1",$num);
    return $num;
}
$num=$_GET['num'];
if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){
    if($num=='36'){
        echo $flag;
    }else{
        echo "hacker!!";
    }
}else{
    echo "hacker!!!";
} hacker!!!

代码分析

  • filter($num) 函数:
    • 它将字符串中的 "0x", "0", ".", "e", "+" 全部替换成了 "1"。
    • 也就是禁止我们使用八 / 十六 进制小数点科学计数法 以及正负数
  • 第一个 if 条件:
  • if(is_numeric(num) and num!'36' and trim(num)!' 36' and filter(num)=='36')
    • is_numeric($num): 检查 $num 是否是数字或数字字符串。这个条件是绕过的关键。
    • $num!=='36' 和 trim($num)!=='36': 这两个是强类型比较。!== 运算符不仅比较值,还比较变量类型。这意味着 $num 的值和类型都不能是字符串 '36'。
    • filter($num)=='36': 这是一个弱类型比较。== 运算符只比较值。经过 filter 函数处理后的 $num 字符串,其值必须等于字符串 '36'。

解题思路

  1. is_numeric($num): 传入的 $num 必须是一个数字或数字字符串。
  2. $num!=='36' 和 trim($num)!=='36': $num 不能是字符串 '36'。
  3. filter($num)=='36': filter 函数会替换 "0x", "0", ".", "e", "+" 为 "1"。要使处理后的结果为 '36',我们可以在输入中包含这些字符。
  4. $num=='36': 传入的 $num 必须在弱类型比较下等于 36。

题目与Web90 差不多(可以看本篇文章),但是感觉把我们的路都封死了,

官方WP

在php中"36"是等于\x0c36的,同时trim也不会过滤掉\x0c也就是%0c

  • %0c==\f
  • 所以payload: /?num=%0c36
bash 复制代码
# payload
?num=%0c36

我真的没招了。


Web123

嗯?怎么直接到Web123 了,我的Web116 呢?

我也不知道啊,题目就是这样的:


所以还是先看代码:

php 复制代码
<?php

error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
$a=$_SERVER['argv'];
$c=$_POST['fun'];
if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){
    if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?/", $c)&&$c<=18){
         eval("$c".";");  
         if($fl0g==="flag_give_me"){
             echo $flag;
         }
    }
}
?>

看到$_SERVER,我一下又感觉回到了熟悉的场景:Web98(新题型)

代码分析

  • POST 参数
    • CTF_SHOWCTF_SHOW.COM 必须存在。
    • fun 参数的值就是我们希望执行的命令。
  • fun 参数 的限制:
    • 不能包含黑名单中的特殊字符。
    • 其值在弱类型比较下必须小于或等于 18。
  • eval() 代码:
    • 执行后必须创建一个变量 $fl0g,并将其值严格设置为 "flag_give_me"。
  • if ($fl0g === "flag_give_me"):
    • 这部分是获取 flag 的关键。它要求一个名为 $fl0g 的变量必须严格等于字符串 "flag_give_me"。
    • 这个 $fl0g 变量是由我们通过 eval() 函数执行的代码来创建和赋值的。

payload

所以我尝试构造了一个payload:
CTF_SHOW=&CTF_SHOW.COM=&fun=extract($_POST,0)&fl0g=flag_give_me

但没有反应。。

随后看了WP,发现忽略了一点:

  • 根据代码: c = c= c=_POST['fun'];和eval("$c".";");
  • 我的代码带入后就变成了 eval("extract($_POST,0)&fl0g=flag_give_me".";");

并且fl0g参数是要不存在才满足条件:

  • 具体代码:if(!isset($_GET['fl0g'])
bash 复制代码
# payload
POST: CTF_SHOW=&CTF[SHOW.COM=&fun=echo $flag

也是得到flag。。

总结

没什么好说的,温故而知新;

相关推荐
Devil枫3 小时前
鸿蒙系统敏感文件安全存储:从系统机制到 ArkTS 实现
安全·华为·harmonyos
安卓开发者3 小时前
鸿蒙Next密码自动填充服务:安全与便捷的完美融合
安全·华为·harmonyos
FreeBuf_4 小时前
Zloader木马再次升级:通过DNS隧道和WebSocket C2实现更隐蔽的攻击
websocket·网络协议·php
用户3521802454754 小时前
🌭 代码审计-xiuno BBS
安全·php
你的人类朋友5 小时前
🍃说说Base64
前端·后端·安全
BingoGo5 小时前
PHP 8.2 vs PHP 8.3 对比:新功能、性能提升和迁移技巧
后端·php
余防6 小时前
CSRF跨站请求伪造
前端·安全·web安全·csrf
Yyyy4826 小时前
LVS三种模式及原理
服务器·php·lvs
Acc1oFl4g6 小时前
【铸网-2025】线下赛 web 详细题解
web安全·ctf·php反序列化