打造一款适合自己的扫描工具

手把手带你打造一款适合自己的扫描工具

0x01 简言

作为一名安全从业人员,在平时的工作中,少不了进行一系列漏洞的挖掘验证以及修复。那么除了很多业务逻辑漏洞需要人为的识别和测试以外,一些常规类的漏洞挖掘是可以依据自动化扫描工具去实现的。当然有很多非常成熟且强大功能的安全扫描工具。但本篇文章主要以python编写一款轻便型的扫描脚本工具。
代码地址:https://github.com/get0shell/AScan.git

0x02 目标

1)轻量级且便携性高,python脚本支持随时执行
2)满足子域名猜解、目录爆破、漏洞扫描以及弱口令爆破等功能
3)字典支持根据不同需求进行增减调整优化
4)漏洞检测规则依托json文件,可依据poc复现进行编写

0x03 开发实战

该主动扫描器主要包括子域名扫描、目录扫描、漏洞扫描以及弱口令扫描等四大模块。

3.1 子域名扫描模块

子域名扫描,即对主域名的二级域名存活进行请求判断。具体实现逻辑如下:

1)打印需要输入主域名格式,并进行接受输入的域名内容
2)将接收到的主域名传入具体扫描的方法中
3)从子域名字典中便利二级域名的关键词,并和主域名进行拼接
4)对拼接完成的域名进行get请求,状态码为200则存在并进行打印输出
5)利用多线程进行子域名的扫描(线程数量默认为5

具体代码如下:

# @Author : alan
# @File : subScan.py

import requests
import threading

def run(e,s):
    header = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0",
    }
    s.acquire()
    with open('./plug/sub.txt', 'rt', encoding='utf-8') as f:
        m = f.readlines()
        for i in m:
            url = 'http://' + str(i.strip('\n')) + '.' + str(e)

            try:
                response = requests.get(url, headers=header)

                if response.status_code == 200:
                    print('[-]存在域名:' + str(i.strip('\n')) + '.' + str(e))
                else:
                    pass
            except requests.exceptions.ConnectionError:
                requests.status_codes = 'xxx'

def subScan():
    print('======================================================')
    print('域名格式:xxx.com')
    print('======================================================')
    domain = input('请输入域名:').strip()
    mutex = threading.Lock()
    for i in range(5):
        t = threading.Thread(target=run,args=(domain,mutex))
        t.start()

3.2 目录扫描模块

目录扫描,即对应用系统的url目录存活进行请求判断。目录扫描支持多域名目录扫描和单域名目录扫描,因此代码逻辑进行分开分析,具体如下:

1、单域名目录扫描
1)打印需要输出扫描模式参数规格,以及域名提交格式
2)接收到扫描模式为1时调用单个域名扫描方法
3)提示输入需要扫描的url,并获取传入的url
4)从目录字典中遍历目录关键词,并和传入的url进行拼接
5)将拼接完成的url进行get请求,状态码为200则存在并进行打印输出

2、多域名目录扫描
1)打印需要输出扫描模式参数规格,以及域名提交格式
2)接收到扫描模式为2时调用多个域名扫描方法
3)提示输入需要扫描的url目录,并获取传入的目录文件
4)便利目录文件中的url,且从目录字典中遍历目录关键词,并和便利出的url进行拼接
5)将拼接完成的url进行get请求,状态码为200则存在并进行打印输出

具体代码如下:

# @Author : alan
# @File : dirScan.py

import requests
def scan():
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0"
    }
    url = input('请输入url:').strip()
    with open('./plug/dir.txt', 'rt', encoding='utf-8') as f:
        m = f.readlines()

        for i in m:
            Url = url + i
            response = requests.get(Url, headers=headers)
            if response.status_code == 200:
                print('[+]存在目录:' + i)
            else:
                pass

def scan1():
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0"
    }
    pwd = input('请输入文件路径:').strip()
    with open(pwd, 'rt', encoding='utf-8') as f:
        m = f.readlines()
        for i in m:

            with open('./plug/dir.txt', 'rt', encoding='utf-8') as f:
                j = f.readlines()
                for h in j:
                    Url = str(i.strip('\n')) + str(h)
                    response = requests.get(Url, headers=headers)
                    if response.status_code == 200:
                        print('[+]存在目录:' + Url)
                    else:
                        pass

def dirScan():
    print('======================================================')
    print('参数规格:')
    print('1、单个域名扫描')
    print('2、多域名文件扫描')
    print('域名格式:http://www.xxx.com')
    print('======================================================')
    t = input('请输入扫描模式:').strip()
    if t == '1':
        scan()
    elif t == '2':
        scan1()
    else:
        print('参数错误!')

3.3 漏洞扫描模块

漏洞扫描,即对应用系统中存在的漏洞进行请求判断。该模块中扫描逻辑比较简单,主要是从poc文件中获取请求payload进行请求,然后通过响应体中关键内容进行判断是否漏洞存在。这块可以根据自己测试扫描的重点进行对应poc文件的编写,程序以json文件为固定文件格式。具体poc的json文件格式如下:

{
  "name": "druid 监控页未授权访问",
  "payload": "/druid/index.html",
  "res": "(\\S)Druid Stat Index(\\S){2}title(\\S)"
}

具体代码逻辑如下:

1)打印需要输入url格式,并接收输入的url内容
2)将接收到的url传入具体扫描的方法中
3)从poc目录下便利出所有的poc文件,并对该文件中的内容进行读取
4)将读取到的payload和url进行拼接,
5)对拼接完成的url进行get请求,利用正在匹配响应内容中是否存在poc文件中的特征内容
6)如果匹配成功则打印存在该漏洞,以及存在的url+payload
7)利用多线程实现漏洞的扫描

具体代码如下:

# @Author : alan
# @File : vulScan.py

import json
import os
import threading

import requests
import re

def run(u, i):
    header = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0",
    }
    i.acquire()
    pathDir = os.listdir('./plug/vul/')
    for allDir in pathDir:
        p = os.path.join('./plug/vul/' + allDir)
        try:
            with open(p, 'rt', encoding='utf-8') as f:
                json_data = json.load(f)
                url = u + json_data['payload']
                response = requests.get(url, headers=header)
                i = re.search(json_data['res'], response.text)
                if i:
                    print('[+] 存在漏洞:' + json_data['name'])
                    print('[+]'+url)
        except Exception:
            print('请求异常,检查url是否正确')

def vulScan():
    print('url格式:http://www.xxx.com/ OR http://www.xxx.com/?id=')
    domain = input('请输入域名:').strip()
    mutex = threading.Lock()
    for i in range(2):
        t = threading.Thread(target=run, args=(domain, mutex))
        t.start()

3.4 弱口令扫描模块

弱口令扫描,即对系统不同服务的账户密码进行猜解判断。该模块包括SSH弱口令、FTP弱口令、以及MYSQL弱口令等三大模块。

3.4.1 SSH弱口令扫描模块

SSH弱口令扫描模块主要是针对ssh服务的账户和密码进行猜解,这边主要调用paramiko库进行实现,因此需要提前安装该库。具体代码逻辑如下:

1)读取用户名和密码字典文件中的用户名和字典
2)提示输入ip以及端口,并获取输入的内容
3)将输入的ip和端口传入对应的连接方法
4)利用paramiko.SSHClient()进行连接测试
5)连接成功则打印对应用户名和密码

具体代码如下:

import paramiko
import threading

def sshScan(t, i, o, u, p):
    try:
        t.acquire()
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(hostname=i, port=o, username=str(u), password=str(p), timeout=10)
        print('[+]SSH连接成功,用户:%s,密码:%s' % (u, p))
        client.close()
    except:
        t.release()

def ssh():
    with open('./plug/passdict/username.txt', 'r')as f:
        user = f.readlines()
    with open('./plug/passdict/password.txt', 'r')as f:
        passw = f.readlines()
    ip = input("请输入IP:").strip()
    port = input("请输入端口:").strip()
    s = threading.Semaphore(10)
    for i in user:
        username = i.strip()
        for j in passw:
            password = j.strip()
            t = threading.Thread(target=sshScan, args=(s, ip, port, username, password))
            t.start()

3.4.2 FTP弱口令扫描模块

FTP弱口令扫描模块主要针对ftp服务的用户名和密码进行猜解,主要利用ftplib库进行连接测试,这块需要设计有账户密码登录以及无用户密码登录,具体代码逻辑如下:

1、无用户密码登录
1)提示输入ip以及端口,并获取输入的内容
2)将输入的ip和端口传入对应的连接方法
3)利用ftplib.FTP()进行连接测试
4)连接成功则打印成功信息

具体代码如下:

import ftplib
def ftp_anyScan(t, i, o):
    try:
        t.acquire()
        ftp = ftplib.FTP()
        ftp.connect(i, o, 2)
        ftp.login()
        ftp.quit()
        print('[+]FTP连接成功,无用户名密码')
    except:
        t.release()

def ftp_any():
    ip = input("请输入IP:").strip()
    port = input("请输入端口:").strip()
    s = threading.Semaphore(10)
    t = threading.Thread(target=ftp_anyScan, args=(s, ip, port))
    t.start()
1、用户密码登录
1)读取用户名和密码字典文件中的用户名和字典
2)提示输入ip以及端口,并获取输入的内容
3)将输入的ip和端口传入对应的连接方法
4)利用ftplib.FTP()进行连接测试
5)连接成功则打印对应用户名和密码

具体代码如下:

import ftplib
def ftpScan(t, i, o, u, p):
    try:
        t.acquire()
        ftp = ftplib.FTP()
        ftp.connect(i, o, 2)
        ftp.login(u, p)
        ftp.quit()
        print('[+]FTP连接成功,用户:%s,密码:%s' % (u, p))
    except:
        t.release()

def ftp():
    with open('./plug/passdict/username.txt', 'r')as f:
        user = f.readlines()
    with open('./plug/passdict/password.txt', 'r')as f:
        passw = f.readlines()
    ip = input("请输入IP:").strip()
    port = input("请输入端口:").strip()
    s = threading.Semaphore(10)
    for i in user:
        username = i.strip()
        for j in passw:
            password = j.strip()
            t = threading.Thread(target=ftpScan, args=(s, ip, port, username, password))
            t.start()

3.4.3 MYSQL弱口令扫描模块

MYSQL弱口令扫描模块主要是针对mysql服务的账户和密码进行猜解,这边主要调用pymysql库进行实现,因此需要提前安装该库。具体代码逻辑如下:

1)读取用户名和密码字典文件中的用户名和字典
2)提示输入ip以及端口,并获取输入的内容
3)将输入的ip和端口传入对应的连接方法
4)利用pymysql.connect()进行连接测试
5)连接成功则打印对应用户名和密码

具体代码如下:

import pymysql
def mysqlScan(t, i, u, p):
    try:
        t.acquire()
        db = pymysql.connect(host=i, user=u, password=p)
        print('[+]MYSQL连接成功,用户:%s,密码:%s' % (u, p))
        db.close()
    except:
        t.release()

def mysql():
    with open('./plug/passdict/username.txt', 'r')as f:
        user = f.readlines()
    with open('./plug/passdict/password.txt', 'r')as f:
        passw = f.readlines()
    ip = input("请输入IP:").strip()
    s = threading.Semaphore(10)
    for i in user:
        username = i.strip()
        for j in passw:
            password = j.strip()
            t = threading.Thread(target=mysqlScan, args=(s, ip, username, password))
            t.start()

3.4.4弱口令扫描模块整合

在扫描工具调用的过程中,需要依据当前的需求进行不同模块的扫描代码,因此需要一个模块进行模块选择,将支持的功能模块打印输出,并获取用户输入的参数选择调用对应的扫描方法。具体代码如下:

def passScan():
    print('''
    支持弱口令扫描类型:
    1、SSH弱口令扫描
    2、FTP弱口令扫描
    3、SMB弱口令扫描
    4、MYSQL弱口令扫描
    ''')
    m = input("请选择扫描的类型:").strip()
    if m == '1':
        ssh()
    elif m == '2':
        ftp()
        ftp_any()
    elif m == '3':
        smb()
    elif m == '4':
        mysql()
    else:
        print('请输入正确的参数')

3.5 扫描模块整合

通过上述一系列代码的编写,成功完成了子域名扫描、目录扫描、漏洞扫描以及弱口令四大模块的扫描逻辑,但是在程序运行时需要实现统一运行,并依据不同的需求选择不同的扫描模块进行执行。因此再编写一个统一的整合模块,用来统一调用和选择不同扫描功能模块。具体代码如下:

# @Author : alan
# @File : Ascan.py

from scan import subScan,dirScan,vulScan
from scan import passScan

def Ascan():
    print('============================================欢迎使用AScan==============================================')
    print('''
            =                 ==                ==                   =                ==          =
           =  =           =       =          =        =             =  =              =  =        =
          =    =            ==             =                       =    =             =    =      =
         = =  = =                ==        =                      = =  = =            =      =    =
        =        =        =       =          =        =          =        =           =        =  =
       =          =           ==                ==              =          =          =          ==
    ''')
    print('=====================================================================================================')
    print('''
    扫描模块:
    1、子域名扫描
    2、目录扫描
    3、漏洞扫描
    4、弱口令扫描
    请选择对应的序号进行扫描
    ''')
    t = input('请输入对应扫描模式序号:').strip()
    if t == '1':
        subScan.subScan()
    elif t == '2':
        dirScan.dirScan()
    elif t == '3':
        vulScan.vulScan()
    elif t == '4':
        passScan.passScan()
    else:
        print('参数错误!')

if __name__ == '__main__':
    Ascan()

0x04 结语

那么通过以上代码的编写,成功完成了一个基础的主动漏洞扫描工具。这样的好处就是扩展性高,小巧便携,可以根据自己的不同需求随时进行调整,同时还可以实现自动化的测试。当然主动扫描工具相对被动扫描工具来说还是有很大的弊端,有些漏洞可能因为没有参数之类的无法识别到。因此在后面也会再进行被动扫描器的编写以及利用web界面进行展示功能的优化。

  • 发表于 2022-07-18 09:41:22
  • 阅读 ( 10137 )
  • 分类:安全工具

0 条评论

请先 登录 后评论
阿蓝
阿蓝

7 篇文章

站长统计