PHP代码审计系列(二)
本系列将收集多个PHP代码安全审计项目从易到难,并加入个人详细的源码解读。此系列将进行持续更新。
strcmp比较字符串
源码如下
<?php
$flag = "flag";
if (isset($_GET['a'])) {
if (strcmp($_GET['a'], $flag) == 0) //如果 str1 小于 str2 返回 < 0; 如果 str1大于 str2返回 > 0;如果两者相等,返回 0。
//比较两个字符串(区分大小写)
die('Flag: '.$flag);
else
print 'No';
}
?>
通读代码逻辑如下:
首先判断是否存在GET请求参数a
若存在使用strcmp函数比较a与flag是否相等,若相等则输出flag退出脚本
输入正确的flag,但我们是不知道flag的值的
利用strcmp函数的漏洞,当传入非字符串类型的数据这个函数将发生错误,但是在5.3
之前的php中,显示了报错的警告信息后,将return 0也就是会判断相等
sha()函数比较绕过
源码如下
<?php
$flag = "flag";
if (isset($_GET['name']) and isset($_GET['password']))
{
if ($_GET['name'] == $_GET['password'])
echo '<p>Your password can not be your name!</p>';
else if (sha1($_GET['name']) === sha1($_GET['password']))
die('Flag: '.$flag);
else
echo '<p>Invalid password.</p>';
}
else
echo '<p>Login first!</p>';
?>
通读代码逻辑如下:
首先判断GET请求中是否存在name与password参数若都存在继续进行
然后判断name是否等于password若等于则失败
经过sha1加密===相等则输出flag
这题也是条件矛盾了,根据sha1的漏洞进行比较的绕过(md5函数也存在)。
传入非字符串类型使得sha1函数返回错误为false,两个都这样操作就false===false条件成立
SESSION验证绕过
源码如下
<?php
$flag = "flag";
session_start();
if (isset ($_GET['password'])) {
if ($_GET['password'] == $_SESSION['password'])
die ('Flag: '.$flag);
else
print '<p>Wrong guess.</p>';
}
mt_srand((microtime() ^ rand(1, 10000)) % rand(1, 10000) + rand(1, 10000));
?>
通读代码逻辑如下:
首先启动session
判断GET请求是否携带password如果携带则继续
判断password与session中存储的password是否一致,一致则输出flag
使请求与session中存储的 password一致即可
http://localhost/phpbugs/08.php?password=
密码md5比较绕过
源码如下
<?php
//配置数据库
if($_POST[user] && $_POST[pass]) {
$conn = mysql_connect("********, "*****", "********");
mysql_select_db("phpformysql") or die("Could not select database");
if ($conn->connect_error) {
die("Connection failed: " . mysql_error($conn));
}
//赋值
$user = $_POST[user];
$pass = md5($_POST[pass]);
//sql语句
// select pw from php where user='' union select 'e10adc3949ba59abbe56e057f20f883e' #
// ?user=' union select 'e10adc3949ba59abbe56e057f20f883e' #&pass=123456
$sql = "select pw from php where user='$user'";
$query = mysql_query($sql);
if (!$query) {
printf("Error: %s\n", mysql_error($conn));
exit();
}
$row = mysql_fetch_array($query, MYSQL_ASSOC);
//echo $row["pw"];
if (($row[pw]) && (!strcasecmp($pass, $row[pw]))) {
//如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。
echo "<p>Logged in! Key:************** </p>";
}
else {
echo("<p>Log in failure!</p>");
}
}
?>
通读代码逻辑如下:
首先判断POST请求中是否存在user与pass字段,若存在尝试连接数据库,连接失败结束脚本
之后对pass字段进行MD5加密赋值给变量$pass,user字段赋值给、$user
执行以下sql,如果未查询到结果结束脚本
select pw from php where user='$user'
若查询到数据结果,将执行mysql_fetch_array函数以关联数组形式返回数据查询结果
如果返回的数组中存在pw字段并且$pass等于数组中的pw字段输出flag
sql中存在注入,构造修改sql返回的pw结果集,payload如下
user=' union select 'e10adc3949ba59abbe56e057f20f883e'#&pass=123456
urldecode二次编码绕过
源码如下
<?php
if(eregi("hackerDJ",$_GET[id])) {
echo("<p>not allowed!</p>");
exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
echo "<p>Access granted!</p>";
echo "<p>flag: *****************} </p>";
}
?>
通读代码逻辑如下:
首先判断GET请求中是否存在id参数,若存在终止脚本
对id参数通过urldecode函数进行url解码
如果解码后的id等于hackerDJ则输出flag
对hackerDJ中的h进行二次url编码绕过
h对应的url编码未%68,%68url编码结果为%2568