[红日安全]代码审计Day4 - strpos使用不当引发漏洞
字数 1072 2025-08-18 11:37:33

PHP代码审计教学:strpos使用不当引发的安全漏洞

1. 漏洞背景

本教学文档基于红日安全团队的代码审计案例,重点分析PHP中strpos()函数使用不当导致的安全漏洞,以及类似的弱类型比较问题在实际CMS中的危害。

2. 基础漏洞分析

2.1 示例代码问题

// 示例代码片段
if (strpos($username, '<') !== false || strpos($username, '>') !== false) {
    die('Illegal character in username');
}
if (strpos($password, '<') !== false || strpos($password, '>') !== false) {
    die('Illegal character in password');
}

// 使用用户输入构建XML
$xml = "<user><name>$username</name><pass>$password</pass></user>";

2.2 strpos函数行为

  • strpos()函数返回查找字符串首次出现的位置
  • 如果字符串开头就是目标字符,返回0
  • 如果找不到目标字符,返回false
  • 在PHP中,0 == falsetrue,但0 === falsefalse

2.3 漏洞原理

开发者错误地使用了!strpos()来判断字符是否存在:

  • 当字符在开头时,strpos()返回0!0true
  • 当字符不存在时,strpos()返回false!falsetrue
  • 导致无法正确过滤开头位置的<>字符

2.4 有效Payload

username=<"><injected-tag%20property="
password=<injected-tag>

3. 实际案例分析:DeDecms V5.7SP2任意密码重置

3.1 漏洞位置

member/resetpassword.php文件中的安全问题和答案验证逻辑

3.2 关键代码

if($dopost == 'safequestion') {
    // 查询用户安全问题信息
    $row = $dsql->GetOne("SELECT safequestion,safeanswer,userid,email FROM `#@__member` WHERE mid = '$mid' ");
    
    // 漏洞点:弱类型比较
    if($row['safequestion'] == $safequestion && $row['safeanswer'] == $safeanswer) {
        sn($mid, $row['userid'], $row['email'], 'N');
        exit();
    }
}

3.3 漏洞利用条件

  1. 用户未设置安全问题(默认safequestion="0", safeanswer=null
  2. 使用弱类型比较(==而非===)

3.4 有效Payload

safequestion=0.0&safeanswer=
safequestion=0.&safeanswer=
safequestion=0e1&safeanswer=

3.5 攻击流程

  1. 访问重置密码页面,提交上述Payload
  2. 系统进入sn()函数,生成临时密码记录
  3. 获取返回的key值(md5加密的随机值)
  4. 使用key构造密码重置链接
  5. 完成密码修改

4. 漏洞修复方案

4.1 strpos使用建议

// 正确用法
if (strpos($username, '<') !== false || strpos($username, '>') !== false) {
    die('Illegal character in username');
}

4.2 弱类型比较修复

// 使用严格比较
if($row['safequestion'] === $safequestion && $row['safeanswer'] === $safeanswer) {
    // 安全逻辑
}

4.3 其他防御措施

  1. 对用户输入进行HTML实体编码
  2. 使用专门的XML编码函数处理XML数据
  3. 实施白名单而非黑名单过滤策略

5. 总结要点

  1. strpos()函数返回0false在松散比较中行为相同
  2. 安全验证必须使用严格比较(===!==)
  3. 默认值设置可能引入安全隐患
  4. 密码重置流程需要多重验证机制
  5. 用户输入必须经过严格过滤和编码

6. 扩展思考

  1. 如何设计更安全的密码重置流程?
  2. 除了strpos(),PHP中还有哪些函数存在类似的陷阱?
  3. 如何在开发过程中避免这类弱类型比较问题?
  4. 自动化工具如何检测这类逻辑漏洞?

通过本案例的学习,开发者应深刻理解PHP类型系统的特点及其对安全的影响,在代码审计过程中特别注意比较操作和用户输入处理的正确性。

PHP代码审计教学:strpos使用不当引发的安全漏洞 1. 漏洞背景 本教学文档基于红日安全团队的代码审计案例,重点分析PHP中 strpos() 函数使用不当导致的安全漏洞,以及类似的弱类型比较问题在实际CMS中的危害。 2. 基础漏洞分析 2.1 示例代码问题 2.2 strpos函数行为 strpos() 函数返回查找字符串首次出现的位置 如果字符串开头就是目标字符,返回 0 如果找不到目标字符,返回 false 在PHP中, 0 == false 为 true ,但 0 === false 为 false 2.3 漏洞原理 开发者错误地使用了 !strpos() 来判断字符是否存在: 当字符在开头时, strpos() 返回 0 , !0 为 true 当字符不存在时, strpos() 返回 false , !false 为 true 导致无法正确过滤开头位置的 < 和 > 字符 2.4 有效Payload 3. 实际案例分析:DeDecms V5.7SP2任意密码重置 3.1 漏洞位置 member/resetpassword.php 文件中的安全问题和答案验证逻辑 3.2 关键代码 3.3 漏洞利用条件 用户未设置安全问题(默认 safequestion="0" , safeanswer=null ) 使用弱类型比较( == 而非 === ) 3.4 有效Payload 3.5 攻击流程 访问重置密码页面,提交上述Payload 系统进入 sn() 函数,生成临时密码记录 获取返回的 key 值(md5加密的随机值) 使用key构造密码重置链接 完成密码修改 4. 漏洞修复方案 4.1 strpos使用建议 4.2 弱类型比较修复 4.3 其他防御措施 对用户输入进行HTML实体编码 使用专门的XML编码函数处理XML数据 实施白名单而非黑名单过滤策略 5. 总结要点 strpos() 函数返回 0 和 false 在松散比较中行为相同 安全验证必须使用严格比较( === 和 !== ) 默认值设置可能引入安全隐患 密码重置流程需要多重验证机制 用户输入必须经过严格过滤和编码 6. 扩展思考 如何设计更安全的密码重置流程? 除了 strpos() ,PHP中还有哪些函数存在类似的陷阱? 如何在开发过程中避免这类弱类型比较问题? 自动化工具如何检测这类逻辑漏洞? 通过本案例的学习,开发者应深刻理解PHP类型系统的特点及其对安全的影响,在代码审计过程中特别注意比较操作和用户输入处理的正确性。