PHP代码审计分段讲解(8)
20 十六进制与数字比较
源代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php error_reporting (0); function noother_says_correct( $temp ) { $flag = 'flag{test}' ; $one = ord( '1' ); //ord — 返回字符的 ASCII 码值 $nine = ord( '9' ); //ord — 返回字符的 ASCII 码值 $number = '3735929054' ; // Check all the input characters! for ( $i = 0; $i < strlen ( $number ); $i ++) { // Disallow all the digits! $digit = ord( $temp { $i }); if ( ( $digit >= $one ) && ( $digit <= $nine ) ) { // Aha, digit not allowed! return "flase" ; } } if ( $number == $temp ) return $flag ; } $temp = $_GET [ 'password' ]; echo noother_says_correct( $temp ); ?> |
GET方式传入password的值,输出经过noother_says_correct函数处理之后的值。
noother_says_correct函数处理的逻辑为:先对password中的每一位进行判断,若在1--9之间,则直接返回false,若都满足,并且$number = '3735929054',$number==$password,则返回flag。
我们很容易能够注意到:
1 | $number == $temp |
这里两个等号,是弱类型比较,即会先将比较的两者类型进行转化后再比较,在计算机中0x开头的表示为十六进制,所以我们可以使用十六进制来绕过前面的for循环,同时满足等于temp
3735929054转换成十六进制后为:deadc0de
加上0x后为0xdeadc0de,可以看出可以逃逸出for循环中的限制,所以最后的payload为:
?password=0xdeadc0de
21 数字验证正则绕过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <?php error_reporting (0); $flag = 'flag{test}' ; if ( "POST" == $_SERVER [ 'REQUEST_METHOD' ]) { $password = $_POST [ 'password' ]; if (0 >= preg_match( '/^[[:graph:]]{12,}$/' , $password )) //preg_match — 执行一个正则表达式匹配 { echo 'Wrong Format' ; exit ; } while (TRUE) { $reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/' ; if (6 > preg_match_all( $reg , $password , $arr )) break ; $c = 0; $ps = array ( 'punct' , 'digit' , 'upper' , 'lower' ); //[[:punct:]] 任何标点符号 [[:digit:]] 任何数字 [[:upper:]] 任何大写字母 [[:lower:]] 任何小写字母 foreach ( $ps as $pt ) { if (preg_match( "/[[:$pt:]]+/" , $password )) $c += 1; } if ( $c < 3) break ; //>=3,必须包含四种类型三种与三种以上 if ( "42" == $password ) echo $flag ; else echo 'Wrong password' ; exit ; } } ?> |
这里用到了PHP正则表达式,简单列举一下字符串类的正则表达式:
1 2 3 4 5 6 7 8 9 10 11 12 | [[:alpha:]] :匹配任何字母 [[:digit:]] :匹配任何数字 [[:alnum:]] :匹配任何字母和数字 [[:space:]] :匹配任何空白字符 [[:upper:]] :匹配任何大写字母 [[:lower:]] :匹配任何小写字母 [[:punct:]] :匹配任何标点符号 [[:xdigit:]] :匹配任何16进制数字,相当于[0-9a-fA-F] [[:blank:]] :匹配空格和Tab,等价于[\t] [[:cntrl:]] :匹配所有ASCII 0到31之间的控制符 [[:graph:]] :匹配所有的可打印字符,等价于[^ \t\n\r\f\v] [[: print :]] :匹配所有的可打印字符和空格,等价于[^\t\n\r\f\v] |
使用POST方式传输password
1 2 3 | if ( "POST" == $_SERVER [ 'REQUEST_METHOD' ]) { $password = $_POST [ 'password' ]; |
第一个if中正则表达式匹配所有的可打印字符,并且需要大于等于12个
1 2 3 4 5 | if (0 >= preg_match( '/^[[:graph:]]{12,}$/' , $password )) //preg_match — 执行一个正则表达式匹配 { echo 'Wrong Format' ; exit ; } |
然后是一个while循环
第二个 if 里面,使用 preg_match_all
1 | $reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/' ; |
按照这个规则(标点符号;数字;大写字母;小写字母),将password至少分为6段
例如:abc123+a1? 就可以分为:abc 123 + a 1 ? 这6段
第三个 if 中,使用 for 循环判断 password 中是否存在 标点符号,数字,大写字母,小写字母中的至少三种
1 2 3 4 5 6 7 8 | $c = 0; $ps = array ( 'punct' , 'digit' , 'upper' , 'lower' ); //[[:punct:]] 任何标点符号 [[:digit:]] 任何数字 [[:upper:]] 任何大写字母 [[:lower:]] 任何小写字母 foreach ( $ps as $pt ) { if (preg_match( "/[[:$pt:]]+/" , $password )) $c += 1; } if ( $c < 3) break ; |
最后想要获得 flag ,还需要令传入的password=="42"
1 | if ( "42" == $password ) echo $flag ; |
从最后的相等出发,因为是弱类型比较,我们首先想到的是十六进制或者科学计数法。
在科学计数法中,有:https://www.php.net/manual/en/language.operators.comparison.php
其中
1 2 3 4 | var_dump(0 == "a" ); // 0 == 0 -> true var_dump( "1" == "01" ); // 1 == 1 -> true var_dump( "10" == "1e1" ); // 10 == 10 -> true var_dump(100 == "1e2" ); // 100 == 100 -> true |
所以我们可以有 4.2e1==42,也可以有420e-1==42,当然还可以继续如0.42e2==42
为了多一个减号,我们采用420e-1,再变形为:420.0e-1,满足password分成六段的要求,接着满足长度大于等于12的要求,变形为:420.00000e-1
POST传输:
参考链接:
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 数据库服务器 SQL Server 版本升级公告
· 程序员常用高效实用工具推荐,办公效率提升利器!
· C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)