• 学习如何用python3编写一个命令行脚本,通过分析brutespray源码


    为什么选取brutespray这个项目

    • star数超过1k——有使用量有口碑。
    • 单文件,代码行数500以内——不至于过于复杂,便于分析。
      顺便介绍一下,brutespray是一个爆破用的安全工具,nmap扫描日志为输入,medusa实施实际爆破过程。

    先找到入口

    brutespray.py的入口很容易找到,在336行的main。脚本的第一步接收入参,调用了parse_args()函数,存入args变量。

    >>>
    if __name__ == "__main__":
        args = parse_args()
    >>>
    

    接下判断参数args.quiet是否存在,若不存在就打印ascii art的banner。这里是纯好玩 ,不影响主逻辑。ascii art确实很有意思,linux上有不少这样的‘玩具‘工具。

        if args.quiet == False:
            print(banner)
        else:
            print(quiet_banner)
    

    接下来的代码多数是判断某参数是否存在,这里关注一下384行到388行,生成临时目录。

    1. 写脚本的时候,可以多多运用tmppath、tmpfile,没必要创建永久文件的,坚决使用临时的。
    2. 使用exit()函数退出时,要提供退出值。好多人在写脚本时不提供错误信息就直接退出。这个脚本非常值得学习的一点,在使用exit()函数时都提供了exit code。这样方便使用者使用$?变量获取此脚本运行情况。
        try:
            tmppath = tempfile.mkdtemp(prefix="brutespray-tmp")
        except:
            sys.stderr.write("
    Error while creating brutespray temp directory.")
            exit(4)
    

    再看393行到395行,判断当前环境变量是否存在medusa命令,可以理解为判断某工具是否已安装。command是一个shell内置变量,用于运行命令,所运行的命令不包括shell自定义函数,包括shell内置变量,也包括从PATH变量搜索到的命令。-v参数,表示打印所调用命令的简要描述,所以当命令找到则返回0,未找到则返回非0。

    日后编写脚本判断工具是否安装时,就可以使用此方法。

        if os.system("command -v medusa > /dev/null") != 0:
            sys.stderr.write("Command medusa not found. Please install medusa before using brutespray")
            exit(3)
    

    408行到421行。这里有一个比较奇怪得写法,仔细分析一下还比较清楚,但是这种写法不是很易读。in_format变量赋值这一行,将输入文件的类型存储在in_format变量。接下来实际定义了一个字典,字典中key-value对应文件类型 - 函数,并且使用[]确定所需要的函数,然后()调用函数。

        if os.path.isfile(args.file):        
            try:
                t = threading.Thread(target=loading)
                t.start()
                in_format = getInput(args.file)
                {
                    "gnmap": make_dic_gnmap,
                    "xml":   make_dic_xml,
                    "json":  make_dic_json
                }[in_format]()
            except:
                print("
    Format failed!
    ")
                loading = True
                sys.exit(0)
    

    423行到426行,调用了interactive()和animate()函数,后面再分析具体函数内容。

            if args.interactive is True:
                interactive()
    
            animate()
    

    433行到444行,开始进行爆破并将结果写入文件。具体功能涉及到services变量保存的内容,看起来应该是个全局变量。

        to_scan = args.service.split(',')
        for service in services:
            if service in to_scan or to_scan == ['all']:
                for port in services[service]:
                    fname = tmppath + '/' +service + '-' + port
                    iplist = services[service][port]
                    f = open(fname, 'w+')
                    for ip in iplist:
                        f.write(ip + '
    ')
                    f.close()
                    brute_process = Process(target=brute, args=(service,port,fname,args.output))
                    brute_process.start()
    

    命令行参数argparse

    argparse属于python3标准库,写脚本工具必备。

    brutespray脚本中,parse_args()函数主要就是在处理命令行接口。每个参数提供了长短两种形式,以及帮助信息,是否为必须参数,是否有默认值等。

    官方文档进行学习吧,再结合代码去看。The importance of studying offical documents cannot be overemphasized.

    爆破

    brute()函数,在根据输入来构造命令。爆破使用的工具为medusa。此工具支持很多种服务的爆破。

    交互模式

    interactive()函数,交互模式参考这里来写。

    动画

    animate()函数,动画。像有些命令行工具,有加载进度之类的,转圈什么的,参考这里。

    美化

    ascii art banner以及添加颜色。

  • 相关阅读:
    background-size ie8及以下不兼容的解决方案
    前端
    JavaScript ES(6-11)
    前端工程化
    前端安全漏洞与防范
    Vue源码思维导图
    项目流程总结
    typescript版数据结构与算法库
    tsconfig.json各项配置注解
    Sql server动态加载存储过程--分页
  • 原文地址:https://www.cnblogs.com/jamesnpu/p/13599178.html
Copyright © 2020-2023  润新知