个人学习25.11.30 hnusec ctf-web week3
week3
依旧按 笔记 和 习题WP 分为两大板块
学习笔记
PHP函数安全
常见绕过
is_numeric
作用:检测变量是否是数字或数字字符串
绕过方法:可以在数字前面或者后面加上%0a %0b %0c %0d %09
绕过原理:
is_numeric 对字符串的检查较严格,字符串中包含非数字字符就会返回 false
%0a %0b %0c %0d %09 是URL编码的空白字符
在使用 == 的比较时,因为是松散比较,会从字符串开头解析数字,直到遇到非数字字符为止
也就是说可以在数字后加上这些空白字符,使得 is_numeric 返回 false 并通过松散比较
%0a换行符%0b垂直制表符%0c换页符%0d回车符%09水平制表符
PHP精度
PHP的双精度格式为 IEEE 754
所谓 IEEE 754 是一个国际标准,规定了浮点数在计算机中的表示和运算方法
由于计算机使用二进制,数学使用十进制,导致在浮点数计算时会出现精度问题
比如
<?php
echo 0.1 + 0.2; // 输出:0.30000000000000004
echo 0.1 + 0.2 == 0.3; // 输出:false
?>
IEEE 754 一般分为半精度浮点数、单精度浮点数、双精度浮点数
基本上所有语言双精度格式都采用 IEEE 754
双精度浮点数为例,在这个长度下会使用 \(1\) 位符号,\(11\) 位指数,\(52\) 位尾数
- 符号:\(0\) 为正,\(1\) 为负
- 指数:数据如果以 \(2\) 为底的幂,则采用偏移表示法
单精度为 \(127\),双精度为 \(1023\)
存储的指数 = 真实的指数 + 偏移量 - 尾数:小数点后的数字
在 PHP 处理浮点数的运算中,采用的就是 IEEE 754 双精度格式
IEEE 754 标准在线转换网站:https://tooltt.com/floatconverter/
在PHP中,如果对一个数进行取整,所产生的最大相对误差为 \(1.11e-16\)
举些例子
echo 1989.9 . '<br>';
#返回:1989.9
echo 1989.99999999999999 . '<br>';
#返回:1990
echo 1.99999999999999 . '<br>'; # (小数为15)
#返回:2
echo 0.5799999999999999 . '<br>';
#返回:0.58
echo 1.9999999999999 . '<br>'; # (小数为13)
#返回:1.9999999999999
echo 1.0000000000001 . '<br>'; # (小数为13)
#返回:1.0000000000001
echo 1.00000000000001 . '<br>'; # (小数为15)
#返回:1
补充
strstr(v1, v2)
作用:
判断 v2 是否为 v1 的子串
如果是,则该函数返回v1字符串里 从v2第一次出现的位置开始到 v1 结尾的 字符串
否则,返回 NULL
比较和类型转换漏洞
比较运算
PHP 包含 松散比较 ( == 、 != 、 > 、 < 、 >= 、 <= )和 严格比较( === 、 !== )
松散比较 比较 值,不比较类型
严格比较 既比较 值 也比较 类型
原理
松散判断:先把二者转换为同一类型,再进行比较,即 先转换后比较
严格比较:先判断二者是否为一个类型,类型相同再比较值,即 先判断后比较
补充
字符串转成数字后会是 \(0\)
PHP 中类型转换有一定的缺陷
如果一个 字符串 要转成 数值 类型,首先对字符串进行一个判断
如果字符串包含 e 、. 、E 则会作为 float 来取值,否则则为 int
如果字符串起始部分为 数值 ,则采用 起始的数值 ,否则一律为 \(0\)
"123" == 123 // true,字符串转数字
"123abc" == 123 // true,取前面数字部分
"abc" == 0 // true,非数字字符串转为0
"0e123" == 0 // true,科学计数法结果为0
布尔值转换
ture == 1 // true
false == 0 // true
ture == "abc" // true,非空字符串转为true
false == "" // true,空字符串转为falese
false == "0" // true,字符串"0"转为false
数组转换
[] == 0 // true,空数组转为0
[] == "0" // false
[] == "" // true
[] == false // true
[1] == 1 // true,单元素数组取第一个元素
[1,2] == 1 // true,多元素数组转为1 (警告)
NULL转换
NULL == 0 // true
NULL == "" // true
NULL == false // true
NULL == "0" // false
字符串"0"
"0" == 0 //true
"0" == false //true
"0" == NULL //false
"0" == "" //false
PHP弱类型比较
-
strcmp()
strcmp(str1, str2)
作用:
如果 str1 小于 str2 返回 < 0
如果 str1 大于 str2 返回 > 0
如果两者相等,返回 0在 php5.0 以前,strcmp 返回的是 str2 第一位字母转成 ascii 后减去 str1 第一位字母
当 strcmp 比较出错后,会返回 null,null 则为 0比如在要求
str1 != str2且strcmp(str1, str2)==0时
可以让 strcmp 比较出错 实现 NULL=0 来满足条件
传入 数组 可以让 strcmp 比较出错,比如?str[] -
is_numeric()
is_numeric()
作用:检测变量是否是数字或数字字符串
对字符串的检查较严格,字符串中包含非数字字符就会返回 false
PHP版本小于 \(8.0.0\) 时,如果传入的是字符串,会先将字符串转换成数值 -
is_switch()
is_switch()
作用:和类型转换一样大同小异,case 会自动将字符转换成数值举个例子:
$a = "233a"; # 注意这里
$flag = "flag{Give you FLAG}";
switch ($a) {
case 1:
echo "No Flag";
break;
case 2:
echo "No Flag";
break;
case 233:
echo $flag;
break;
default:
$a = 233;
echo "Haha...";
}
输出结果为:
flag{Give you FLAG}
-
md5()
md5(字符串,var2)
作用:
计算 字符串 的 MD5 散列值
如果 var2 为真,将返回 16 字符长度的原始二进制格式MD5
是一种密码散列函数,可以产生128位(16字节)的散列值
就像数字指纹,可以将输入的文字、文件等,输出为32个16进制字符- 长度:总是32个字符
- 字符:只包含0-9和a-f
三种特性:
- 确定性:若输入确定,输出的散列值也是确定的
- 雪崩效应:及时输入只是微小改变,输出的md5也天差地别
- 不可逆性:可以由输出计算md5,md5无法反推输出
常见绕过:
- 简单比较绕过
输入md5开头为0e的字符串,可以被松散比较当作科学计数法,返回值为0 - 数组绕过
md5(array)的返回值为NULL
不常见但有:
输入不同,md5仍可能相同,称为MD5碰撞
需要时可以上传两个不同内容但md5相同的文件
方法
使用 FastColl 对 md5 进行一个简单碰撞
首先创建一个文件1.txt,在里边输入任意值,其次使用命令
fastcoll -p 1.txt -o 2.txt 3.txt
分别生成2.txt和3.txt,这时候打开会发现这些是二进制字符串(?)
接着对这两个文件内容分别进行 md5 编码 和 url 编码
会发现 md5 后的编码是一样的 -
sha1()
sha1()
类似md5,也是一种密码散列函数
可以把输入内容变成160位(20字节)的散列值
-
长度:总是42个字符
-
字符:只包含0-9和a-f
绕过方法:
开头为0e的字符串,可以被松散比较当作科学计数法,返回值为0
参数不能为数组,传入数组会返回NULL
$$
叫做可变变量,允许使用一个变量的值作为另一个变量的名称
举个例子
<?php
$name = "username";
$$name = "admin"; // 相当于 $username = "admin"
echo $username; // 输出结果为:admin
?>
其实就是简单的套娃
$$name→$"username"→$username
- 常见漏洞
$flag = "flag{Chain!}";
foreach ($_GET as $key => $value) {
$$key = $value;
}
if ($id === "admin") {
echo $flag;
}else{
echo "Out!";
}
可以传入:?id=admin
- 补充
foreach()
foreach($array as $value)与foreach($array as $key => $value)
前者只获得值,后者获得键和值
作用:遍历索引数组
举个例子
<?php
$user = array(
"name" => "Tom",
"age" => 20,
"role => "admin"
);
foreach($user as $key => $value){
echo "$key: $value<br>";
}
?>
结果为
name: Tom
age: 20
role: admin
正则表达式
还没学
文件包含
还没学
习题WP
RCE
CTFHub 命令注入-综合练习
进来发现没什么文字,就是php代码
读了一下,大概就是:
要GET一个ip地址,并且
"/(||&|;| |/|cat|flag|ctfhub)/"
被禁了
发现ls没被禁,干脆先列出来看看
所以给让ip等于本地回环地址,再附加ls
发现数组第九个元素叫flag_is_here
试着用cat打开它(用%09、%0a、ca\t和fla\g来绕过)
发现没反应,意识到他可能是个文件夹
于是再次用ls列开它
发现数组第11个元素flag_258865938799.php
那就用cd进入这个文件夹
加上cat来打开它
最终URL:
http://challenge-cb2d39bd274989d9.sandbox.ctfhub.com:10800/?ip=127.0.0.1%0als%0als%09f\lag_is_here%0acd%09f\lag_is_here%0aca\t%09fl\ag_258865938799.php
发现出现了数组第12个元素,但没显示flag
查看源代码,发现有flag
ctfhub{fca4372830c5e52c484ecca5}

PHP
[SWPUCTF 2022 新生赛]奇妙的MD5
Problem: [SWPUCTF 2022 新生赛]奇妙的MD5
解题大致思路
进来发现问“可曾听过ctf 中一个奇妙的字符串”
查阅资料,查到所谓的万能密码ffifdyop
成功弹窗至下一阶段”仔细想想在哪里找线索“
-
选择burpsute
抓包,发现一段这样的文字
<!--
$x= $GET['x'];
$y = $_GET['y'];
if($x != $y && md5($x) == md5($y)){
;
-->
-
所以想到数组绕过都得NULL
那就GET x和y
?x[]=1&y[]=2 -
新界面
还是数组绕过,不过是POST
wqh[]=1&dsy[]=2 -
取得flag
NSSCTF{296d2b16-06a9-4376-a9b0-34808136d2a6}
具体攻击代码
- ffifdyop
- ?x[]=1&y[]=2
- wqh[]=1&dsy[]=2
总结
- 对该题的考点总结
md5的0e绕过
md5的数组绕过
![b2763f6f7d9e700e547a44880d41d858]()
[SWPUCTF 2022 新生赛]funny_php
Problem: [SWPUCTF 2022 新生赛]funny_php
思路
解题大致思路
-
最后一个区块意思大概是过了三关就输出flag
-
第一关
大概意思是要让GET一个num
让它字符串长度小于等于3,值大于999999999
直白的输数字,字符串肯定大于3
所以考虑别的表示数字的方法
想到科学计数法
于是令num等于1e9
输出:D,成功 -
第二关
大概意思是GET一个str
让str里面的NSSCTF剪掉后仍然等于NSSCTF
那就令str等于NSSNSSCTFCTF
输出wow,成功 -
第三关
第三关是md5
要POST两个值
看了一下必须字符串
md5必值要相等
那就搞两个md5值是0e开头的
QNKCDZO240610708
输出niceyoxi!,成功 -
输出flag
NSSCTF{825386ec-28da-4007-ab9a-62a9346378bd)
具体攻击代码
- ?num=1e9
- &Str=NSSNSSCTFCTF
- md5 1=QNKCDZ0&md5 2=240610708(POST)
![39b4b368ca712ef280ed17b1527833b0]()
WEEK1 WEB Begin of PHP
-
大致看了一下代码,是五个题目,都解出来就有flag
-
Level 1
要GETkey1key2
要求两个变量不等但md5值相等
那就数组绕过
?key1[]=1&key2[]=2 -
Level 2
要POSTkey3
要变量的md5值等于sha1值
也数组绕过就行
key3[]=1 -
Level 3
要GETkey4
strcmp会比较里面的两个元素
右半部分为0 可以让变量为数组
因为NULL=0
&key4[]=1 -
Level 4
要GETkey5
需要变量不是数字且大于2023
这个不是数字判断比较严格
可以用科学计数法绕过
&key5=2024e0 -
Level 5
要POSTflag5
禁用了字母和数字
要求flag5为非空字符串
那就给个符号
&flag5=! -
取得flag
flag{7a06ca07-0b87-4aff-8068-ac0dd2b45d5e}
![56cc1daa7bd4b3887602044b80d09a02]()
文件包含
还没写




浙公网安备 33010602011771号