Django 很适合用来写安全小工具,因为很多安全工具都是 Python 编写的,所以 Django 集成的话就可以少走很多弯路,又因为 Django 的官方文档比较全,目前 Django 最新的版本都已经到 Django3 了,很适合新手上手使用。文中的项目暂时还没有开源,这个只是国光初次尝试写的第一个版本,代码很多地方都需要重构,功能上也有很多待完善,目前写这篇文章只是想下一下思路,证明自己可以写扫描器,因为之前立过写扫描器的 Flag ,国光建议大家也可以尝试用 Django 之类的 Web 框架整合自己的小工具。

相关技术

  • Python 3.8.0

Python 3.8 支持许多高级特性,在 Web 漏扫这一块 Python 编写也十分灵活。

  • Django 3

使用了最新的 Django 版本,Django 是 Python 语言中文档比较全的一个 Web 框架,因为文档比较全,适合新手上手,所以这里选了 Django

  • MySQL

经典的关系型数据库,实际上因为 Django 可以完美的支持各种数据库,一般我们不需要对数据库进行直接操作,所以换其他的数据库也是可以的,因为对 MySQL 比较熟悉,就选择了 MySQL 了。

  • H+ 4.1

H+ 是一个功能全面的收费框架,基于 Bootstrap3.3.6 码云上有人开源出来了,因为 Bootstrap 容易上手,所以国光这里就白嫖了这个框架,然后在此基础上进行了深度修改

  • ECharts

ECharts 是百度开源的一个数据可视化的 JS 图表插件,之前国光我使用 Django 重写我的 Hexo 博客的时候,发现我那个主题就是使用的 ECharts 图表插件,所以这次写 Web 漏扫的时候也就轻车熟路的直接使用了,ECharts 很强大,对于我们这种前端一般般的开发者来说,简直是福利。

登录界面

中规中矩的界面,这个没啥好说的,登录界面的话 也不需要花里胡哨的,毕竟谁会没事儿天天盯着看。

漏洞检测

漏洞检测实际上国光我一开始是不打算写的,因为我对漏洞检测的算法没有信心,另外国光也看了网上那些看上去 NB 哄哄的 Web 漏扫,发现漏洞检测的效果也就是 just soso。但是一个扫描器还是要有漏洞检测功能的,所以国光在写这个功能前把 AWVS 13 APi 全部亲自测试了一遍,然后把长亭科技的 xray 的官方文档也过了一遍。

所以这个漏洞检测功能最终就是使用 AWVS 13 爬虫来爬取目标资产信息,然后将获取到的信息转发给 xray 进行漏洞检测,直接用轮子效率真的高,新版本的 xray 支持 webhook 方便获取到漏洞信息,Demo 界面如下:

Django 写的对应的 xray webhook 接口,下面是这个接口简单的实现代码:

import json
from django.shortcuts import render
from django.views.generic.base import View
from django.views.decorators.csrf import csrf_exempt


class WebHook(View):
    @csrf_exempt
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

    def post(self, request):
        vul_data = json.loads(request.body)
        if 'detail' in str(request.body):
            print('漏洞插件:', vul_data['plugin'])
            print('漏洞位置:', vul_data['target']['url'])
            print('漏洞分类:', vul_data['vuln_class'])

        return render(request, 'test.html', {
        })

因为 Django 安全机制问题,xray post 提交请求到 Django 必须填写 CSRF Token才可以,解决方法就是手动关掉这个类的 CSRF 检测@csrf_exempt

点击资产名称的跳转到漏洞细节:

点击对应的漏洞 URL 会展开详细的漏洞细节:

总的来说功能上基本上可以满足渗透测试人员的需求了。

端口扫描

端口扫描国光我的扫描思路是先使用 masscan 进行网段粗略扫描,然后再用 nmap 进行详细扫描。比较舒服的事情是 Python 里面都有不错的相应的模块可以直接使用,这样代码写起来就更加得心应手了。

python-masscan 的扫描效果图:

IP 归属地查询使用的接口如下:

ip_api_url = f'http://freeapi.ipip.net/{ip_addr}'
r = requests.get(url=ip_api_url)
addr_list = literal_eval(r.text)
addr = ' '.join(addr_list[:3])

接着点击网段后的跳转页面如下图所示:

在这里可以继续发起扫描,这里就是调用的 nmap 扫描器,上方图标插件分别展示了端口和服务类别的饼状图,资产比较多的资产也会在右上侧列出来,总体效果还是可以的。

指纹识别

指纹识别主要使用了 wappalyzer 做基本的指纹探测,这可以让结果看上去不会那么尴尬,毕竟不是每个资产都可以那么容易识别到 CMS 的;当然传统的指纹识别功能也集成了,这里使用的指纹库是:TideFinger,虽然这个指纹库比较老了,但是可以自己在这个基础上扩充,基本上也可以满足基本的指纹探测功能的,国光我整理出的JSON 格式链接地址

指纹识别详情展示图:

当然一些古老的 CMS 也是可以识别出来的,这个就归功于 TideFinger 的功劳了:

不过这些 CMS 的名称和描述是需要自己建库的,然后对应的数据库 model 注册到 Django Admin 中:

@admin.register(Component)
class ComponentAdmin(admin.ModelAdmin):
    list_display = ('name', 'desc', 'category', 'icon_data')
    search_fields = ('name', 'desc')
    readonly_fields = ('icon_data',)
    list_per_page = 20

    fieldsets = (
        ('编辑组件', {
            'fields': ('name', 'desc', 'category', 'icon', 'icon_data')
        }),
    )

    formfield_overrides = {
        models.CharField: {'widget': TextInput(attrs={'size': '59'})},
    }

其中 icon 是图片,这里需要我们在对应的 Model 里面编写好对应的 HTML:

class Component(models.Model):
    name = models.CharField(max_length=200, verbose_name='组件名称')
    desc = models.CharField(max_length=200, verbose_name='组件描述')
    icon = models.FileField(upload_to='icons/', verbose_name='组件logo', max_length=100)
    category = models.CharField(max_length=100, verbose_name='组件类别', blank=True)

    def icon_data(self):
        return format_html(
            '<img src="/media/{}" width="50px" height="50px" />',
            self.icon,
        )

    icon_data.short_description = 'Logo'

实际上在 Django Admin中添加编辑起来的话效率也比较高,国光这里使用的是目前比较流行的 Django Admin:Simple Ui ,下图是具体的效果:

这里国光我打包了对应的数据库以及 icon 素材,方便大家直接使用:CMS组件描述-蓝奏云

域名探测

域名探测功能国光我发现比较流行的子域名探测功能 one for all 用的也是很多 API 接口,于是国光我也打算使用第三方服务来获取子域名,这样获取的速度会很快。

为什么不用传统的暴力破解子域名呢?因为现在很多 SRC 的子域名都已经到 3 级甚至 4 级了,这个时候用暴力破解子域名的话 效率是及其低下的 得等到天荒地老。接口的话 国光我筛选了 6 个还算不错和稳定接口,基本上覆盖面是有的了:

因为这些子域名是存入数据库的,所以也就顺便增加了域名监控功能,每次扫描可以统计出新增的域名数量。域名探测所使用的 6 个接口分别如下,大家也可以直接拿去使用,做好对应的数据提取就可以了:

# 爱站
https://baidurank.aizhan.com/baidu/{domain}/

# 百度云观测
http://ce.baidu.com/index/getRelatedSites?site_address={domain}

# hackertarget
https://api.hackertarget.com/hostsearch/?q={domain}

# IP138
https://site.ip138.com/{domain}/domain.htm

# crt.sh SSL 证书反查
https://crt.sh/?q=%25.{domain}

# 千寻
url = 'https://www.dnsscan.cn/dns.html'
datas = {"ecmsfrom": '8.8.8.8', "show": 'none', "keywords": domain}

域名探测细节效果图:

域名访问超时直接丢弃结果的,然后再获取网页标题,这个在实际的信息收集中比较实用的,一些 404 403 的资产可以跳过,减少无意义的浪费时间。

目录扫描

目录扫描国光这里直接强行把 Dirsearch 给集成到 Django 中了,附上罗永浩那句话:又不是不能用

为什么是强行呢,因为代码实在不优雅 等后面正式开源的话 这里得好好重写一下。又因为前端比较菜,所以 Web 目录扫描这一块和之前的模板外观看上去是差不多的:

点击目录扫描细节可以看到详细的目录扫描结果:

这里没有啥亮点,Dirsearch 本身就很强大,后期打算集成 top 1000 字典,每次目录命中的话,计数 + 1,然后把高命中的字典保存下载下来,这样实战中应该会更实用。

小工具

目前小工具集成的功能如下:IP 提取、文本对比、批量获取网页标题、SSH批量爆破验证 这些都是比较常用的小功能,写起来也比较简单:

这些小工具实际上就是一些小脚本的整合,建议大家也尝试使用 Django 去集成一些,这样平时使用的时候就会更加方便了,不需要翻来覆去地导出找脚本了。

SSH 批量爆破验证

众所周知,SSH 可能开启公私钥登录,这个时候如果直接丢到类似 超级弱口令爆破工具 理论批量爆破的话 就会很浪费时间。所以最好爆破之前批量检测一下是否支持密码爆破。下面是简单的 Python Demo:

import os
import pexpect
import progressbar

with open('22.txt') as f:
    lines = f.readlines()

attack_ips = []
p = progressbar.ProgressBar()
for line in p(lines):
    ssh = pexpect.spawn('ssh root@{ip}'.format(ip=line))
    try:
        flag = ssh.expect(['continue', 'password:'], timeout=3)
        if str(flag).isnumeric():
            attack_ips.append(line)
    except pexpect.EOF:
        ssh.close()
    except pexpect.TIMEOUT:
        ssh.close()

for ip in attack_ips:
    with open('ssh.txt','a') as f:
        f.write(ip)

类似的还可以写 MySQL 批量爆破验证,因为 MySQL 不一定都是开启外连的,所以爆破前的检测是很有必要的,这样可以在后面的爆破节省大量的时间。

总结

总的来说使用 Django 写一个漏扫虽然难度不高(用了轮子了,让我写一个 xray 这种强大的扫描器 还差的很远呢…),但是要做的细致好用的话难度还是很高的。这里给自己挖个坑,待以后有精力了重写这个扫描器

  • Redis 缓存加速
  • WebSocket 通信
  • Django 配合 React、Vue 等技术实现前后端分离
  • 代码变量、数据库结构优化
  • 实用功能完善

总之不论是开发还是安全都有很长的路要走,路漫漫其修远兮,吾将上下而求索,共勉 !

这个坑看来是填不上了,这个扫描器是 2020 年疫情在家写的,毕设立的 flag 写扫描器,正好去年疫情哪也去不了,所以最终才完成了这个项目,工作之后呢,各种项目进度都很赶 呜呜呜呜,这个还不是最糟糕的,最糟糕的是今年主板短路烧坏了我的 1TB 硬盘,这个扫描器源码我自己都没有备份过,如果要写的话,真的是从 0 开始重构了,虽然「成功不可以复制,但可以重演」,但也希望自己未来工作之余真的可以抽出时间来,给我重写这个扫描器的机会(不知不觉有立了个 flag)。

支持一下

本文可能实际上也没有啥技术含量,但是写起来还是比较浪费时间的,在这个喧嚣浮躁的时代,个人博客越来越没有人看了,写博客感觉一直是用爱发电的状态。如果你恰巧财力雄厚,感觉本文对你有所帮助的话,可以考虑打赏一下本文,用以维持高昂的服务器运营费用(域名费用、服务器费用、CDN费用等)

微信
支付宝

没想到文章加入打赏列表没几天 就有热心网友打赏了 于是国光我用 Bootstrap 重写了一个页面用以感谢支持我的朋友,详情请看 打赏列表 | 国光