Brupsuite被动扫描Log4j2插件临时修改

Brupsuite被动扫描Log4j2插件临时修改,记录一次将想法化为行动的经历

前言

上周log4j2的漏洞在中期还不温不火,到了周五,非常简单的POC被爆出,漫天的厂家log4j2告警,朋友圈挤满了漏洞通告。当时还在项目上,Github看到了whwlsfb师傅写的Burpsuite被动扫描log4j2漏洞的插件(链接在文末)。

本着学过菜鸟教程JAVA的基础类型,试着分析下代码是如何实现被动检测的。因为当时的检测方法就是在可能被日志记录的地方胡乱插入POC,然后通过dns平台的回显来判断注入点是否存在。

分析

当时正在关注这个插件,想直接拿来测试的,但是在进行最开始的版本测试的时候,发现无法检测到,然后抓包找问题,发现用的是dnslog.cn平台来做一个判断,而且POC中漏了},这在新版本中都已经修改

以下为v0.2.1版本的项目树结构

  1. D:.
  2. .gitignore
  3. pom.xml
  4. README.md
  5. ├─screenshots
  6. detected.png
  7. └─src
  8. └─main
  9. └─java
  10. └─burp
  11. BurpExtender.java
  12. Log4j2Issue.java
  13. ├─dnslog
  14. IDnslog.java
  15. └─platform
  16. Ceye.java
  17. DnslogCN.java
  18. ├─scanner
  19. Log4j2Scanner.java
  20. └─utils
  21. HttpUtils.java
  22. ScanItem.java
  23. SslUtils.java
  24. Utils.java

当时已然更新到v0.2.1版本,Clone下来发现代码量不大,虽然没有接触过burpsuite的插件开发,但是通过函数名以及调用结构可以猜测到大概的意思
其中主要就三个文件:Ceye.java ,DnslogCN.java ,Log4j2Scanner.java
/brup/scanner/Log4j2Scanner.java
通过函数名可以知道是被动扫描模块
主要是定义了exp,并且通过遍历参数,当遍历到是Get参数,Cookie参数,POST参数时,会进行值的替换,替换后进行一个CheckResult的方法调用

/brup/dnslog/platform/DnslogCN.java
platform package中就是对具体的dnslog平台的解析,其中内置了ceye和dnslog.cn两个公开站

最主要的就三个函数

其中initDomain函数就是请求dnslog.cn然后获取一个子域

getNewDomain函数就是进行一个拼接,比如获取一个子域ehb52l.dnslog.cn,拼接成xxxcc.ehb52l.dnslog.cn,主要用来递归解析

CheckResult函数则是对应Refresh Recode请求获取解析结果

这样就一目了然了,该插件通过被动扫描遍历每一个参数,提取出Cookie,Get,Post参数,然后有多少个就遍历多少个,每遍历一个参数值就会发送一次子域的获取,获取完后再进行数据的获取,查看是否返回数据,如果有返回数据,就可以确定某个路径下的某个参数存在log4j记录日志的行为并且触发了漏洞(dnslog平台数据和结果的同步性判断通过okhttp3的CookieJar Cookie持久化实现)

实验

顺序其实也是先实验遇到问题然后在分析工具改写的,这里倒过来看,稍微清晰点
由于技术太菜,秉持着脚本小子拿来就用的风格,直接加载了该插件并且被动扫描测试了Tools上有师傅发的漏洞Web Demo,发现了问题=>dnslog.cn炸了

POC变成了${jndi:ldap://1639129872920gxXTk./803533}
通过之前的getNewDomain函数可以看到.后面应该是rootDomain,也就是我们请求dnslog.cn/getdomain.php之后获取到的子域,但是这里无了,测试了好几次还是这个问题,于是去访问了下dnslog.cn平台,发现已经访问不了,直接裂开了,ceye.io也访问不了。两个公开常用的dnslog平台均失效。

  1. public String getNewDomain() {
  2. return Utils.getCurrentTimeMillis() + Utils.GetRandomString(5) + "." + rootDomain;
  3. }

由于当时气氛火热,很想复现一下,并且将该插件立马用到项目上去检测,但是平台都挂了,等于枪有了,子弹空了。试试看自己能不能再解析一个新平台https://log.xn--9tr.com/,于是自己开始面向百度开始修改

修改

该平台并不像dnslog一样,Cookie持久化就可以任意取domain,任意获取results,该站点设置了Token
请求样式如下
获取子域:

获取数据:

可以看到请求获取子域的方式非常的简单,一个Get请求即可,而获取数据的方式需要将获取到的domain和token放入Cookie中,并且请求路径需要改写为https://log.xn--9tr.com/${token}的样式。于是照猫画虎,原项目中使用okhttp3,我也面向百度学习使用okhttp3来做请求,并且相应的对HttpUtils.java进行基础http请求的改写

最开始真的把原项目代码搬来搬去,并且结合百度学习和自己的思路摘抄改写解析方式。
最后粗制滥造糅杂了一些Java代码,调来调去,保证了没有报错,形成了如下的代码

  1. package com.K0uaz.demo;
  2. import com.alibaba.fastjson.JSONException;
  3. import com.alibaba.fastjson.JSONObject;
  4. import okhttp3.CacheControl;
  5. import okhttp3.OkHttpClient;
  6. import okhttp3.Request;
  7. import okhttp3.Response;
  8. import java.io.IOException;
  9. import java.util.Calendar;
  10. import java.util.Random;
  11. import java.util.concurrent.TimeUnit;
  12. public class HellWorld {
  13. OkHttpClient client = new OkHttpClient().newBuilder().
  14. connectTimeout(3000, TimeUnit.SECONDS).
  15. callTimeout(3000, TimeUnit.SECONDS).build();
  16. JSONObject paramss = null;
  17. String platformUrl = "https://log.xn--9tr.com/";
  18. public static void main(String[] args) {
  19. HellWorld a = new HellWorld();
  20. Okktest b = new Okktest();
  21. System.out.println(b.path);
  22. //a.Go();
  23. }
  24. public void Go() {
  25. try {
  26. // 初始化 OkHttpClient
  27. //OkHttpClient client = new OkHttpClient();
  28. // 初始化请求体
  29. Request request = new Request.Builder()
  30. .get()
  31. .url("https://log.xn--9tr.com/new_gen?t=0.3113540327207853")
  32. //.url("http://121.5.44.178/test.php")
  33. .build();
  34. // 得到返回Response
  35. Response resp = client.newCall(request).execute();
  36. String respStr = resp.body().string();
  37. paramss = sloveJSON(respStr);
  38. String domain = paramss.getString("domain");
  39. String token = paramss.getString("token");
  40. System.out.println(domain.substring(0,domain.length()-1)+"-"+token);
  41. System.out.println(CheckResult(paramss));
  42. //parseJsonWithJsonObject(resp);
  43. //System.out.println(domain);
  44. }
  45. catch (IOException e) {
  46. e.printStackTrace();
  47. }
  48. }
  49. private JSONObject sloveJSON(String respStr) throws IOException {
  50. JSONObject object = null;
  51. try{
  52. object = JSONObject.parseObject(respStr);
  53. }catch (JSONException e) {
  54. e.printStackTrace();
  55. }
  56. return object;
  57. }
  58. public boolean CheckResult(JSONObject respStr){
  59. try {
  60. String domain = respStr.getString("domain");
  61. String token = respStr.getString("token");
  62. Response resp = client.newCall(GetDefaultRequest(domain,token,platformUrl + token + "?t=0.3113540327207853").build()).execute();
  63. String responsedata = resp.body().string();
  64. System.out.println(responsedata);
  65. return responsedata.contains("subdomain");
  66. } catch (Exception ex) {
  67. System.out.println(ex);
  68. return false;
  69. }
  70. }
  71. public Request.Builder GetDefaultRequest(String domain,String token,String url) {
  72. CacheControl NoCache = new CacheControl.Builder().noCache().noStore().build();
  73. int fakeFirefoxVersion = GetRandomNumber(45, 94 + Calendar.getInstance().get(Calendar.YEAR) - 2021);
  74. Request.Builder requestBuilder = new Request.Builder()
  75. .url(url);
  76. requestBuilder.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:" + fakeFirefoxVersion + ".0) Gecko/20100101 Firefox/" + fakeFirefoxVersion + ".0");
  77. requestBuilder.header("Cookie", "key=" + domain + "; " + "token=" + token);
  78. return requestBuilder.cacheControl(NoCache);
  79. }
  80. public static int GetRandomNumber(int min, int max) {
  81. return new Random().nextInt(max - min + 1) + min;
  82. }
  83. }

其中遇到最麻烦的就是Json的解析,百度搜索了okhttp3对于json返回值的解析,发现有很多复制粘贴的,基本都无法使用,都是报错,然后Google搜索到菜鸟教程,看到了两句话就解析完了。

最后就是将上面写的解析的代码柔和到插件项目中,然后由于发包量太大,效率不高,我精简了参数的遍历数量,最后成品也在下文链接中。

感悟

该文主要就是简单记录了自己的一次将想法化为行动的经历。

因为我发现很多时候拿来就用的习惯,让自己停止了一些思考,停止了对于知识的探索和运用,总觉得会用=>懂了,收藏了文章=>会了。渐渐的少了很多漏洞复现,少了很多漏洞分析,少了很多新的思考。

以后应该多想着让想法落地,提高自己的效率和行动力,而不是凭空想象。

顺带提一嘴:现在https://log.咕.com/限制了频率,且我不太推荐依靠外部Dnslog平台,对公共平台资源利用占用太大,免不了被Ban,更好的方法比如有自己搭建DNSLOG平台,利用JNDI监听器代替dnslog等。

原项目仍在不断的更新,增加了检测类型,忽略静态文件,增加绕过POC等新功能,既然想法适应不了工具,试着动动手,让工具适应你的想法。个人认为这也是造轮子的一种意义。

上文链接:

精品更新原项目:https://github.com/whwlsfb/Log4j2Scan
粗制滥造修改版:https://github.com/K0uaz/Log4j2Scan_K

  • 发表于 2021-12-14 11:37:06
  • 阅读 ( 11729 )
  • 分类:安全工具

1 条评论

K0u_az
K0u_az

5 篇文章

站长统计