个人学习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弱类型比较

  1. strcmp()
    strcmp(str1, str2)
    作用:
    如果 str1 小于 str2 返回 < 0
    如果 str1 大于 str2 返回 > 0
    如果两者相等,返回 0

    在 php5.0 以前,strcmp 返回的是 str2 第一位字母转成 ascii 后减去 str1 第一位字母
    当 strcmp 比较出错后,会返回 null,null 则为 0

    比如在要求 str1 != str2strcmp(str1, str2)==0
    可以让 strcmp 比较出错 实现 NULL=0 来满足条件
    传入 数组 可以让 strcmp 比较出错,比如 ?str[]

  2. is_numeric()
    is_numeric()
    作用:检测变量是否是数字或数字字符串
    对字符串的检查较严格,字符串中包含非数字字符就会返回 false
    PHP版本小于 \(8.0.0\) 时,如果传入的是字符串,会先将字符串转换成数值

  3. 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}
  1. 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相同的文件
    方法
    使用 FastCollmd5 进行一个简单碰撞
    首先创建一个文件 1.txt,在里边输入任意值,其次使用命令
    fastcoll -p 1.txt -o 2.txt 3.txt
    分别生成 2.txt3.txt,这时候打开会发现这些是二进制字符串(?)
    接着对这两个文件内容分别进行 md5 编码 和 url 编码
    会发现 md5 后的编码是一样的

  2. sha1()
    sha1()
    类似md5,也是一种密码散列函数
    可以把输入内容变成160位(20字节)的散列值

  • 长度:总是42个字符

  • 字符:只包含0-9和a-f

    绕过方法:
    开头为0e的字符串,可以被松散比较当作科学计数法,返回值为0
    参数不能为数组,传入数组会返回NULL

  1. $$
    叫做可变变量,允许使用一个变量的值作为另一个变量的名称
    举个例子
<?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%0aca\tfla\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}
00b400e4823142e97cd095ac7ef91a9f

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}

具体攻击代码

  1. ffifdyop
  2. ?x[]=1&y[]=2
  3. 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开头的
    QNKCDZO 240610708
    输出nice yoxi!,成功

  • 输出flag
    NSSCTF{825386ec-28da-4007-ab9a-62a9346378bd)

具体攻击代码

  1. ?num=1e9
  2. &Str=NSSNSSCTFCTF
  3. md5 1=QNKCDZ0&md5 2=240610708(POST)
    39b4b368ca712ef280ed17b1527833b0

WEEK1 WEB Begin of PHP

  • 大致看了一下代码,是五个题目,都解出来就有flag

  • Level 1
    要GET key1 key2
    要求两个变量不等但md5值相等
    那就数组绕过
    ?key1[]=1&key2[]=2

  • Level 2
    要POST key3
    要变量的md5值等于sha1值
    也数组绕过就行
    key3[]=1

  • Level 3
    要GET key4
    strcmp会比较里面的两个元素
    右半部分为0 可以让变量为数组
    因为NULL=0
    &key4[]=1

  • Level 4
    要GET key5
    需要变量不是数字且大于2023
    这个不是数字判断比较严格
    可以用科学计数法绕过
    &key5=2024e0

  • Level 5
    要POSTflag5
    禁用了字母和数字
    要求flag5为非空字符串
    那就给个符号
    &flag5=!

  • 取得flag
    flag{7a06ca07-0b87-4aff-8068-ac0dd2b45d5e}
    56cc1daa7bd4b3887602044b80d09a02

文件包含

还没写

posted @ 2025-11-30 21:52  icent  阅读(0)  评论(0)    收藏  举报