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传输:
参考链接:
__EOF__

本文链接:https://www.cnblogs.com/Cl0ud/p/13290628.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!