历时好久的 php
中间拖了丢了不想学了
终于是把整个板块拉完了
丢几道觉得还不错的题目又水一篇
web 109(无参数函数执行”漏洞利用链)
攻击者可以利用 PHP 内置函数或已声明的类实现以下目的:
任意代码执行:$v1 = "assert"; $v2 = "system"(导致命令执行)
敏感信息泄露:$v1 = "Exception"; $v2 = "get_defined_constants"(抛出异常时可能回显常量信息。)
文件操作:$v1 = "SplFileObject"; $v2 = "fopen"(读取或写入服务器文件)
触发魔术方法链:$v1 = "SimpleXMLElement"; $v2 = "file_get_contents"(通过 echo 触发 __toString() 进行 XXE 攻击或数据外带。)

eval("echo new $v1($v2());");

简易理解:v1=PDO,v2=phpinfo
执行的代码结果就是
echo new PDO( phpinfo() );

通过遍历路径找到flag文件,cat拿下flag


web 115
trim() 函数的作用是去除字符串首尾的空白字符
filter()函数用于验证和过滤外部输入数据
is_numeric() 函数用于检查变量是否为数字或数字字符串
url编码手册
这里使用%0C换页符


web 123(非法参数解析)
只要变量名中出现非法参数名(”空格“、”.“、”+“、“[")
就是这类型题
但php中有个特性就是如果传入【,它被转化为_之后,后面的字符就会被保留下来不会被替换




web 125
同上题非法参数解析
but此题ban掉了flag,所以没办法echo直接调用flag
我尝试使用system读取也失败了(说是底层逻辑就不给system写入)
直接使用include/highlight_file(only读取作用)读取成功

web 130

这题的正则有一个非贪婪模式(正则非贪婪模式是指在匹配时尽可能少地匹配字符,通常通过在量词后添加问号(?)来实现。)
也就是说
if(preg_match('/.+?ctfshow/is', $f)){
die('bye!');
}
"ctfshow"之前加任何东西都会被拦
而
if(stripos($f, 'ctfshow') === FALSE){
die('bye!!');
}
传入的f中必须带有“ctfshow”,否则触发bye
所以,直接尝试POST传入f=ctfshow/../../../var/www/html/flag.php
成功拿到flag
。。。
或者直接传入f=ctfshow
也能拿到
**原因:第一个if语句中无法匹配,第二个if语句中返回0,两个die都不会执行,会执行echo $flag;
web131(正则表达式栈溢出)

简单说,输入大量垃圾函数让这个函数承载量爆炸,使其返回 false,就会执行echo $flag;
<?php
// 设置生成字符串的长度
$length = 1000000;
// 生成包含一百万个数字 "1" 的字符串
$onesString = str_repeat('1', $length);
// 输出结果
echo $onesString;
?>

很无聊的题目。。。。被气笑了,但也是给了一个新的解题思路
web 139(反弹shell 时间盲注)
开题

有一个解题方法是用时间盲注去解,但是解不出来
所以我们换反弹shell
思路在于用’'或者\来绕过命令的过滤,然后利用base64外带数据来找flag
开个监听

首先 . 被ban了 找个在线ip转换工具(上有政策下有对策)

发现绕过成功 那就ls一下看看有什么东西(因为是开的nc 这里有个很重要的点,每一次都要重新再开监听)
!

得到经过base64编码的字符串

看到f149_15_h3r3
cat一下

解码得到flag

web 137(无参数调用类静态方法)
call_user_func 把第一个参数作为回调函数调用
危险点在于用户可以完全控制 $callback 参数:
- 可以调用任意已定义的函数
- 可以调用任意类的静态方法(绕过对象实例化)
- 不需要
new创建对象,也就不触发__wakeup()等魔术方法
<?php
function now($a,$b)
{
echo $a;
echo $b;
echo $a+$b;
}
call_user_func('now', " 111 "," 222 ");
call_user_func('now', " 333 "," 444 ");
//显示 111 222 333
// 333 444 777
function hello() {
echo "Hello World";
}
call_user_func('hello'); // 输出: Hello World

payload为ctfshow=ctfshow::getFlag
类的静态方式:静态方法是属于类本身而不是属于某个对象实例的方法
格式:call_user_func('Flag::getFlag');
类名::方法名()


web 138(利用数组调用静态方法)
同类型题,只不过这题用的是数组调用
格式:call_user_func([类名, 方法名]);
['类名', '方法名'] 等价于 ‘类名::方法名’
即ctfshow[]=ctfshow&ctfshow[]=getFlag

payload为ctfshow[]=ctfshow&ctfshow[]=getFlag


147 (PHP 可变函数调用导致的动态代码执行)

全局命名空间
没有定义任何命名空间时的默认空间,用 \ 表示。
- 如果某个函数在自定义命名空间被重写或禁用
- 可以用
\函数名直接调用全局命名空间中的原始系统函数 - 从而绕过限制
核心:可变函数调用 + create_function() 代码注入 + 反斜杠绕过正则。
if(!preg_match('/^[a-z0-9_]*$/isD',$ctfshow)) {
i:不区分大小写s:点号.匹配包括换行符在内的所有字符D:美元符号$仅匹配字符串末尾,不匹配末尾的换行符
意思:如果 ctf 不是纯字母数字下划线,就执行函数调用
payload
GET: ?show=;};system('grep flag flag.php');/*
POST: ctf=%5ccreate_function
%5c解码后是
其中 \ 不在 [a-z0-9_] 范围内,所以正则匹配失败,preg_match() 返回 0,取反后进入 if。
$ctfshow('',$_GET['show']);
这句代码的意思是:把$ctfshow里的内容当作函数名,然后调用这个函数,并传入两个参数
比如
$ctfshow = 'system';
$ctfshow('', $_GET['show']);
等价于
system('', $_GET['show']);
在这里:$ctfshow的值是post传入的‘ctf’,所以 POST 里的 ctf 控制了要调用哪个函数。
而在 PHP 里,函数名前面的反斜杠表示全局命名空间:\create_function等价于调用全局函数:create_function
所以这一步既绕过了正则,又没有改变函数含义.
所以post传入的%5ccreate_function最终变为\create_function('', $_GET['show']);
为什么要用这个函数呢
create_function() 它会根据字符串动态创建函数,本质上类似于拼接代码再 eval
且 因为create_function函数格式为:
create_function(函数参数列表, 函数体代码)
所以create_function('', $_GET['show']);
意思就是创建一个“没有参数”的匿名函数,函数体代码由 show 参数控制
因此如果:
GET: show=echo 123;
大致相当于创建:
function 临时函数名() {
echo 123;
}
但如果传:
GET: show=;};system('grep flag flag.php');/*
就可以把函数体闭合掉,逃出去执行语句:
system('grep flag flag.php');
详情看未命名php_ctf_create_function_analysis
看不懂 我已急哭
!!!!茅塞顿开
为什么这里不能用其他函数,比如直接system读取,要绕这么大个圈子呢
因为:
如果payload为
POST: ctf=\system
GET: show=cat flag.php
那解析后就变成了
system('', $_GET['show']);
对于system来说,system() 的第一个参数才是命令,而这里第一个参数被固定成了空字符串 '',所以不能直接执行我们想要的命令。

web149(条件竞争)
写入后清理,通常出现在高难度的 CTF 无参数 RCE(远程代码执行)
unlink() 是 PHP 的内置函数,专门用来删除服务器上的文件,功能等同于 Linux 的 rm 命令。
![[Pasted image 20260510203614.png]]
$files = scandir('./');
foreach($files as $file) {
if(is_file($file)){
if ($file !== "index.php") { unlink($file);
}
}
}
- 扫描当前目录。
- 只保留
index.php自身。 - 删除其他所有文件,确保目录干净,不给攻击者留下任何可利用的现成脚本
file_put_contents($_GET['ctf'], $_POST['show']);
$files = scandir('./');
foreach($files as $file) {
if(is_file($file)){
if ($file !== "index.php") { unlink($file);
}
}
}
- 写入文件后,再次执行相同的清理逻辑。
php文件进行写马操作
get重写index.php
post写一个一句话木马
哥斯拉连接



Comments | NOTHING