手工操作几种常见SQL注入

手工SQL注入示例

一、联合查询注入(回显注入)

是一种结合数据库原始报错信息和union查询的注入方式

使用场景:数据库中查询的结果能够直接在前端页面中展示出来

UNION 操作符用于将两个或多个 SELECT 语句执行的结果合并为一个结果集输出,以下是演示示例:

image-20240614141950605

了解MySQL数据库中几个特殊的数据库

sys

mysql

performanc_schema

information_schema (是MySQL的元数据信息数据库,存储了关于数据库、表及其字段、用户等的元数据,MySQL5.0及以后的版本才有这个库,也是进行SQL注入时重点关注的一个库)

查询时使用的关键字段信息(这个不重要)

image-20240614143004688

操作步骤

(一)判断注入点
判断注入点的数据类型

(1)一般情况下,看默认的输入的值与输入点的功能即可看出输入点的数据类型(默认输入时数字,则可能是数字型;默认输入是字符,则一定是字符型)。

(2)判断数字型,使用四则运算判断(如果id=n和id=(n+1)-1产生的结果一致,则可能是数字型,再尝试添加闭合符号,时sql执行出错,就能证明注入点的数据类型为数字型)

(3)判断字符型(先是报错再闭合),如果有原始数据库报错信息,就一一枚举可能得闭合符号。

(4)判断注入点是否存在,在疑似注入点后加上 and 1=1 和and 1=2,如果两次执行的页面发生了改变(也就是拼接的sql语句在数据库中执行的时候出了问题,页面就会有所改变),说明漏洞存在

(二)判断表中的列数

利用order by 结合折半查找的方式确定表中的列数。

(三)判断数据回显的位置

利用union并将原始查询置空(置空的目的,是让union前面的select查询语句查不到结果,union前面的select语句就不会输出内容,使整个sql语句只输出union后面select语句的查询内容(也就是我们想要看到的内容))来判断数据回显的位置。

(四)将待查询的内容替换到数据回显的位置

示例(以sqlli_labs第3关为例)

(一)判断注入点

(1)判断注入点的数据类型

image-20240619164432384

image-20240619164502843

可以看到输入参数id=1和id=2时返回的结果不一致,表明注入点的数据类型为字符型


(2)判断注入点使用的闭合符号

一般情况下,输入点的闭合符号大概为英文状态下的单引号、双引号和小括号。在判断闭合符号时,遵循“先报错,再闭合”原则,“报错”是指让界面显示数据库原始报错信息。然后再使用闭合符号使sql语句形成闭合状态。

image-20240620163513956

此时出现了数据库原始报错信息,接着我们按照“先报错,再闭合”的思路进去进行下一步“闭合操作”

image-20240620163609154

可以看出,当我在末尾加上 --+ 用来注释掉sql语句后面多余的部分,还是出现了数据库原始报错信息。(这里为什么使用 --+ 我会在后面进行解释)。出现这种情况,说明此处数据的闭合符号不单单是一个单引号,必定还有其他符号和这个单引号一起组成了闭合符号。

借来继续尝试 ’ 号与其他符号组合,让前端界面出现数据原始报错信息。

image-20240619175554502

可以看到,在加上 ') 闭合符号后,页面也出现了数据库原始报错信息。

其实当我在注入点数据后加上 ')  后,在后端文件中,sql语句已经被拼接成了以下语句
SELECT * FROM `users` where id=('1')') LIMIT 0,1;

可以看出,拼接后的sql语句多了一组闭合符号,也就是 ') 这两个符号,此时sql语句已经不再是一条正确的sql查询语句,所以当后端文件在拼接完成sql语句并带入到数据库中执行时,必然会出错。并且报错信息在前端界面中展示了出来。

为了更直观的展示拼接后的sql语句在数据中执行的效果,我直接在数据库中进行演示。

image-20240620140830141

image-20240620141019249

从以上两张图是不是很直观的看出问题出在了哪?首先,sql语句中的1,就是我在前端中输入的参数,参数1后面的 ') 这组闭合符号,也是我在前端中通过不断尝试凑出的闭合符号。而后面青蓝色框框住的这一组 ') 闭合符号,其实是在后端文件中预设好的。以下是第3关的原代码

image-20240620142026738

从上图可以看出,在源代码中,确实已经有了一组 ') 闭合符号,而我在前端中又凑了一组闭合符号,而多出来的这一组闭合符号,就是让sql语句报错的根本原因。

至于为什么要在末尾加上 --+ 这几个符号,这就涉及到MySQL中的注释了。在MySQL的查询语句中,除了使用 # 号来做注释意外,是不是还可以使用 – 来做注释(注意:–符号后面有一个空格)。在末尾加上 --+ 符号,就是为了将sql语句中后面多余的内容给注释掉。下面我将在数据库中做演示。

image-20240620143546756

为什么在URL中空格要换成 + 号,大致解释可以参考该文章https://blog.csdn.net/dongheng123/article/details/130416855


(二)判断表中的列数

一般情况下,数据库中表的字段数(列数)不会很大,一般不会超过20 ,但也存在特殊情况。通常情况下从10或者20开始,一半一半往下降,很快就能确定表中的列数。

order by 10

image-20240620144810426

order by 5

image-20240620144830165

order by 3

image-20240620144851716

order by 4

image-20240620144910301

从上面四张图可以看出,我使用order by 进行排序,当我尝试到order by 3时,前端界面展示出了数据,而尝试到order by 4时,数据有没了,这就说明表中的字段只有三个。image-20240620145305050

看一下数据库,表中确实只有三个字段id,username,password


(四)判断数据回显位置

表中有既然有3个字段信息,就使用union select 1,2,3 来观察,哪些数据会在前端界面中展示出来。(注意:在判断回显位置时,要将原始查询置空。)

image-20240620150002344

从上图可以看出,2和3出现的位置就是数据回显的位置,此时我们只需要把我们要查询的内容给替换到这两个位置的任一位置就行。比如获取当前数据库和数据库角色。

image-20240620150518658

可以看出当前用户为本地root用户,当前数据库为security。


(五)爆数据

爆数据是在知道库、表、列的情况下,才能获得最终数据。也就是你得知道数据库服务器中有哪些数据库,数据库中有哪些表,表中有哪些字段(列),你才能获得明确的数据。这里就设计到MySQL数据库中有一个特殊的数据库——information_schema数据库image-20240620153024277

这个数据库中,有三个特殊的表:schemata、tables、columns,这三个表的有哪些特殊的点呢?

schemata表

该表中schema_name字段,记录了该数据库服务器中所有数据库的信息。

image-20240620153702474

tables表

该表中的table_name字段,记录了数据库中所有表的信息。

image-20240620154255224

columns表

该表中的column_name字段,记录了数据库中所有字段(列)的信息。

image-20240620154529681

(1)爆库

就是我们首先得知道这个数据库服务器中有哪些数据库,只有获取到数据库的信息,才能继续往下操作。

之前说过,information_schema数据库的schemata表的schema_name字段,记录了数据库中所有数据库的信息,所以此时我们要获取所有数据库的信息,就得在information_schema库的schemata表中来操作。

image-20240620152154748

从上图可以看出,sql语句执行后它只列出了一个数据库名 information_schema,很显然列出的数据库不全。如何让它显示全部的数据库信息,这里就要用到MySQL中的聚合函数group_concat(),该聚合函数的作用,就是把查询出的多行数据,合并成一个字符串进行输出。image-20240620155150063

以下是数据库管理软件中的截图

image-20240620155246967

结合两张图,确实只有六个数据库,且完全对应得上。

(2)爆表

在知道有哪些数据库以后,我们得根据需求,去获取指定数据库中有哪些表。之前说过,information_schema数据库的table表的table_name字段,记录了数据库中所有表的信息,所以要获取表的信息,就得在information_schema数据库的table表中进行操作。另外,还得根据上一步确定的数据库的信息,指定获取哪个数据库中的表

image-20240620160158458

(3)爆字段(列)
http://127.0.0.1/sqli-labs-master/Less-3/?id=-1%27)%20union%20select%201,2,group_concat(column_name)%20from%20information_schema.columns%20where%20table_schema%20=%20%27security%27%20and%20table_name%20=%20%27users%27--+

image-20240620160925463

从上图可以看出,表中的字段有id,username,password

(4)爆数据
http://127.0.0.1/sqli-labs-master/Less-3/?id=-1%27)%20union%20select%201,2,group_concat(id,username,password)%20from%20users--+

image-20240620161445162

只查询用户名和密码

image-20240620161623085

以上,就是手工进行联合查询注入的步骤及操作。

二、报错注入

报错注入,是在数据库原始报错信息会在前端界面展示出来的情况下使用。这可能是在系统开发的过程中,开发工程师为了调试方面,会把数据库报错信息在前端界面中打印出来。但开发工程师在开发结束后,未将这样功能给去掉,依然保留了这一方法。

示例(以sql_labs第5关为例)

(一)判断注入点

报错注入,在判断注入点,依然遵循“先报错,再闭合”的原则

image-20240625140710881

image-20240625140735284

可以看到,但执行id=1和id=2-1时,界面并没有,什么变化,既然这样,我们直接尝试让它出现报错

image-20240625141912283

使用 ’ 号进行闭合时,出现了报错,接下来尝试将后的内容注释掉,看页面是否报错

image-20240625142051245

当注释掉后面的内容后,界面恢复了正常,说明拼接的sql语句在数据库中执行了,且没有出错,证明这里的闭合符号就是 ’ 号。解下来就是使用and 1=1 和and 1=2 来判断是否存在注入点。

image-20240625142326340

image-20240625142354262

可以看到,当使用and 1=2时,界面发生了明显的变化(此时sql语句被拼接再到数据库中执行时,由于条件 and 1=2 不成立,sql没有出错,但语句查询不出结果,也就无法再界面中显示什么内容。到这里我们大概知道,当我们输入的内容经过后端文件拼接,带到数据库中执行后,如果sql语句语法正确且查询有结果,那前端界面中就会显示 “You are in…………”,如果sql语句出现了语法错误,前端界面中就会将错误信息打印出来,如果,sql语句语法没问题,但给出的条件不成立,sql语句查询不到任何内容,界面就会“空空如也”。页面发生了改变,说明存在注入点。

(二)使用报错函数爆数据

image-20240625143814442

extravtvalue为MySQL数据库中的报错函数

concat()函数的作用,是连接两个或多个字符串,生成一个新的字符串,在这里,表示吧查询到的内容生成一个新的字符创进行输出(展示)

(1)爆库
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (extractvalue(1,concat(0x7e,(select group_concat(schema_name) from information_schema.schemata))))--+

image-20240625144403152

group_concat()函数之前讲过

可以看到,确实爆出了数据库的信息,但显示的信息部完整。如果是这样,由于无法获取后面没有显示的数据库的信息,我们不知道数据库服务器中有哪些数据库,那我们岂不是无法获得我们想要的数据库的数据了?这里,我们要使用到MySQL数据库中的阶段函数。mysql 中可进行数据截断的函数有好几个,我比较喜欢使用mid()函数

mid()函数使用方法 :mid(string, start, length)

http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (extractvalue(1,concat(0x7e,(select mid(group_concat(schema_name),1,30) from information_schema.schemata))))--+

mid(group_concat(schema_name),1,30)解释

group_concat(schema_name),是将查询到的所有数据库的名称合成一个字符串进行输出

mid(group_concat(schema_name),1,30) 这一整句,就是说把查询到的这写数据合成一个字符创,在把这个字符创从第一个字符开始,往后取30个字符,进行输出。示例如下图

image-20240625150310064

如果要获取到后面为显示的内容,修改mid()函数中的第二个参数即可

http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (extractvalue(1,concat(0x7e,(select mid(group_concat(schema_name),30,30) from information_schema.schemata))))--+

image-20240625150601630

mid(group_concat(schema_name),30,30) 这一整句,就是说把查询到的这写数据合成一个字符创,在把这个字符创从第30个字符开始,往后取30个字符,进行输出。

image-20240625150745673

经过多次截取数据,是不是就可以确定数据库服务器中有哪些数据库(information_schema、challengs、dvwa、mysql、performance_schema、security)

接下来爆表,爆字段、报数据和联合查询的方法类似,只需简单修改部分参数即可

(2)爆表

tip:这里有个小点要注意,访问URL后,界面却没有任何结果,怎么查都不知道哪里有问题,如下图

http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (extractvalue(1,concat(0x7e,(select mid(group_concat(table_name),60,30) from information_schema.tables where table_schema='security'))))--+

image-20240625151828193

很多人在爆出数据库后想要继续爆表时,怎么都爆不出数据,此时要注意mid()函数的第二个参数是否在正常范围内,如果第二个参数超出了字符创长度范围,肯定爆不出数据。下图才是正解。

http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (extractvalue(1,concat(0x7e,(select mid(group_concat(table_name),1,30) from information_schema.tables where table_schema='security'))))--+

image-20240625152138993
image-20240625152259654
从第30个字符开始截取30个字符串没有数据,说明,所有数据都在1到30个字符串之间了,也就是往上第二张图中的数据。

(3)爆字段
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (extractvalue(1,concat(0x7e,(select mid(group_concat(column_name),1,30) from information_schema.columns where table_schema='security' and table_name='users'))))--+

image-20240625152902693

(4)爆数据
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (extractvalue(1,concat(0x7e,(select mid(group_concat(id,'*',username,'*',password),1,30) from users))))--+
里面的 '*'  号,只是为了看上去美观,把id,username,password之间用*号隔开了而已

image-20240625153547990

后续还有布尔盲注,时间盲注,堆叠注入、宽字节注入等常见注入方式讲解,后面会继续完善。

  • 27
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值