이 글에서는 PHP의 문자 오프셋 기능으로 인해 발생하는 우회 취약점에 대한 관련 정보를 주로 소개합니다. 이 글에서는 취약점의 형성을 자세히 소개할 뿐만 아니라, 더 중요한 것은 확실한 참고 자료인 복구 방법을 소개합니다. 배움의 가치, 필요한 친구들은 아래를 구경하러 오세요.
php의 문자 오프셋 기능
PHP의 문자열에는 매우 흥미로운 기능이 있습니다. PHP의 문자열도 배열처럼 평가될 수 있습니다.
$test = "hello world"; echo $test[0];
최종 결과는 h입니다.
하지만 위 기능은 가끔 예상치 못한 효과를 낳기도 합니다. 아래 코드를 보세요
$mystr = "hello world"; echo $mystr["pass"];
위 코드의 출력 결과는 왜일까요? 사실 다른 많은 언어와 마찬가지로 PHP의 문자열도 배열처럼 값을 얻기 위해 첨자를 사용할 수 있습니다. $mystr["pass"]
를 전달하면 암시적으로 0으로 변환되므로 $mystr[0]
의 출력 결과는 첫 번째 문자 h입니다.$mystr["pass"]
中pass会被进行隐性类型转换为0,这样$mystr[0]
的输出结果就是首字母h.
同样地,如果尝试如下的代码:
$mystr = "hello world"; echo $mystr["1pass"];
输出结果就是e.因为1pass会被隐性类型转换为1,$mystr[1]
的输出结果就是第二个字母e.
字符特性造成的漏洞
下面这段代码是在在phpspy2006中用于判断登录时所使用的代码。
$admin['check'] = "1"; $admin['pass'] = "angel"; ...... if($admin['check'] == "1") { .... }
这样的验证逻辑如果利用上述的特性就很容易地就可以被绕过。$admin没有被初始定义为数组类型,那么当我们用字符串提交时phpsyp.php?admin=1abc
时,php会取字符串1xxx的第一位,成功绕过if的条件判断。
上面那段代码是一个代码片段,接下来的这段代码是一段完整的逻辑代码,来自于php4fun中第5题,比较有意思。
<?php # GOAL: overwrite password for admin (id=1) # Try to login as admin # $yourInfo=array( //this is your user data in the db # 'id' => 8, # 'name' => 'jimbo18714', # 'pass' => 'MAYBECHANGED', # 'level' => 1 # ); require 'db.inc.php'; function mres($str) { return mysql_real_escape_string($str); } $userInfo = @unserialize($_GET['userInfo']); $query = 'SELECT * FROM users WHERE id = \'' . mres($userInfo['id']) . '\' AND pass = \'' . mres($userInfo['pass']) . '\';'; $result = mysql_query($query); if (!$result || mysql_num_rows($result) < 1) { die('Invalid password!'); } $row = mysql_fetch_assoc($result); foreach ($row as $key => $value) { $userInfo[$key] = $value; } $oldPass = @$_GET['oldPass']; $newPass = @$_GET['newPass']; if ($oldPass == $userInfo['pass']) { $userInfo['pass'] = $newPass; $query = 'UPDATE users SET pass = \'' . mres($newPass) . '\' WHERE id = \'' . mres($userInfo['id']) . '\';'; mysql_query($query); echo 'Password Changed.'; } else { echo 'Invalid old password entered.'; }
这道题目网上也仅仅只是给了一个最终的答案,其中的原理都没有说或者没有说得很详细。其实原理就是上面讲到的php的字符特性。
题目要求很简单就是修改admin的密码,admin的id为1。我们需要思考以下几个问题:
如何在更新的时候将id修改为1
$userInfo['pass'] = $newPass;
这行代码有什么作用,为什么会在if判断语句中存在这种的代码
想通了这两个问题,那么最终的解决方法也有了。将id为8的用户的密码修改为8,然后传入一个userInfo的字符串‘8',突破查询防护,最后利用$userInfo['pass'] = $newPass
将id修改为1。
最终的payload就是;
第一次提交, index.php?userInfo=a:2:{s:2:"id";i:8;s:4:"pass";s:12:"MAYBECHANGED";}&oldPass=MAYBECHANGED&newPass=8
,目的是将id为8的用户的密码修改为8
第二次提交,index.php?userInfo=s:1:"8";&oldPass=8&newPass=1
,这样序列化$userInfo得到的就是字符串‘8',即$userInfo = ‘8'
,这样数据库查询验证就可以通过。之后的if验证也可以通过,通过这行代码$userInfo['pass'] = $newPass;
,由于$newpass的值为1,那么上述代码变为了$userInfo['pass'] = 1;
,$userInfo
由于一个字符串类型,最后得到的是$userInfo='1'
마찬가지로, 다음 코드를 시도해 보세요.
rrreee출력 결과는 e입니다. 1pass는 암시적으로 1로 변환되므로 $mystr[1]
의 출력 결과는 두 번째 문자 e입니다.
phpsyp.php?admin=1abc
를 제출하면 PHP는 문자열 1xxx의 첫 번째 비트를 가져와 if 조건부 판단을 성공적으로 우회합니다. . 🎜🎜위 코드는 코드 조각이고 다음 코드는 php4fun의 질문 5에서 나온 완전한 논리 코드입니다. 이는 매우 흥미롭습니다. 🎜🎜🎜🎜rrreee🎜이 질문은 온라인에서 최종 답변만 제공할 뿐, 원리가 설명되지 않거나 자세히 설명되지 않습니다. 사실 그 원리는 위에서 언급한 PHP의 성격적 특성입니다. 🎜🎜🎜질문 요구 사항은 매우 간단합니다. 관리자의 비밀번호를 변경하는 것입니다. 다음 질문에 대해 생각해야 합니다. 🎜$userInfo[ 'pass'] = $newPass;
이 코드 줄은 무엇을 합니까? if 판단문에 이런 종류의 코드가 존재하는 이유는 무엇입니까?$userInfo['pass'] = $newPass
를 사용하여 수정합니다. ID는 1입니다. 🎜🎜🎜최종 페이로드는 🎜🎜🎜첫 번째 제출, index.php?userInfo=a:2:{s:2:"id";i:8;s:4:"pass"; 12:"MAYBECHANGED";}&oldPass=MAYBECHANGED&newPass=8
, 목적은 ID가 8인 사용자의 비밀번호를 8🎜🎜🎜두 번째 제출, index.php?userInfo=s :1로 변경하는 것입니다. :"8";&oldPass=8&newPass=1
, 이런 식으로 $userInfo를 직렬화하여 얻은 문자열 '8', 즉 $userInfo = '8'
, 데이터베이스 쿼리 검증을 통과하세요. 후속 if 확인도 이 코드 줄 $userInfo['pass'] = $newPass;
를 통과할 수 있습니다. $newpass 값이 1이므로 위 코드는 $userInfo[가 됩니다. 'pass'] = 1;
,$userInfo
문자열 유형으로 인해 최종 결과는 $userInfo='1'
이고, 마지막으로 ID는 업데이트됨 사용자 1명의 비밀번호가 사라졌습니다. 🎜🎜🎜🎜수정 방법🎜🎜🎜🎜이러한 취약점을 수정하는 방법도 매우 간단합니다. 데이터 유형을 미리 정의하고 사용 시 예상되는 데이터 유형과 일치하는지 확인하세요. 그렇지 않으면 위에서 언급한 우회 문제가 발생합니다. 동시에 입력을 제어해야 하며, 입력 데이터를 확인하고 함부로 사용해서는 안 됩니다. 🎜위 내용은 PHP의 오프셋 문자로 인한 취약점 우회 결과에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!