打造自己的渗透测试框架 — 溯光:扩展篇

BB两句

  • 开发插件建议使用 Intellij IDEA IDE,需要安装 lombok 插件。

目录结构

├─trackray.jar # 编译出来的主程序
│  LICENSE      # 许可协议
│  pom.xml      # maven 根依赖配置文件
│  README.md    # 说明文档
├─base  # 基础模块
│  │  pom.xml   # 基础模块依赖配置
│  │
│  ├─src
│  │  ├─main
│  │  │  ├─java
│  │  │  │  └─com
│  │  │  │      └─trackray
│  │  │  │          └─base
│  │  │  │              ├─annotation    # 注解包
│  │  │  │              │      Exploit.java # 漏洞扫描注解类
│  │  │  │              │      Function.java    # MVC插件功能注解类
│  │  │  │              │      Param.java   # 插件参数注解类
│  │  │  │              │      Plugin.java  # 插件注解类
│  │  │  │              │      Rule.java    # 插件规则注解类
│  │  │  │              │
│  │  │  │              ├─attack    # 集成模块包
│  │  │  │              │      Awvs.java    # AWVS 实现类
│  │  │  │              │      HackKit.java # 插件工具包
│  │  │  │              │      Metasploit.java  # Metasploit 实现类
│  │  │  │              │      Payload.java # Payload 字典类
│  │  │  │              │      Python.java  # Python 实现类
│  │  │  │              │
│  │  │  │              ├─bean  # JavaBean
│  │  │  │              │      Assets.java
│  │  │  │              │      Banner.java
│  │  │  │              │      Constant.java    # 系统常量
│  │  │  │              │      FingerBean.java
│  │  │  │              │      HostInfo.java
│  │  │  │              │      Result.java
│  │  │  │              │      ResultCode.java
│  │  │  │              │      Rule.java
│  │  │  │              │      SenseInfo.java
│  │  │  │              │      SystemInfo.java
│  │  │  │              │      Task.java
│  │  │  │              │      Vulnerable.java  # 漏洞类
│  │  │  │              │
│  │  │  │              ├─controller
│  │  │  │              │      DispatchController.java
│  │  │  │              │
│  │  │  │              ├─entity
│  │  │  │              │      PortEntity.java
│  │  │  │              │      SystemEntity.java
│  │  │  │              │
│  │  │  │              ├─enums # 枚举
│  │  │  │              │      FingerPrint.java # WEB指纹库
│  │  │  │              │      HttpMethod.java
│  │  │  │              │      Language.java    # 编程语言枚举类
│  │  │  │              │      SystemOS.java    # 操作系统枚举类
│  │  │  │              │      VulnLevel.java
│  │  │  │              │      VulnType.java
│  │  │  │              │      WEBServer.java   # WEB服务器枚举类
│  │  │  │              │
│  │  │  │              ├─exception
│  │  │  │              ├─exploit
│  │  │  │              │      AbstractExploit.java # 漏洞插件抽象类
│  │  │  │              │      Exploter.java
│  │  │  │              │
│  │  │  │              ├─handle
│  │  │  │              │      CoreThreadMap.java
│  │  │  │              │      Shell.java   # 系统 SHELL 工具
│  │  │  │              │      SystemInit.java  # 系统初始化
│  │  │  │              │      ThreadMonitor.java
│  │  │  │              │
│  │  │  │              ├─httpclient    # Http发包工具
│  │  │  │              │      CrawlerPage.java
│  │  │  │              │      Fetcher.java
│  │  │  │              │      HttpClient.java
│  │  │  │              │      HttpClientWrapper.java
│  │  │  │              │      HttpProxy.java
│  │  │  │              │      Request.java
│  │  │  │              │      Response.java
│  │  │  │              │      ResponseStatus.java
│  │  │  │              │
│  │  │  │              ├─plugin
│  │  │  │              │      AbstractPlugin.java  # 插件抽象类
│  │  │  │              │      CommonPlugin.java    # 无交互式接口插件父类
│  │  │  │              │      CrawlerPlugin.java   # 爬虫插件父类
│  │  │  │              │      InnerPlugin.java     # 内部插件父类
│  │  │  │              │      MVCPlugin.java       # MVC插件父类
│  │  │  │              │      WebSocketPlugin.java # 命令行交互式插件父类
│  │  │  │              │
│  │  │  │              ├─quartz
│  │  │  │              │      QuartzManager.java   # quartz调度管理
│  │  │  │              │      SpringJobFactory.java
│  │  │  │              │
│  │  │  │              ├─service
│  │  │  │              ├─store
│  │  │  │              │      VulnDTO.java
│  │  │  │              │      VulnRepository.java
│  │  │  │              │
│  │  │  │              └─utils
│  │  │  │                      ...
│  │  │  │
│  │  │  └─resources
│  │  │          log4j2.xml
│  │  │
│  │  │
├─data  # 数据库目录
├─module    # 插件模块
│  │  pom.xml   # 插件模块依赖配置文件
│  │
│  ├─src
│  │  ├─main
│  │  │  ├─java
│  │  │  │  └─com
│  │  │  │      └─trackray
│  │  │  │          └─module
│  │  │  │              │  Verify.java
│  │  │  │              │
│  │  │  │              ├─auxiliary # 辅助工具包
│  │  │  │              │      ...
│  │  │  │              │
│  │  │  │              ├─crawler   # 爬虫插件包
│  │  │  │              │      ...
│  │  │  │              │
│  │  │  │              ├─exploit   # 漏洞扫描插件包
│  │  │  │              │      ...
│  │  │  │              │
│  │  │  │              ├─inner     # 内部插件包
│  │  │  │              │      ...
│  │  │  │              │
│  │  │  │              └─plugin    # 普通插件包
│  │  │  │
│  │  │  └─resources    # 资源包
│  │  │      │
│  │  │      └─templates    # MVC插件模板目录
│  │  │          ├─common
│  │  │          │      error.html
│  │  │          │
│  │  │          ├─json
│  │  │          │      index.html
│  │  │          │      result.html
│  │  │
├─resources    # module 模块 resources 包释放出来的目录
│
└─web
    │  pom.xml  # WEB模块依赖配置文件
    │
    ├─src
    │─main
    │  │  ├─java
    │  │  │  └─com
    │  │  │      └─trackray
    │  │  │          │  WebApplication.java # 程序启动类
    │  │  │          │
    │  │  │          └─web
    │  │  │              ├─api
    │  │  │              │
    │  │  │              ├─config   # 配置包
    │  │  │              │
    │  │  │              ├─handle
    │  │  │              │      ScannerJob.java
    │  │  │              │
    │  │  │              ├─service
    │  │  │              │  │  PluginService.java
    │  │  │              │  │  TaskService.java
    │  │  │              │  │
    │  │  │              │  └─impl
    │  │  │              │          PluginServiceImpl.java
    │  │  │              │          TaskServiceImpl.java
    │  │  │              │
    │  │  │              └─ws
    │  │  │                      HandshakeInterceptor.java
    │  │  │                      MsfHandler.java
    │  │  │                      PluginHandler.java
    │  │  │
    │  │  └─resources
    │  │      │  application.properties # 程序配置文件
    │  │      │  log4j.properties
    │  │      │  trackray-base-framework.xml
    │  │      │  trackray-moudle-application.xml
    │  │      │  trackray-web-application.xml
    │  │      │
    │  │      ├─static  # 静态资源目录
    │  │      │  ├─assets
    │  │      │  │
    │  │      │  ├─css
    │  │      │  │
    │  │      │  └─js
    │  │      │
    └─└────└─templates
                              

插件

AbstractPlugin

这是交互式插件和非交互式插件的父类。

BASE常量

其中的静态常量 BASE 是 /resources/include/ 的所在目录。

如果你的插件需要额外的静态资源,那么你可以在 /resources/include 目录里创建一个和插件 KEY 相同的文件夹,便于识别,如果没有在 @Plugin 注解中设置 value 则默认的插件 KEY 就是当前类名首字母小写。

Typecho001 = typecho001

check(Map<String,Object> param)

public abstract boolean check(Map<String,Object> param);

这是用于检验是否合规的方法,需要被强制重写,当返回 true 时才会调用 start() 方法

param 参数是从前台传过来的参数键值对。

常被用于检验参数格式是否正确或漏洞是否存在。

after()

在 start() 方法之前调用

before()

在 start() 方法之后调用

start()

public abstract E start();  

这是一个抽象方法,所有继承了该类的子类都需要重写这个方法。

在 check 方法通过后会调用 start() 方法

start() 方法返回值最终会会当做插件结果,响应给前台。

shell()

调用当前系统 shell 来辅助完成插件功能。

executor()

插件执行的主方法

crawlerPage

http请求对象(不推荐使用)

fetcher

执行 http 请求对象(不推荐使用)

errorMsg

当校验不通过时,返回给前台的信息。

param

前台传过来的参数键值对

requests

HTTP 发包工具(推荐使用)

hackKit

hack 常用工具包

无交互插件

无交互插件需要你填写好所有要填写的参数,直接请求接口来执行插件。

默认需要去继承 CommonPlugin类。

public abstract class CommonPlugin<E> extends AbstractPlugin<E> {

    public enum Type{
        /**
         * 非交互式插件响应类型
         */
        JSON("application/json"),
        XML("application/xml"),
        HTML("text/html"),
        TEXT("text/plain");

        private String value;

        Type(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }
    public enum Charset{
        /**
         * 非交互式插件响应编码
         */
        UTF8("charset=utf-8"),
        GBK("charset=gbk"),
        GB2312("charset=gb2312"),
        NULL("");

        private String value;

        Charset(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }

    public HttpServletRequest request;
    public HttpServletResponse response;

    public boolean isNone(String o){
        return StringUtils.isBlank(o);
    }

    public boolean isNull(Object o){
        return o==null;
    }

}

这是一个抽象类,继承了 AbstractPlugin

主要多出来两个属性:requestresponse

继承了 CommonPlugin 的类可以通过调用这两个属性来控制请求和响应内容。

TypeCharset 枚举类,用于在插件注解里声明当前接口返回的数据格式和编码类型。

无交互插件同时也需要使用 @Rule@Plugin 插件,这两个注解后面会讲到。

http://127.0.0.1:8080/api,找到相应的插件填写好参数提交即可完成调用。

或直接调用接口。

http://127.0.0.1:8080/plugin/use?key=插件KEY&参数=参数值

交互式插件

交互式插件一般在命令行控制台中调用,可以允许你通过命令行交互来完成插件的调用。

交互式插件由 Websocket 实现,想要写一个交互式插件,首先要继承 WebSocketPlugin 类。

同时设置 @Rule 注解的 websocket 参数为 true ,如果需要异步交互需要将 sync 也设置为 true。

@Rule(sync = true,websocket = true)

    public void sendColorMsg(WebSocketMessage msg);//向控制台发送有颜色的消息

    public void send(String text);//向控制台发送消息

    public String getInput();//获取控制的输入

    public void onClose();//当前会话结束时调用,有需要做对象销毁处理的可以重写这个方法

内部插件

所属包:con.trackray.module.inner

内部插件是不可以通过外部去调用的,需要继承 InnerPlugin 并使用 @Plugin 注解,通常在漏洞扫描时时会调用。

例如 “网页爬虫”,“指纹识别”,“端口扫描” 等,都是通过调用内部插件实现的。

还有用于检测 SSRF 等漏洞用的 FuckCeye 插件也属于内部插件。

通过 spring 的自动注入,来注入内部插件到当前对象。

例子可参考 WebLogicWLSRCE.java

爬虫插件

所属包:con.trackray.module.crawler

爬虫插件会在扫描任务被勾选“网页爬虫”时调用,每爬取一条请求就会调用一次爬虫插件。

爬虫插件需要继承 CrawlerPlugin,继承该类必须重写 check 和 process 方法。

check 方法用于检验请求是否符合插件规则,以免产生多余请求。

当 check 方法返回为 true 时会调用 process 方法。

process 方法里写插件主要检测代码。

addVulnerable()

当插件检测出漏洞时,可以通过调用 addVulnerable() 方法来向数据库插入一条漏洞。

requests

requests 属性为请求工具包,处理 https 和 http 都很方便。

response

response 属性为当前爬虫得到的 HTTP 响应。

task

task 属性为当前任务对象,如果你的爬虫插件不是检测漏洞而希望是检测一些敏感信息的话可以修改 task.getResult() 里的属性。

参考 FingerProbe.javaInfoProbe.java

target

爬虫爬取到的 URL 对象。

fetcher & crawlerPage

http 请求对象(不建议使用)。

漏洞扫描插件

漏洞扫描插件会在,扫描任务中勾选“漏洞攻击模块”时调用。

漏洞扫描插件分为三种

1.独立插件

com.trackray.module.exploit

独立的漏洞扫描插件需要继承 AbstractExploit 并使用 @Plugin@Exploit

AbstractExploit 中有以下需要了解的方法和属性。

requests

http / https 发包工具

target 当前扫描任务的地址。

task

当前扫描任务对象。

check()

check 是一个抽象方法,需要被子类强制重写。

该方法一般用于检验是否符合当前漏洞扫描插件的规则,以免产生多与请求。

attack()

attack 也是一个抽象方法,需要被子类强制重写。

该方法是检测漏洞的主方法。

before()

在 attack 方法前执行

after()

在 attack 方法后执行

addVulnerable()

当插件检测出漏洞时,可以通过调用 addVulnerable() 方法来向数据库插入一条漏洞。

fetcher & crawlerPage

http 请求对象(不建议使用)。

2.漏洞规则

位于

com.trackray.module.inner.SimpleVulRule

实际上这是一个“内部插件”,会在勾选漏洞模块攻击时调用。

有一些漏洞检测方法很简单,只通过简单的判断响应体就能识别出来,也就没有必要再去写一个独立的插件而占用空间了。

在 doSwitch() 方法中会先去根据当前任务的指纹识别结果走一遍 switch 流程。

swtich 的每一个 case 都是 WEB 指纹的枚举对象。
当 switch 找到当前任务 WEB 指纹对应的 case 后,case 内的代码会通过构建一个漏洞规则添加到 loaders 集合里。
如果规则是通用的,可以写在 switch 的外面。

例:phpcms 的 authkey 泄漏漏洞规则

        switch (finger) {
            case $phpcms:
                loaders.add(
                        Payloader.builder()
                                .url("/api.php?op=get_menu&act=ajax_getlist&callback=aaaaa&parentid=0&key=authkey&cachefile=..\\..\\..\\phpsso_server\\caches\\caches_admin\\caches_data\\applist&path=admin")
                                .method(HttpRequest.Method.GET)
                                .containsStr("aaaaa")
                                .vuln(
                                        Vulnerable.builder()
                                                .level(Vulnerable.Level.HIGH.getLevel())
                                                .type(Vulnerable.Type.INFO_LEAKAGE.getType())
                                                .title("phpcms authkey泄漏")
                                                .build()) //另一种实现方式
                                .build()
                );
                break;
         }

3.kunpeng JSON插件

kunpeng 是一个 go 语言编写的 poc 测试框架,这里我对 kunpeng 的 JSON 插件做了一个支持。

只需要按照 kunpeng json 插件的格式规范创建一个 json 文件到 /resources/json 目录。

在扫描任务勾选“漏洞攻击模块”时会被调用,或通过 MVC 插件调用 http://127.0.0.1:8080/apps/json

MVC 插件

位于

com.trackray.module.mvc

MVC 插件的特点在于,他可以像是在写一个功能一样,而非简单的接口式调用。

MVC 插件需要继承 MVCPlugin 类,并使用 @Rule,@Plugin 注解。

MVCPlugin 内置了一个 ModelAndView 对象, 是 SpringMVC 提供的。

可以通过 setViewName() 来指定视图层的网页模板。

通过 addObject(key,value) 向视图层网页模板注入参数。

这里的视图层是使用 freemarker 实现的,需要懂 freemarker 的语法。

例子可以参考:com.trackray.module.inner.JSONPlugin

继承 MVCPlugin 必须要重写一个 index 方法,这是插件的入口。

如果需要写其他的功能,就得再创建一个 public 返回值为 void 的无参方法。

并且要在该方法上使用 @Function 注解,该注解的 value 参数如果不填写的话则默认的 requestMapping 地址为方法名。

例如

@Rule
@Plugin(title = "渗透测试思维导图", value = "pentest" )
public class Pentest extends MVCPlugin{
    @Override
    public void index() {
        model.setViewName("indexPage");
    }
    @Function(value="foo")
    public void fooTest(){
      model.setViewName("fooPage");
    }
}

http://127.0.0.1:8080/plugin/mvc/pentest/index 对应 index()

http://127.0.0.1:8080/plugin/mvc/pentest/foo 对应 fooTest()

最后还需要在 /module/src/main/resources/templates 创建一个目录名为插件 KEY 的目录。

里面存放扩展名为 .html 的模板文件。

1557660576(1).jpg

Python 插件

python 插件有两种实现方式。

1.通过命令行实现
这种方式最为简单,通过在 include 里写一个 python 脚本。

然后在插件里调用 shell() 方法来执行系统命令。

案例可参考 com.trackray.module.plugin.windows.smb.MS17010

但这样还需要再写 java 的代码,对于没有学过 java 的人来说很不友好。

2.通过jython实现

jython 是一个 Python 语言在 Java 中的完全实现。

我将它的调用过程写成了一个交互式插件。

你可以通过在 /resources/python/ 目录下安装如下规范去创建一个 python 文件。

在这个 python 文件中需要写两个方法。

params(): 返回字典对象,key 为 参数,value 为参数的说明。

verify(args): args 是一个字典类型,是从前台传过来的参数。

def params():
    return {"url":"this is target url."}

def verify(args):
    return args

1557661673(1).jpg

关于注解

com.trackray.base.annotation

@Rule

一般用在“可交互插件”和“无交互插件”类上。

public @interface Rule {
    boolean enable() default true;  //是否在外部启用插件
    boolean websocket() default false;  //是否为websocket插件
    boolean sync() default false;   //是否为异步任务
    Param[] params() default {}; // 插件参数
    CommonPlugin.Type type() default CommonPlugin.Type.JSON;    //当使用commonplugin时返回给浏览器的文本类型
    CommonPlugin.Charset charset() default CommonPlugin.Charset.UTF8;   //使用commonplugin时返回给浏览器的文本编码
    String[] headers() default {};  //返回给浏览器时的response header
    String filename() default "";   //插件用于下载功能时返回的文件名
}

params() 最为常用,它用来声明这个插件需要哪几个参数。

public @interface Param {
    String key () default "";           // 参数键
    String defaultValue() default "";   // 参数默认值
    String desc() default "";           // 参数说明

}

例子:Thinkphp51and52RCE.java

@Rule( type = CommonPlugin.Type.HTML ,
        params = {
                @Param(key = "target", desc = "目标地址"),
                @Param(key = "func",defaultValue = "phpinfo" , desc = "执行函数"),
                @Param(key = "var",defaultValue = "1" , desc = "函数参数"),
        })

@Plugin

它是所有插件必须要使用的注解,只有声明了这个注解才可以使用。

public @interface Plugin {
    String value() default "";  //插件在springioc容器的ID
    String title(); //插件标题
    String desc() default "";   //插件介绍
    String author() default "anonymous";    //插件作者
    String[] link() default ""; //插件相关连接
    long time() default 0L; //插件对应的时间戳
}

WEB指纹

这里顺便再说一下如何添加指纹库。

com.trackray.base.enums.FingerPrint

指纹库位于 base 模块,是一个枚举类。

可以在首部或尾部添加一条新的枚举,尽量使用 $ 开头。

第一个参数是 指纹的名称,如果第二个参数是 String 类型则是该指纹的说明。

FingerBean 类是指纹匹配对象。

public class FingerBean {
    private String version; //指纹版本
    private String match;   //匹配表达式
    private String url; //指纹URL
    private String md5; //指纹MD5
}

dedecms 指纹示例

    $dedecms("dedecms",
            new FingerBean("","/data/admin/allowurl.txt","dedecms",""),
            new FingerBean("","/data/index.html","dedecms",""),
            new FingerBean("","/data/js/index.html","dedecms",""),
            new FingerBean("","/data/admin/ver.txt","","b4d132542083d1364022bac8f790cc95"),
            new FingerBean("","/include/data/vdcode.jpg","","ea3350e457f70cf7b4f122c8b832ddbe")),

发表留言

人生在世,错别字在所难免,无需纠正。