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。。

总结

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

相关推荐
BingoGo20 小时前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack20 小时前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
cipher1 天前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
BingoGo2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack4 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理4 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
一次旅行4 天前
网络安全总结
安全·web安全