CTF:PHP弱类型常见考点总结
PHP弱类型比较是CTF比赛中的常见考点,当使用==进行比较时,类型转换可能导致非预期的结果。
如0 == “abc"会返回false,但"0e12345” == "0e67890"会被认为是相等的,因为都被视为科学计数法的0。另外,像true和任何非空字符串比较可能为真,如true == "non-empty string"是true。
还有MD5和SHA1的弱碰撞。如两个不同的字符串经过哈希后以0e开头,比较时会视为相等。例如,MD5(‘240610708’)是0e462097431906509019562988736854,和MD5(‘QNKCDZO’)的结果类似,这样比较时会相等。
switch和in_array的松散比较。当switch使用松散类型时,比如字符串和数字比较,比如case 0会匹配字符串"abc",因为字符串转换为数字是0。而in_array默认不开启严格模式,所以可能被绕过。比如查找字符串"abc"在数组中是否有0的情况,因为类型转换后可能匹配。
还有strcmp和数组的漏洞。如果strcmp的参数是数组,会返回0,比如strcmp( G E T [ ′ p a s s w o r d ′ ] , ′ a b c ′ ) ,如果传入 p a s s w o r d [ ] = x ,就会导致返回 0 ,从而绕过检查。同样, m d 5 ( 数组 ) 会返回 n u l l ,如果比较 m d 5 ( _GET[‘password’], ‘abc’),如果传入password[]=x,就会导致返回0,从而绕过检查。同样,md5(数组)会返回null,如果比较md5( GET[′password′],′abc′),如果传入password[]=x,就会导致返回0,从而绕过检查。同样,md5(数组)会返回null,如果比较md5(_GET[‘a’]) == md5($_GET[‘b’]),传入数组的话,两边都为null,从而相等。
JSON解析中的问题,比如json_decode解析数字字符串为整数,可能导致类型比较问题。例如,如果后端期望的是字符串类型的值,但传入的是数字,可能被误判。例如,{“num”: “123”}和{“num”: 123}在PHP中会被视为不同,但如果处理不当,可能被利用。
还有is_numeric的问题,比如字符串中包含十六进制或科学计数法会被认为是数字,可能导致注入或溢出。例如,0x61646d696e会被当作数字,转换为十进制后是admin的ASCII值,可能用于绕过检查。
另外,switch的松散比较和类型转换,比如当switch传入的是字符串,而case是数字时,可能导致非预期的分支执行。比如传入"1abc",转换为整数1,会匹配case 1。
还有关于=的严格比较和的区别,在CTF中常被用来设计陷阱,比如要求使用时可以通过类型转换绕过,而=则需要完全匹配。
还有数组和字符串的转换,比如当数组被当作字符串使用时,会变成"Array",而某些情况下可能被利用,比如在拼接SQL查询时,但可能这个点更多是注入相关,但弱类型可能也有涉及。
还有关于NULL和空字符串的比较,比如使用时,NULL == “” 为true,而=则为false。这可能在某些条件判断中被利用。
另外,可能涉及十六进制和八进制的字符串转换,比如"0x1a"被转换为26,或者"0123"被当作八进制,但PHP中可能在某些函数处理时需要注意。
使用sha1处理数组返回false,如果比较sha1( a ) = = s h a 1 ( a) == sha1( a)==sha1(b),当 a 和 a和 a和b都是数组时,两边都是false,从而相等。或者使用===比较时,两边都是false,但题目可能设计成松散比较,导致false == 0或者其他情况。
还有,当变量被用来进行数学运算时,自动转换为整数或浮点数,可能造成溢出或截断,比如大数字字符串转换为整数时变成负数,或者科学计数法表示,如"1e3"被转换为1000。
另外,在正则表达式匹配时,使用弱类型可能导致绕过,比如使用^0在PHP中可能因为类型转换导致匹配失败。
可能还需要考虑强制类型转换,比如在条件判断中使用加法或其他运算符,导致类型转换,例如"123abc" + 0得到123,从而绕过某些检查。
总结下来,常见的考点应该包括:
\1. 松散比较(==)的类型转换问题,包括科学计数法、字符串转数字等。
\2. 哈希比较中的0e开头字符串。
\3. switch和in_array的松散比较。
\4. strcmp等函数处理数组时的漏洞。
\5. JSON解析中的类型混淆。
\6. is_numeric的检测问题(十六进制、科学计数法)。
\7. 类型转换在条件判断或数学运算中的副作用。
\8. 某些函数返回值的类型问题,如md5数组返回null。
\9. 十六进制和八进制的转换问题。
\10. 使用恒等(=)和相等()运算符的不同。
可能还要注意PHP版本的不同,比如某些行为在PHP5和PHP7中的差异,例如在PHP7中,0e开头的数字字符串在比较时会当作数字,而某些函数的行为可能变化,但CTF题目可能仍以PHP5的环境为主。
以下是典型考点及示例:
*1. 松散比较(*==*)的类型转换***
-
原理:PHP在
==比较时会自动转换类型,导致非预期结果。 -
- 科学计数法绕过:
"0e12345" == "0e67890"→True(视为0)。 - 字符串与数字比较:
"123abc" == 123→True(字符串转为整型123)。 - 布尔值陷阱:
true == "non-empty"→True,false == "0"→True。
- 科学计数法绕过:
CTF应用:
if ($_GET[‘a’] == ‘admin’) { /* 传入a=0可绕过 */ }
*2. 哈希弱碰撞(0e开头的MD5/SHA1)*
-
原理:某些字符串哈希后以
0e开头,松散比较时视为0。 -
-
MD5示例:
md5(‘240610708’) = 0e462097431906509019562988736854
-
md5(‘QNKCDZO’) = 0e830400451993494058024219903391
-
// 满足 KaTeX parse error: Undefined control sequence: \[ at position 6: \_GET\̲[̲‘a’\] != G E T …_GET[‘b’])
-
SHA1示例:
sha1('aaroZmOk')和sha1('aaK1STfY')均以0e开头。
-
*3. 函数参数类型漏洞*
- strcmp数组绕过:
strcmp($_POST['pass'], 'password')中,若pass为数组(pass[]=1),返回NULL,松散比较时NULL == 0。 - md5/sha1处理数组:
md5(array())返回NULL,若比较md5($_GET['a']) == md5($_GET['b']),传入数组使两边均为NULL。
*4. switch/in_array的松散比较*
-
switch类型转换:
$input = “1abc”;
-
switch ($input) {
-
case 1: // 匹配成功,字符串转为整型1
-
// 执行敏感操作}
-
in_array默认松散:
in_array('abc', [0, 1, 2])→True('abc’转为整型0)。
*5. JSON解析类型混淆*
-
原理:
json_decode可能将字符串数字解析为整型。$data = json_decode(‘{“is_admin”: “0”}’);
-
if ($data->is_admin == true)
-
{ // "0"转为整型0,0 == false // 被绕过}
*6. is_numeric的陷阱*
- 十六进制/科学计数法:
is_numeric('0x1a')→True(PHP5),is_numeric('1e3')→True。 - 利用场景:
传入0x61646d696e(hex转ASCII为admin)绕过字符串过滤。
*7. 类型转换的数学运算*
- 字符串转数字截断:
"123abc" + 456 = 579,"abc"部分被忽略。 - 科学计数法计算:
"1e3" == 1000→True。
*8. 严格比较(=)与松散比较()*
- 绕过技巧:若代码误用
==,可通过类型转换构造Payload。
if($_POST[‘code’] == 12345) {
// 传入code=12345abc 可绕过(转为整型12345)}
9.strpos 返回值的类型问题
在 PHP 中,strpos() 函数用于查找子字符串在目标字符串中首次出现的位置,其返回值类型存在特殊的类型问题,尤其在松散比较(==)场景下可能导致安全漏洞。返回子字符串在目标字符串中的位置索引(从 0 开始计数),若未找到则返回 false。PHP 的松散比较(==)会将 0(整数)和 false(布尔值)视为相等。
if (strpos($_GET[‘data’], ‘ctf’) == false) {
// 认为未找到’ctf’,
但若 data=ctf123,strpos返回0,0 == false → 成立!
}
// 应使用严格比较:strpos(…) === false
*10. 空字符串与零的隐式转换*
-
原理:空字符串
""在比较/运算中可能转为0。if ($_POST[‘code’] == 0) { // 传入 code= 或 code=“”,空字符串转为0,绕过验证}
*11. 十六进制/八进制字符串转换*
-
原理:字符串中的十六进制/八进制格式可能被转换为数字。
i n p u t = ′ 0 x 61646 d 696 e ′ ; / / h e x ( " a d m i n " ) i f ( i s n u m e r i c ( input = ‘0x61646d696e’; // hex(“admin”)if (is_numeric( input=′0x61646d696e′;//hex(“admin”)if(isnumeric(input) && $input == ‘admin’) { // 0x61646d696e 转为十进制后与字符串比较,可能绕过}
*12. 浮点数精度问题*
-
原理:浮点数比较时精度损失导致非预期结果。
a = 0.99999999999999999 ; a = 0.99999999999999999; a=0.99999999999999999;b = 1;if ($a == $b) { // true,精度丢失后均为1 }
*13.* empty() *和* isset() *的陷阱*
-
原理:运算符(如
.和+)强制转换变量类型。a = " 123 a b c " + 456 ; / / 579 (字符串转整型 123 后相加) a = “123abc” + 456; // 579(字符串转整型123后相加) a=“123abc”+456;//579(字符串转整型123后相加)b = “123” . 456; // “123456”(拼接为字符串)
-
原理:
empty()认为"0"、0、null均为“空”。if (empty($_GET[‘auth’])) {
// 传入 auth=0 时,empty(0) → true,绕过身份检查}
*防御建议*
- 使用严格比较(
===)。 - 函数启用严格模式,如
in_array(..., true)。 - 避免直接比较哈希值,优先对比原始字符串。
- 对用户输入显式类型转换(如
(int)$_GET['id'])。
网络安全学习资源分享:
给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
因篇幅有限,仅展示部分资料,朋友们如果有需要全套《网络安全入门+进阶学习资源包》,需要点击下方链接即可前往获取
读者福利 | 优快云大礼包:《网络安全入门&进阶学习资源包》免费分享 (安全链接,放心点击)
👉1.成长路线图&学习规划👈
要学习一门新的技术,作为新手一定要先学习成长路线图,方向不对,努力白费。
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。


👉2.网安入门到进阶视频教程👈
很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,其中一共有21个章节,每个章节都是当前板块的精华浓缩。(全套教程文末领取哈)


👉3.SRC&黑客文档👈
大家最喜欢也是最关心的SRC技术文籍&黑客技术也有收录
SRC技术文籍:

黑客资料由于是敏感资源,这里不能直接展示哦!(全套教程文末领取哈)
👉4.护网行动资料👈
其中关于HW护网行动,也准备了对应的资料,这些内容可相当于比赛的金手指!

👉5.黑客必读书单👈

👉6.网络安全岗面试题合集👈
当你自学到这里,你就要开始思考找工作的事情了,而工作绕不开的就是真题和面试题。

所有资料共282G,朋友们如果有需要全套《网络安全入门+进阶学习资源包》,可以扫描下方二维码或链接免费领取~
读者福利 | 优快云大礼包:《网络安全入门&进阶学习资源包》免费分享 (安全链接,放心点击)
549

被折叠的 条评论
为什么被折叠?



