PHP代码审计分段讲解(5)

11 sql闭合绕过

源代码为

<?php


if($_POST[user] && $_POST[pass]) {
    $conn = mysql_connect("*******", "****", "****");
    mysql_select_db("****") or die("Could not select database");
    if ($conn->connect_error) {
        die("Connection failed: " . mysql_error($conn));
} 
$user = $_POST[user];
$pass = md5($_POST[pass]);

//select user from php where (user='admin')#

//exp:admin')#

$sql = "select user from php where (user='$user') and (pw='$pass')";
$query = mysql_query($sql);
if (!$query) {
    printf("Error: %s
", mysql_error($conn));
    exit();
}
$row = mysql_fetch_array($query, MYSQL_ASSOC);
//echo $row["pw"];
  if($row['user']=="admin") {
    echo "<p>Logged in! Key: *********** </p>";
  }

  if($row['user'] != "admin") {
    echo("<p>You are not admin!</p>");
  }
}

?>

POST方式传入user和pass的值,同时连接数据库

if($_POST[user] && $_POST[pass]) {
    $conn = mysql_connect("*******", "****", "****");
    mysql_select_db("****") or die("Could not select database");
    if ($conn->connect_error) {
        die("Connection failed: " . mysql_error($conn));
} 
$user = $_POST[user];
$pass = md5($_POST[pass]);

将pass的值使用md5处理重新赋值,接着使用sql语句进行查询

$sql = "select user from php where (user='$user') and (pw='$pass')";

查询成功后进入判断

  if($row['user']=="admin") {
    echo "<p>Logged in! Key: *********** </p>";
  }

这里可以看到,登录的时候只对查询出结果里面的user进行了判断,当其的值为admin的时候,登录成功,并没有进行密码的校验

所以我们只需要闭合前面的SQL查询语句,令user=admin即可

所以payload为:

admin')#

密码输入什么都无所谓

sql语句最后变成了这样:

$sql = "select user from php where (user='admin')#') and (pw='$pass')";

也就是

$sql = "select user from php where (user='admin')

登录即可获取flag

 

12 X-Forwarded-For绕过指定IP地址

源代码为:

<?php
function GetIP(){
if(!empty($_SERVER["HTTP_CLIENT_IP"]))
    $cip = $_SERVER["HTTP_CLIENT_IP"];
else if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"]))
    $cip = $_SERVER["HTTP_X_FORWARDED_FOR"];
else if(!empty($_SERVER["REMOTE_ADDR"]))
    $cip = $_SERVER["REMOTE_ADDR"];
else
    $cip = "0.0.0.0";
return $cip;
}

$GetIPs = GetIP();
if ($GetIPs=="1.1.1.1"){
echo "Great! Key is *********";
}
else{
echo "错误!你的IP不在访问列表之内!";
}
?>

第一次遇到伪造IP的题目是在BugKu的做题平台上,这里的代码使用HTTP头里面的IP信息来进行IP访问列表的判断,而HTTP头的信息是可以通过我们抓包改变的。

这里我们跟题目一样,使用X_FORWARDED_FOR来进行IP的伪造

在请求头里面添加:X-Forwarded-For: 1.1.1.1

即可获取flag

 

13 md5加密相等绕过

<?php

$md51 = md5('QNKCDZO');
$a = @$_GET['a'];
$md52 = @md5($a);
if(isset($a)){
if ($a != 'QNKCDZO' && $md51 == $md52) {
    echo "nctf{*****************}";
} else {
    echo "false!!!";
}}
else{echo "please input a";}

?>

将 QNKCDZO MD5加密后,使用GET方式传入a的值,将a进行MD5加密,获取flag的条件为:

if ($a != 'QNKCDZO' && $md51 == $md52) {

传入的a不能为QNKCDZO,有需要令两者的md5加密后的值相等,这里需要用到MD5碰撞的知识

我们重新梳理一遍代码

$md51 = md5('QNKCDZO');

获得的md51的值为

0e830400451993494058024219903391

有意思的地方在于,这串字符串转换成为数字的话,按照科学计数法,它是0的830400451993494058024219903391次方,虽然看上去很大,但是由于底数为0,所以结果也是0,而比较两个md5值的时候是

$md51 == $md52

两个等号时会先进行类型转换,所以我们只需要找到一个md5值也是0e开头的字符串即可,这样它的md5加密结果科学计数法也会是0

当然这个也不需要找了,因为已经有大佬找好了:

https://blog.csdn.net/qq_38603541/article/details/97108663

我们选择其中的一个即可

获得flag

 

原文地址:https://www.cnblogs.com/Cl0ud/p/13254459.html