本系列将收集多个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\n", mysql_error($conn));
exit();
}
$row = mysql_fetch_array($query, MYSQL_ASSOC);
//echo $row["pw"];
if($row['user']=="admin") {
echo "Logged in! Key: ***********
";
}
if($row['user'] != "admin") {
echo("You are not admin!
");
}
}
?>
通读代码出现漏洞的是这一段sql存在注入,通过’)#闭合可以绕过密码的校验
$sql = "select user from php where (user='$user') and (pw='$pass')"
payload:
user=admin')#&pass=1
源码如下
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不在访问列表之内!";
}
?>
通读代码发现只要GetIP()方法返回的IP为1.1.1.1就可以获得flag,这个方法是根据HTTP_CLIENT_IP、HTTP_X_FORWARDED_FOR、REMOTE_ADDR请求头来校验ip的
我用了burp更改请求头,推荐个burp插件fakeip一键生成多种请求头进行绕过
源码如下
$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加密后相等
$a != 'QNKCDZO' && $md51 == $md52
==在进行比较的时候会进行数据转换,字符串与数字进行比较的时候字符串开头数字会被转换为数值进行比较例如
echo '123tpaer' == 123;
结果是1
QNKCDZO经过MD5加密后为0e开头
字符串e0XXX会转换为0,我们只需要找到MD5加密后开头为0e的字符串即可百度有很多
payload:
http://localhost/phpbugs/13.php?a=s155964671a
intval函数四舍五入
源码如下
if($_GET[id]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$id = intval($_GET[id]);
$query = @mysql_fetch_array(mysql_query("select content from ctf2 where id='$id'"));
if ($_GET[id]==1024) {
echo "no! try again
";
}
else{
echo($query[content]);
}
}
?>
通读代码主要需要绕过以下条件
$_GET[id]==1024
在查询sql之前使用了intval函数
利用intval的四舍五入特性绕过
echo intval('1024.1');
//结果为1024
源码如下
$flag = "flag";
if (isset ($_GET['nctf'])) {
if (@ereg ("^[1-9]+$", $_GET['nctf']) === FALSE)
echo '必须输入数字才行';
else if (strpos ($_GET['nctf'], '#biubiubiu') !== FALSE)
die('Flag: '.$flag);
else
echo '骚年,继续努力吧啊~';
}
?>
通读代码逻辑如下:
首先判断GET请求中的nctf字段,对该字段进行校验是否输入的都是数字不是则结束脚本,使用strops判断字符串#biubiubiu中是否存在nctf的字段如果存在输出flag
需要绕过以下条件
strpos ($_GET['nctf'], '#biubiubiu') !== FALSE
可以通过报错使strpos返回NULL,满足条件NULL!== FALSE
也可以利用erge的截断漏洞,绕过以下条件
@ereg ("^[1-9]+$", $_GET['nctf']) === FALSE