<?php
header("Content-type:text/html;charset=utf-8");
$link = mysqli_connect('localhost',"root","root","security");
function ip(){
if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'),'unknown')){
$ip = getenv('HTTP_CLIENT_IP');
}elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'),'unknown')){
$ip = getenv('HTTP_X_FORWARDED_FOR');
}elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'),'unknown')){
$ip = getenv('REMOTE_ADDR');
}elseif (isset($SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER,'unknown')){
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}
@$ip = ip();
$sql = "select * from uagents where ip_address = '$ip'";
echo $sql;
echo '<br>---------------<br>';
$result = mysqli_query($link,$sql);
if ($row = mysqli_fetch_assoc($result)){
echo '你的ip是'.$row['ip_address'];
}else{
echo '你的ip无';
}
mysqli_close($link)
?>
跟着写了一个py的脚本,开启web服务后通过抓包能够添加对应的字段完成注入
代码审计:
看看 function ip中的内容
判断是否存在client-ip:字段,且不为空。。以此类推
$SERVER['REMOTE_ADDR']是不可控的,抓包分析我认为是本地的ip地址
这里可以在if中继续加判断是否存在HTTP_X_FORWARDED_FOR
if(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'),'unknown')){
$ip = getenv('HTTP_X_FORWARDED_FOR');
这里HTTP_X_FORWARDED_FOR对应的是数据包中x-forwarded-for:字段
往下看函数把返回值赋值给变量$ip,再把它拼接进sql语句中
接下来进行echo输出,输出的结果是数据库中第三个字段,因此回显位是第三位
在burp中构造client-ip:字段,后加注入语句,这里用联合查询
' union select 1,2,(user()),4 # //这里我尝试用--空格和--+都报错,不知道为啥
成功爆出结果
这里如何防止sql注入,用正则匹配,保证拼接内容$ip是一个ip地址
修改代码如下:
<?php
header("Content-type:text/html;charset=utf-8");
$link = mysqli_connect('localhost',"root","root","security");
function ip(){
if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'),'unknown')){
$ip = getenv('HTTP_CLIENT_IP');
}elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'),'unknown')){
$ip = getenv('HTTP_X_FORWARDED_FOR');
}elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'),'unknown')){
$ip = getenv('REMOTE_ADDR');
}elseif (isset($SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER,'unknown')){
$ip = $_SERVER['REMOTE_ADDR'];
}
$res =preg_match('/[\d\.]{7,15}/',$ip,$matches)?$matches[0]:'';
return $res;
}
@$ip = ip();
$sql = "select * from uagents where ip_address = '$ip'";
echo $sql;
echo '<br>---------------<br>';
$result = mysqli_query($link,$sql);
if ($row = mysqli_fetch_assoc($result)){
echo '你的ip是'.$row['ip_address'];
}else{
echo '你的ip无';
}
mysqli_close($link)
?>
增加一个$res变量,对$ip进行正则匹配preg_match
其中\d是数字0-9\.是用反斜杠匹配. 因为.在正则中匹配除了斜杠的所有内容{7,15}是ipv4最长和最短地址(包括.的)
最短:1.1.1.1
最长:111.111.111.111
验证
用burp改包
phpstorm中动态调试
函数结束后ip变成" "