CTF:PHP弱类型常见考点总结

admin 2025年6月8日09:25:34评论14 views字数 4095阅读13分39秒阅读模式

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($_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) == sha1($b),当$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" → Truefalse == "0" → True

CTF应用

if($_GET['a']=='admin'){/* 传入a=0可绕过 */}

2. 哈希弱碰撞(0e开头的MD5/SHA1)

  • 原理:某些字符串哈希后以0e开头,松散比较时视为0。

    • MD5示例

      md5('240610708')=0e462097431906509019562988736854

    • md5('QNKCDZO')=0e830400451993494058024219903391

    • // 满足 $_GET['a'] != $_GET['b'],但 md5($_GET['a']) == md5($_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){

  • case1:// 匹配成功,字符串转为整型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 开始计数),若未找到则返回 falsePHP 的松散比较(==)会将 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. 十六进制/八进制字符串转换

  • 原理:字符串中的十六进制/八进制格式可能被转换为数字。

    $input='0x61646d696e';// hex("admin")if(is_numeric($input)&&$input=='admin'){// 0x61646d696e 转为十进制后与字符串比较,可能绕过}

12. 浮点数精度问题

  • 原理:浮点数比较时精度损失导致非预期结果。

    $a=0.99999999999999999;$b=1;if($a==$b){// true,精度丢失后均为1 }

13. empty() 和 isset() 的陷阱

  • 原理:运算符(如 . 和 +)强制转换变量类型。

    $a="123abc"+456;// 579(字符串转整型123后相加)$b="123".456;// "123456"(拼接为字符串)

  • 原理empty() 认为 "0"0null 均为“空”。

    if(empty($_GET['auth'])){

    // 传入 auth=0 时,empty(0) → true,绕过身份检查}

防御建议

  1. 使用严格比较(===)。

  2. 函数启用严格模式,如in_array(..., true)

  3. 避免直接比较哈希值,优先对比原始字符串。

  4. 对用户输入显式类型转换(如(int)$_GET['id'])。

原文始发于微信公众号(小话安全):CTF:PHP弱类型常见考点总结

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月8日09:25:34
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CTF:PHP弱类型常见考点总结http://cn-sec.com/archives/3774401.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息