巡风视图函数源码学习--view.py

Posted 梁十安。

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了巡风视图函数源码学习--view.py相关的知识,希望对你有一定的参考价值。

记录一下巡风扫描器view.py这个脚本里的视图函数的学习,直接在代码里面做的注释,里面有一些print 代码是为了把数据打印出来小白我自己加的,勿怪勿怪。可能存在一些理解错误和不到位的地方,希望大佬多多指正。。

0x01:跳转到登陆页面##

第二遍看这个脚本的源码时,想到一个问题,如果你在浏览器地址栏里输入http://127.0.0.1/login可以跳转到登陆页面,如果只输入127.0.0.1,这时候并没有运行Login这个视图函数,却也能直接跳转到登陆页面,这是为什么呢?原来,在Main视图函数上面有这样两行代码:

@app.route(\'/\')
@logincheck
def Main():

只输入127.0.0.1时,相当于访问了根目录,会运行Main视图函数,而要运行Main函数,要先运行logincheck这个用于判断是否已经登陆的修饰函数,因为此时还未登陆,在logincheck函数里给我们跳转到了Login函数。

return redirect(url_for(\'Login\'))

好了,下面开始看代码(掉头发)。。

0x02:Login视图函数##

为什么先看这个呢?因为你要先登陆啊(ps:屁话,不登陆怎么进入)

@app.route(\'/login\', methods=[\'get\', \'post\'])
def Login():
    if request.method == \'GET\':
        return render_template(\'login.html\')
    else:
        # 获取前端输入的用户名密码
        account = request.form.get(\'account\')
        password = request.form.get(\'password\')
        if account == app.config.get(\'ACCOUNT\') and password == app.config.get(\'PASSWORD\'):
            session[\'login\'] = \'loginsuccess\'
            return redirect(url_for(\'Search\'))
        else:
            return redirect(url_for(\'Login\'))

调转到登陆页面后,就要输入账号密码了,前端输入的账号密码,传到login.html这个页面,并命名为account和password,是login.html里的这两行代码:

<input class="form-control" type="text" required="" placeholder="Account" name="account">

<input class="form-control" type="password" required="" placeholder="Password" name="password">

通过request.form.get获取到输入的账号密码之后,在数据库里面做验证,验证通过后,设置session[\'login\'] = \'loginsuccess\',用于后面的登陆验证,然后跳转到Search函数。

0x03:logincheck登陆验证函数##

def logincheck(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        try:
            if session.has_key(\'login\'):
                if session[\'login\'] == \'loginsuccess\':
                    return f(*args, **kwargs)
                else:
                    return redirect(url_for(\'Login\'))
            else:
                return redirect(url_for(\'Login\'))
        except Exception, e:
            print e
            return redirect(url_for(\'Error\'))

    return wrapper

如果session的login字段等于loginsuccess,则说明已经登陆,否则跳转到Login函数,让用户登陆

0x04:Search视图函数##

@app.route(\'/filter\')
@logincheck
def Search():
    return render_template(\'search.html\')

这个函数的功能就是接受前端用户输入的搜索条件,并名为为q,是Search.html里面的这行代码

<input type="text" class="form-control" placeholder="Example:  ip: 192.168.1.1; port: 22" style="color: #797979;" id="filter" name="q">

0x05:Deleteall视图函数##

@app.route(\'/deleteall\', methods=[\'post\'])
@logincheck
def Deleteall():
    # 移除仓库下的Task数据库
    Mongo.coll[\'Task\'].remove({})
    return \'success\'

Mongo是从__init.py__里面引入过来的,是数据库的连接对象,这个函数的作用是,使用Mongo,找到Task这个数据库并移除

0x06:Main视图函数##

def Main():
# 获取前端的q
q = request.args.get(\'q\', \'\')
page = int(request.args.get(\'page\', \'1\'))
plugin = Mongo.coll[\'Plugin\'].find()  # 插件列表,列出Plugin中的所有列表
plugin_type = plugin.distinct(\'type\')  # 插件类型列表
if q:  # 基于搜索条件显示结果
    # 分开多条件查询
    result = q.strip().split(\';\')
    print result
    query = querylogic(result)  # 判断搜索类型,返回字典{"port": ,"ip": , "banner": ,"hostname"}
    # 在info表里把条件代入查询sort()根据time字段排序 limit()分页
    # .find返回<class \'pymongo.cursor.Cursor\'>类型对象
    cursor = Mongo.coll[\'Info\'].find(query).sort(\'time\', -1).limit(page_size).skip((page - 1) * page_size)
    return render_template(\'main.html\', item=cursor, plugin=plugin, itemcount=cursor.count(),
                           plugin_type=plugin_type, query=q)
else:  # 自定义,无任何结果,用户手工添加
    return render_template(\'main.html\', item=[], plugin=plugin, itemcount=0, plugin_type=plugin_type)

q就是你在前端输入的搜索条件,鼠标放在“搜索”旁边的问号图标上,可以查到所支持的搜索方式,

0x07:Getplugin视图函数##

@app.route(\'/getplugin\', methods=[\'get\', \'post\'])
@logincheck
def Getplugin():
    # 获取了type risk search 是否有值
    # 没有的话,就全部查询。
    # 有的话 在Plugin表代入条件查询。然后将插件名字和信息转json格式返回。
    type = request.form.get(\'type\', \'\')
    risk = request.form.get(\'risk\', \'\')
    search = request.form.get(\'search\', \'\')
    print type,risk,search
    query = {}
    if type:
        query[\'type\'] = type
    if risk:
        query[\'level\'] = risk
    if search:
        search = unquote(search)
        query[\'name\'] = {"$regex": search, \'$options\': \'i\'}
    cursor = Mongo.coll[\'Plugin\'].find(query)
    print list(cursor)
    rsp = []
    # 把插件的name和info添加到列表中
    for i in cursor:
        result = {\'name\': i[\'name\'], \'info\': i[\'info\']}
        rsp.append(result)
    return json.dumps(rsp)

type、risk在新增任务的那个弹窗里或偶的,search还没找到是从哪里获取的

0x08:Addtask视图函数##

@app.route(\'/addtask\', methods=[\'get\', \'post\'])
@logincheck
def Addtask():
    # 先获取了页面传了的值 先默认result为fail
    # 没有plugin的话直接返回fail
    # 有的话,先判断结果集是否全选,将结果集的ip和port都加入列表,否则将当前页的ip将入列表。
    title = request.form.get(\'title\', \'\')   # 任务名称
    plugin = request.form.get(\'plugin\', \'\')	# 从插件列表里所选择的插件
    condition = unquote(request.form.get(\'condition\', \'\'))	# 所选结果的ip地址
    plan = request.form.get(\'plan\', 0)		# 执行周期
    ids = request.form.get(\'ids\', \'\')			# 所选地址的 ip:端口
    isupdate = request.form.get(\'isupdate\', \'0\')    # 是否自动更新列表
    resultcheck = request.form.get(\'resultcheck\', \'0\')  # 结果集是否全选
    print title,plugin,condition,plan,ids,isupdate,resultcheck
    result = \'fail\'
    if plugin:
        targets = []
        if resultcheck == \'true\':  # 结果集全选
            list = condition.strip().split(\';\')
            query = querylogic(list)
            cursor = Mongo.coll[\'Info\'].find(query)
            for i in cursor:
                tar = [i[\'ip\'], i[\'port\']]
                targets.append(tar)
        else:  # 当前页结果选择
            for i in ids.split(\',\'):
                tar = [i.split(\':\')[0], int(i.split(\':\')[1])]
                targets.append(tar)
        temp_result = True
        for p in plugin.split(\',\'):
            query = querylogic(condition.strip().split(\';\'))
            item = {\'status\': 0, \'title\': title, \'plugin\': p, \'condition\': condition, \'time\': datetime.now(),
                    \'target\': targets, \'plan\': int(plan), \'isupdate\': int(isupdate), \'query\': dumps(query)}
            # 插入到数据库
            insert_reuslt = Mongo.coll[\'Task\'].insert(item)
            if not insert_reuslt:
                temp_result = False
        if temp_result:
            result = \'success\'
    return result

这个函数的作用,在搜索之后,如果要根据搜索结果新增任务,就获取你新增任务时的一些参数,任务名、是否自动更新、是都全选等。

0x09:Task视图函数##

@app.route(\'/task\')
@logincheck
def Task():
    # 查询出任务信息,并展示。
    page = int(request.args.get(\'page\', \'1\'))
    cursor = Mongo.coll[\'Task\'].find().sort(\'time\', -1).limit(page_size).skip((page - 1) * page_size)
    return render_template(\'task.html\', item=cursor)

利用Mongo查询出Task数据库里面的所有任务,排序、分页并在前端展示

0x10:Recheck视图函数##

# 复测任务异步
@app.route(\'/taskrecheck\')
@logincheck
def Recheck():
    # 获取前端需要复测的任务
    tid = request.args.get(\'taskid\', \'\')
    # 找到任务,判断扫描完成后更新数据库,返回success
    task = Mongo.coll[\'Task\'].find_one({\'_id\': ObjectId(tid)})
    result = \'fail\'
    if task and task[\'plan\'] == 0 and task[\'status\'] == 2:  # 一次性任务,并且已经扫描完成
		# 更新数据库内容
        result = Mongo.coll[\'Task\'].update({\'_id\': ObjectId(tid)}, {\'$set\': {\'status\': 0}})
        if result:
            result = \'success\'
    return result

在任何一个任务框里,点击沙漏图标,可以对该任务进行复测。

0x11:TaskDetail视图函数##

# 任务详情页面
@app.route(\'/taskdetail\')
@logincheck
def TaskDetail():
    # 获取任务id
    id = request.args.get(\'taskid\', \'\') # 点击具体任务时获取到参数
    page = int(request.args.get(\'page\', \'1\'))
    # 查询指定的日期
    taskdate = request.args.get(\'taskdate\', "")
    plugin_name = \'\'
    # 从数据库里找到任务具体信息
    task_info = Mongo.coll[\'Task\'].find_one({\'_id\': ObjectId(id)})
    print id,taskdate
    if task_info:
        plugin_name = task_info[\'plugin\']
    vulcount = 0
    # 获取集合中指定字段的不重复值,并以数组的形式返回
    lastscan = Mongo.coll["Result"].distinct(\'task_date\', {\'task_id\': ObjectId(id)})
    result_list = []
    if len(lastscan) > 0:
        lastscan.sort(reverse=True)
        if taskdate:  # 根据扫描批次,查看结果
            cursor = Mongo.coll[\'Result\'].find(
                {\'task_id\': ObjectId(id), \'task_date\': datetime.strptime(taskdate, "%Y-%m-%d %H:%M:%S.%f")}).sort(
                \'time\', -1).limit(page_size).skip((page - 1) * page_size)
        else:  # 查看最新批次结果
            taskdate = lastscan[0].strftime("%Y-%m-%d %H:%M:%S.%f")
            cursor = Mongo.coll[\'Result\'].find(
                {\'task_id\': ObjectId(id), \'task_date\': lastscan[0]}).sort(\'time\', -1).limit(page_size).skip(
                (page - 1) * page_size)
        vulcount = cursor.count()
        for _ in cursor:
            result_list.append(
                {\'ip\': _[\'ip\'], \'port\': _[\'port\'], \'info\': _[\'info\'], \'vul_level\': _[\'vul_info\'][\'vul_level\'],
                 \'time\': _[\'time\']})

        # 速度优化,数据量多采取不同的方式查询
        if len(result_list) > 100:
            ip_hostname = {}
            hostname = Mongo.coll[\'Info\'].aggregate(
                [{\'$match\': {\'hostname\': {\'$ne\': None}}}, {\'$project\': {\'_id\': 0, \'ip\': 1, \'hostname\': 1}}])
            for _ in hostname:
                if \'hostname\' in hostname:
                    ip_hostname[_["ip"]] = _["hostname"]
            for _ in result_list:
                if \'ip\' in ip_hostname:
                    _[\'hostname\'] = ip_hostname[_["ip"]]
                else:
                    _[\'hostname\'] = \'\'
        else:
            for _ in result_list:
                hostname = Mongo.coll[\'Info\'].find_one({\'ip\': _[\'ip\']})
                if hostname and \'hostname\' in hostname:
                    _[\'hostname\'] = hostname[\'hostname\']
                else:
                    _[\'hostname\'] = \'\'
    return render_template(\'detail.html\', item=result_list, count=vulcount, id=id, taskdate=taskdate,
                           plugin_name=plugin_name, scanlist=lastscan)

根据你所选择的任务,获取到该任务的id,获取到该任务的数据,传到detail.html页面,并在前端展示

0x12:DeleTask视图函数##

# 删除任务异步
@app.route(\'/deletetask\', methods=[\'get\', \'post\'])
@logincheck
def DeleteTask():
    # 获取将要删除任务的id
    oid = request.form.get(\'oid\', \'\')   # 点击删除时,获取参数
    print oid
    if oid:
        # delete_one(): 删除符合条件的一条文档,返回pymongo对象
        # ObjectId将字符串id转化为ObjectId对象
        result = Mongo.coll[\'Task\'].delete_one({\'_id\': ObjectId(oid)})
        print result
        # deleted_count删除的数量
        if result.deleted_count > 0:
            # delete_many():删除Result数据库中符合条件的所有文档,就是删除这个任务的所有结果
            result = Mongo.coll[\'Result\'].delete_many({\'task_id\': ObjectId(oid)})
            if result:
                return \'success\'
    return \'fail\'

0x13:DownloadXls视图函数##

# 下载excel任务报表异步
@app.route(\'/downloadxls\', methods=[\'get\', \'post\'])
@logincheck
def DownloadXls():
    tid = request.args.get(\'taskid\', \'\')
    taskdate = request.args.get(\'taskdate\', \'\')
    print 1111,tid, 1111,taskdate
    print type(tid),len(tid), type(taskdate),len(taskdate)
    result_list = []
    # 下载具体的某一个任务
    if tid:  # 有任务id
        if taskdate:  # 从任务中拉取指定批次扫描结果
            taskdate = datetime.strptime(taskdate, "%Y-%m-%d %H:%M:%S.%f")#转换日期格式
            # 找到具体的某一条数据
            cursor = Mongo.coll[\'Result\'].find({\'task_id\': ObjectId(tid), \'task_date\': taskdate}).sort(
                \'time\', -1)
        else:  # 从任务中直接取该任务最新一次扫描结果
            # distinct获取集合中指定字段的不重复值,并以数组的形式返回
            lastscan = Mongo.coll["Result"].distinct(\'task_date\', {\'task_id\': ObjectId(tid)})
            if len(lastscan) == 0:
                cursor = []
                taskdate = datetime.now()
            else:
                lastscan.sort(reverse=True)
                taskdate = lastscan[0]
                # sort函数用来排序,1为升序,-1为降序
                cursor = Mongo.coll[\'Result\'].find({\'task_id\': ObjectId(tid), \'task_date\': taskdate}).sort(
                    \'time\', -1)
        title = Mongo.coll[\'Task\'].find_one({\'_id\': ObjectId(tid)})[\'title\']
        for _ in cursor:
            hostname = \'\'
            result = Mongo.coll[\'Info\'].find_one({\'ip\': _[\'ip\']})
            if result and \'hostname\' in result:
                hostname = result[\'hostname\']
            # 将扫描结果查询出来后加到result_list
            result_list.append(
                {\'ip\': _[\'ip\'], \'port\': _[\'port\'], \'info\': _[\'info\'], \'vul_level\': _[\'vul_info\'][\'vul_level\'],
                 \'time\': _[\'time\'], \'vul_name\': _[\'vul_info\'][\'vul_name\'], \'lastscan\': taskdate, \'title\': title,
                 \'hostname\': hostname})
        response = make_response(CreateTable(result_list, taskdate.strftime("%Y%m%d-%H%M%S")))
        if taskdate == \'\':
            response.headers["Content-Disposition"] = "attachment; filename=nodata.xls;"
        else:
            response.headers["Content-Disposition"] = "attachment; filename=" + quote(
                title.encode(\'utf-8\')) + taskdate.strftime(
                "%Y-%m-%d-%H-%M-%S") + ".xls;"
    else:  # 下载任务页面里面所有的任务
        # 找到Task数据库里面所有的数据
        tasks = Mongo.coll[\'Task\'].find({})
        t_list = []
        for t in tasks:
            name = t[\'title\']
            # distinct获取集合中指定字段的不重复值,并以数组的形式返回
            lastscan = Mongo.coll["Result"].distinct(\'task_date\', {\'task_id\': t[\'_id\']})
            if len(lastscan) == 0:
                cursor = Mongo.coll[\'Result\'].find({\'task_id\': t[\'_id\']})
                taskdate = None
            else:
                # 降序排列,recerse=False升序(默认)
                lastscan.sort(reverse=True)
                taskdate = lastscan[0]
                cursor = Mongo.coll[\'Result\'].find({\'task_id\': t[\'_id\'], \'task_date\': taskdate})
            for _ in cursor:  # 单任务详情
                hostname = Mongo.coll[\'Info\'].find_one({\'ip\': _[\'ip\']})
                if hostname:
                    _[\'hostname\'] = hostname[\'hostname\']
                else:
                    _[\'hostname\'] = None
                _[\'title\'] = name
                _[\'vul_level\'] = _[\'vul_info\'][\'vul_level\']
                _[\'vul_name\'] = _[\'vul_info\'][\'vul_name\']
                _[\'lastscan\'] = taskdate
                t_list.append(_)
        response = make_response(CreateTable(t_list, \'all_data\'))
        response.headers["Content-Disposition"] = "attachment; filename=all_data.xls;"
    response.headers["Content-Type"] = "application/x-xls"
    return response

这个视图函数有两个功能,比可以单独下载某一个任务,也可以下载全部任务

0x14:search_result_xls视图函数##

# 搜索结果报表下载接口
@app.route(\'/searchxls\', methods=[\'get\'])
@logincheck
def search_result_xls():
    # query为前端用户输入的搜索条件
    query = request.args.get(\'query\', \'\')
    print 11111,query
    if query:
        result = query.strip().split(\';\')
        filter_ = querylogic(result)
        cursor = Mongo.coll[\'Info\'].find(filter_).sort(\'time\', -1)
        title_tup = (\'IP\', \'端口号\', \'主机名\', \'服务类型\')
        xls = [title_tup, ]
        for info in cursor:
            item = (
                info.get(\'ip\'), info.get(\'port\'),
                info.get(\'hostname\'), info.get(\'server\')
            )
            xls.append(item)
        file = write_data(xls, \'search_result\')
        resp = make_response(file.getvalue())
        resp.headers["Content-Disposition"] = "attachment; filename=search_result.xls;"
        resp.headers["Content-Type"] = "application/x-xls"
        resp.headers["X-Content-Type-Options"] = "nosniff"
        return resp
    # 输入的搜索条件不受支持
    else:
        redirect(url_for(\'NotFound\'))

功能一上面的DownloadXls函数类似,只不过它下载的是搜索结果页面

0x15:Plugin视图函数##

# 插件列表页
@app.route(\'/plugin\')
@logincheck
def Plugin():
    # 获取前端页面
    page = int(request.args.get(\'page\', \'1\'))
    print 1111,page
    # 从数据库里面找到有关插件数据
    cursor = Mongo.coll[\'Plugin\'].find().limit(page_size).skip((page - 1) * page_size)
    # 在前端页面展示
    return render_template(\'plugin.html\', cursor=cursor, vultype=cursor.distinct(\'type\'), count=cursor.count())

0x16:AddPlugin视图函数##

# 新增插件异步
@app.route(\'/addplugin\', methods=[\'get\', \'post\'])
@logincheck
def AddPlugin():
    result = \'fail\'
    isupload = request.form.get(\'isupload\', \'false\')    # 是否共享
    print 99999,isupload
    # 插件格式
    methodurl = request.form.get(\'methodurl\', \'\')
    print 999999,methodurl
    file_name = \'\'
    # 上传script格式,也就是python文件
    if methodurl == \'\':
        # 获取上传的文件
        f = request.files[\'file\']
        # 获取所上传的文件名
        fname = secure_filename(f.filename)
        if fname.split(\'.\')[-1] == \'py\':
            path = file_path + fname
            # 重命名并保存
            if os.path.exists(file_path + fname):
                fname = fname.split(\'.\')[0] + \'_\' + str(datetime.now().second) + \'.py\'
                path = file_path + fname
            f.save(path)
            if os.path.exists(path):
                file_name = fname.split(\'.\')[0]
                # __import__()加载这个文件, 获取到里面的get_plugin_info()的信息。
                # 我们编写插件的格式要有get_plugin_info()这个方法,返回插件信息。
                # 然后再加入了文件名 时间。保存到数据库。
                module = __import__(file_name)
                mark_json = module.get_plugin_info()
                mark_json[\'filename\'] = file_name
                mark_json[\'add_time\'] = datetime.now()
                mark_json[\'count\'] = 0
                if \'source\' not in mark_json:
                    mark_json[\'source\'] = 0
                insert_result = Mongo.coll[\'Plugin\'].insert(mark_json)
                if insert_result:
                    result = \'success\'
                    file_name = file_name +\'.py\'
    # 上传json格式
    else:
        # 从前端获取插件信息数据,然后插入数据库,并写入json文件里
        name = request.form.get(\'name\', \'\') # 插件名字
        info = request.form.get(\'info\', \'\')  # 插件说明
        author = request.form.get(\'author\', \'\') # 插件作责
        level = request.form.get(\'level\', \'\') # 危害等级
        type = request.form.get(\'vultype\', \'\') # 插件类型
        keyword = request.form.get(\'keyword\', \'\')   # 查询条件
        pluginurl = request.form.get(\'pluginurl\', \'\')   # 插件说明链接
        methodurl = request.form.get(\'methodurl\', \'\')   # 插件内容
        pdata = request.form.get(\'pdata\', \'\')      # post数据
        analyzing = request.form.get(\'analyzing\', \'\')   # 判断类型
        analyzingdata = request.form.get(\'analyzingdata\', \'\')   # 判断依据
        tag = request.form.get(\'tag\', \'\')
        print info,level,keyword,pluginurl,methodurl,pdata,analyzing,analyzingdata,tag
        try:
            query = {\'name\': name, \'info\': info, \'level\': level, \'type\': type, \'author\': author, \'url\': pluginurl,
                     \'keyword\': keyword, \'source\': 0}
            query[\'plugin\'] = {\'method\': methodurl.split(\' \', 1)[0], \'url\': methodurl.split(\' \', 1)[1],
                               \'analyzing\': analyzing, \'analyzingdata\': analyzingdata, \'data\': pdata, \'tag\': tag}
            file_name = secure_filename(name) + \'_\' + str(datetime.now().second) + ".json"
            with open(file_path + file_name, \'wb\') as wt:
                wt.writelines(json.dumps(query))
            query.pop(\'plugin\')
            query[\'add_time\'] = datetime.now()
            query[\'count\'] = 0
            query[\'filename\'] = file_name
            # 插入到数据库
            insert_result = Mongo.coll[\'Plugin\'].insert(query)
            if insert_result:
                result = \'success\'
        except:
            pass
    # 如果同意共享插件,且上传成功则增加到巡风的插件里面
    if isupload == \'true\' and result == \'success\':
        # 读取文件
        code_tuple = open(file_path+file_name).read()
        code = \'\'
        for _ in code_tuple:
            code += _
        params = {\'code\': code}
        req = urllib2.Request(\'https://sec.ly.com/xunfeng/pluginupload\')
        req.add_header(\'Content-Type\',\'application/x-www-form-urlencoded\')
        rsp = urllib2.urlopen(req,urlencode(params))
        print \'upload result:\' + rsp.read()
    return result

0x17:DeietePlugin视图函数##

# 删除插件异步
@app.route(\'/deleteplugin\', methods=[\'get\', \'post\'])
@logincheck
def DeletePlugin():
    # 获取插件id
    oid = request.form.get(\'oid\', \'\')
    print oid
    if oid:
        # 从数据库中删除
        result = Mongo.coll[\'Plugin\'].find_one_and_delete({\'_id\': ObjectId(oid)}, remove=True)
        if not result[\'filename\'].find(\'.\') > -1:
            result[\'filename\'] = result[\'filename\'] + \'.py\'
        # 进行插件文件中移除
        if os.path.exists(file_path + result[\'filename\']):
            os.remove(file_path + result[\'filename\'])
            return \'success\'
    return \'fail\'

与删除任务类似

0x18:Analysis视图函数##

# 统计页面
@app.route(\'/analysis\')
@logincheck
def Analysis():
    # distinct获取集合中指定字段的不重复值,以集合的形式返回,就是去重
    ip = len(Mongo.coll[\'Info\'].distinct(\'ip\'))
    print \'ip总数\', ip
    # 获取数量
    record = Mongo.coll[\'Info\'].find().count()
    print \'记录总数\', record
    # 获取任务数量
    task = Mongo.coll[\'Task\'].find().count()
    print \'任务总数\', task
    # group是mongodb中自带的三种聚合函数之一
    # count:简单统计集合中符合某种条件的文档数量。
    # distinct:用于对集合中的文档针进行去重处理。
    # group:用于提供比count、distinct更丰富的统计需求,可以使用js函数控制统计逻辑
    vul = int(Mongo.coll[\'Plugin\'].group([], {}, {\'count\': 0},\'function(doc,prev){prev.count = prev.count + doc.count}\')[0][\'count\'])
    plugin = Mongo.coll[\'Plugin\'].find().count()
    print "插件总数", plugin
    vultype = Mongo.coll[\'Plugin\'].group([\'type\'], {"count":{"$ne":0}}, {\'count\': 0},\'function(doc,prev){prev.count = prev.count + doc.count}\')
    print "漏斗类型", vultype
    # sort根据date字段降序排列,limit指定读取的数据数量
    cur = Mongo.coll[\'Statistics\'].find().sort(\'date\', -1).limit(30)
    trend = []
    for i in cur:
        trend.append(
            {\'time\': i[\'date\'], \'add\': i[\'info\'][\'add\'], \'update\': i[\'info\'][\'update\'], \'delete\': i[\'info\'][\'delete\']})
    # 找到Heartbeat集合中的两个文档
    vulbeat = Mongo.coll[\'Heartbeat\'].find_one({\'name\': \'load\'})
    scanbeat = Mongo.coll[\'Heartbeat\'].find_one({\'name\': \'heartbeat\'})
    if vulbeat == None or scanbeat == None:
        taskpercent = 0
        taskalive = False
        scanalive = False
    else:
        taskpercent = vulbeat[\'value\'] * 100
        taskalive = (datetime.now() - vulbeat[\'up_time\']).seconds
        scanalive = (datetime.now() - scanbeat[\'up_time\']).seconds
        taskalive = True if taskalive < 120 else False
        scanalive = True if scanalive < 120 else False
    server_type = Mongo.coll[\'Info\'].aggregate(
        [{\'$group\': {\'_id\': \'$server\', \'count\': {\'$sum\': 1}}}, {\'$sort\': {\'count\': -1}}])
    web_type = Mongo.coll[\'Info\'].aggregate([{\'$match\': {\'server\': \'web\'}}, {\'$unwind\': \'$webinfo.tag\'},
                                             {\'$group\': {\'_id\': \'$webinfo.tag\', \'count\': {\'$sum\': 1}}},
                                             {\'$sort\': {\'count\': -1}}])
    return render_template(\'analysis.html\', ip=ip, record=record, task=task, vul=vul, plugin=plugin, vultype=vultype,
                           trend=sorted(trend, key=lambda x: x[\'time\']), taskpercent=taskpercent, taskalive=taskalive,
                           scanalive=scanalive, server_type=server_type, web_type=web_type)	

这个方法就是将数据库中的值查询出来然后显示.

0x19:Config视图函数##

# 配置页面
# 判断是爬虫引擎还是扫描引擎,然后分别查询出数据
@app.route(\'/config\')
@logincheck
def Config():
    val = []
    table = request.args.get(\'config\', \'\')
    if table in ("vulscan", "nascan"):
        dict = Mongo.coll[\'Config\'].find_one({\'type\': table})
        if dict and \'config\' in dict:
            dict = dict[\'config\']
            for _ in dict:
                if _.find(\'_\') > 0:
                    item_type = "list"
                else:
                    item_type = "word"
                val.append({"show": item_type, "type": _, "info": dict[_]["info"], "help": dict[_]["help"],
                            "value": dict[_]["value"]})
    val = sorted(val, key=lambda x: x["show"], reverse=True)
    # 传到前端展示
    return render_template(\'config.html\', values=val)

0x20:UpdateConfig视图函数##

# 配置更新异步
@app.route(\'/updateconfig\', methods=[\'get\', \'post\'])
@logincheck
def UpdateConfig():
    rsp = \'fail\'
    name = request.form.get(\'name\', \'default\')
    value = request.form.get(\'value\', \'\')
    conftype = request.form.get(\'conftype\', \'\')
    if name and value and conftype:
        # 判断所要更新的配置
        # 端口列表或MAsscan配置
        if name == \'Masscan\' or name == \'Port_list\':
            origin_value = Mongo.coll[\'Config\'].find_one({\'type\': \'nascan\'})["config"][name]["value"]
            value = origin_value.split(\'|\')[0] + \'|\' + value
        # 判断是否启用存活探测ICMP
        elif name == \'Port_list_Flag\':
            name = \'Port_list\'
            origin_value = Mongo.coll[\'Config\'].find_one({\'type\': \'nascan\'})["config"][\'Port_list\']["value"]
            value = value + \'|\' + origin_value.split(\'|\')[1]
        # 判断是否启用MASSCAN
        elif name == \'Masscan_Flag\':
            name = \'Masscan\'
            path = Mongo.coll[\'Config\'].find_one({\'type\': \'nascan\'})["config"]["Masscan"]["value"]
            if len(path.split(\'|\')) == 3:
                path = path.split(\'|\')[1] + "|" + path.split(\'|\')[2]
            else:
                path = path.split(\'|\')[1]
            if value == \'1\':
                value = \'1|\' + path
            else:
                value = \'0|\' + path
        result = Mongo.coll[\'Config\'].update({"type": conftype}, {\'$set\': {\'config.\' + name + \'.value\': value}})
        if result:
            rsp = \'success\'
    return rsp

根据name来判断是哪个配置,就从数据库去取对应的值,然后把提交过来的value加上去更新。

0x21:PullUpdate视图函数##

0x22:checkupdate视图函数##

0x23:installplugin视图函数##

均为更新插件的,不细分析。

在https://sec.ly.com/xunfeng/getlist 查询出最新插件,然后与数据库比较。

查看是否本地有安装。

https://sec.ly.com/xunfeng/getplugin?name= 在这里实现下载

参考文章:一个还需要努力的人:巡风源码解读与分析

以上是关于巡风视图函数源码学习--view.py的主要内容,如果未能解决你的问题,请参考以下文章

巡风扫描器工作流程

Django视图学习

django学习笔记1

Django编写RESTful API:基于类的视图

url分发器

如何让片段中的多个视图调用片段类中声明的相同 onClick 函数?