浅谈Log4j2不借助dnslog的检测(一)

简介: 浅谈Log4j2不借助dnslog的检测

介绍

目前的Log4j2检测都需要借助dnslog平台,是否存在不借助dnslog的检测方式呢

也许在甲方内网自查等情景下有很好的效果


笔者实习期间参与过xray的一些开发,对其中的反连平台有一些了解。正好天下大木头师傅找到我,提出了它同样的思路,于是我们交流后编写了一款工具,目前功能简单,后续可能会加强


主要原理是参考LDAPRMI协议文档,编写解析协议的代码,获取我们需要的数据,保存即可


所以本文主要就是分析该工具的介绍和编写思路,首先来看看效果

运行工具:./Log4j2Scan.exe -p 8000

4391a9c7e886035296bd051739c171de_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


由于我在本地测试,所以ip地址为127.0.0.1

使用RMI触发漏洞(RMI方式的Payload必须有Path否则不会发请求)

public static void main(String[] args) {
   logger.error("${jndi:rmi://127.0.0.1:8000/xxx}");
}

使用LDAP触发漏洞

public static void main(String[] args) {
   logger.error("${jndi:ldap://127.0.0.1:8000}");
}


可以看到命令行的输出

5ed21892ce07566dd20d426c953086ee_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


我另外做了一个动态更新的web页面,每收到一个请求都会在页面中刷新

7cebf5d8b01d6b3d9cbd9e8993409a28_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


这是最初的版本,这两天我加入了一些新功能,可以从路径中带出参数,该功能有利于批量扫描等方式

(例如ldap://127.0.0.1:1389/4ra1n会收集到4ra1n

cd489e09273629203b8b9ab6eb9abd9a_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


后来木头师傅又做了Burpsuite插件的适配(由于一些原因木头师傅删除了这些功能)

5fe6de3ce428cfb311e1b871c28a232e_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


LDAP

无论是LDAP还是RMI协议情况下的漏洞触发,总是需要发请求的,于是我们将这些请求抓包分析

搭建正常的LDAP Server并监听lookback网卡并设置端口为tcp:1389

5e6c7cff5ecacbb65aef1f1cbe51bc3c_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


无需关心前三步,这三步是TCP的握手,并不包含真正的数据,从PSH+ASK这一条数据来看

首先是漏洞触发端(客户端)向LDAP服务端发了300c020101600702010304008000这样的一串数据

a24b6e3edc06c7ff7e267f6b8d24f56f_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


经过多次不同操作系统下的测试,确认这应该是LDAP协议的指纹,正常情况下客户端都会向服务端首先发送这样一个字符串,为了进一步确认,我尝试到googlegithub进行搜索

Github类似代码 中发现该字符串被很多脚本作为LDAP协议的探测指纹信息,在 官方文档 中确认了为什么是这样的字符串

30 0c -- Begin the LDAPMessage sequence
  02 01 01 -- The message ID (integer value 1)
  60 07 -- Begin the bind request protocol op
    02 01 03 -- The LDAP protocol version (integer value 3)
    04 00 -- Empty bind DN (0-byte octet string)
    80 00 -- Empty password (0-byte octet string with type context-specific
          -- primitive zero)


于是我们用Golang编写了类似的逻辑,构造了一个虚假的LDAP Server分析来自漏洞触发端的TCP连接

监听Socket

log.Info("start fake reverse server")
listen, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", config.Port))
...
for {
   conn, err := listen.Accept()
   ...
   // 分析
   go acceptProcess(&conn)
}

根据上述指纹进行分析

func acceptProcess(conn *net.Conn) {
  buf := make([]byte, 1024)
  num, err := (*conn).Read(buf)
  ...
  hexStr := fmt.Sprintf("%x", buf[:num])
  // LDAP 指纹
  if "300c020101600702010304008000" == hexStr {
     // 如果符合则记录该请求
     res := &model.Result{
        Host:   (*conn).RemoteAddr().String(),
        Name:   "LDAP",
        Finger: hexStr,
    }
  }
}


到这一步只能确定是LDAP协议还拿不到传过来的参数(ldap://127.0.0.1:1389/4ra1n中的4ra1n

于是继续查看官方文档,构造标准的返回包

30 0c -- Begin the LDAPMessage sequence
  02 01 01 -- The message ID (integer value 1)
  61 07 -- Begin the bind response protocol op
    0a 01 00 -- success result code (enumerated value 0)
    04 00 -- No matched DN (0-byte octet string)
    04 00 -- No diagnostic message (0-byte octet string)

按照标准返回之后,会再次从客户端得到输入

不过这个包并不能匹配到LDAP官方文档中任意一种协议(也许是我没找到)


通过大量请求做diff后发现这里新输入的规律

  • 输入前7位是固定的
  • 输入的第8位代表路径的长度n(例如4ra1n长度为05
  • 从第9位到第9+n位是对应的路径参数


按照这个规则编写,即可取到其中的参数

if "300c020101600702010304008000" == hexStr {
   data := []byte{
       0x30, 0x0c, 0x02, 0x01, 0x01, 0x61, 0x07,
       0x0a, 0x01, 0x00, 0x04, 0x00, 0x04, 0x00,
  }
   _, _ = (*conn).Write(data)
   _, _ = (*conn).Read(buf)
   length := buf[8]
   pathBytes := bytes.Buffer{}
   for i := 1; i <= int(length); i++ {
       temp := []byte{buf[8+i]}
       pathBytes.Write(temp)
  }
   // 得到path
   path := pathBytes.String()
   ...
   _ = (*conn).Close()
   return
}


RMI

RMI的分析过程大致分为5步,我将和大家逐个介绍

(1)Client -> Server

接下来分析RMI的情况

同样的方式抓包看到4a524d4900024b的指纹,由漏洞触发端(客户端)发向RMI服务端

不过RMI协议的开头并不这么简单,不一定是一个固定的字符串

Oracle官网看到了这样的描述:RMI协议分为请求头Header和消息Message部分,上文的字符串是Header相关的内容,该TCP连接后续会进行Message的传输

关于Header的解释如下:0x4a 0x52 0x4d 0x49为固定字节(转成字符串是JRMI

后面两个字节分别表示VersionProtocol信息,按照RMI协议的规定,这里的Version应该是0x00 0x01,实际抓包看到的是0x00 0x02,或许是文档较老的原因?

末尾的0x4b表示这是StreamProtocol协议方式,没有什么问题

Header:
  0x4a 0x52 0x4d 0x49 Version Protocol
Version:
  0x00 0x01
Protocol:
  StreamProtocol
  SingleOpProtocol
  MultiplexProtocol
StreamProtocol:
  0x4b
SingleOpProtocol:
  0x4c
MultiplexProtocol:
  0x4d

其实仔细看Wireshark的解析,和我做的分析一致

1e2820d97c940bf79400e3296f25b0d8_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

如果只为了确认RMI协议,那么到这里就可以了

但我们的目的是获取路径参数,在RMI协议中这一步尤其复杂


(2)Server -> Client

接下来应该是RMI服务端返回数据给漏洞触发端(客户端)

原始报文为

0000   4e 00 0f 44 45 53 4b 54 4f 50 2d 46 50 30 32 42   N..DESKTOP-FP02B
0010   4b 48 00 00 f8 8e                                 KH....

根据官方文档不难看出0x4e表示ProtocolAck且后续内容应该是具体返回的值

In:
  ProtocolAck Returns
ProtocolAck:
  0x4e

简单分析了下这里0x00 0x0f表示长度15,后15位DESKTOP-FP02BKH是服务端的主机名

最后的0xf8 0xfeRMI客户端的端口:63630

Wireshark中可以看到解析结果和分析一致

ded8a69d4d3a85b05a8c1f7ff881d372_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png



相关文章
|
云安全 域名解析 安全
警惕主动外联!云防火墙检测拦截勒索、Muhstik僵尸网络等 Log4j2漏洞利用
近期,阿里云安全观测到,在 Apache Log4j2 漏洞攻击全程中,无论是在漏洞利用阶段,还是后续要进行验证和进一步的控制利用,大多涉及多次受害服务器的主动外联,云防火墙已陆续发现并拦截60余万次涉及勒索、挖矿家族的漏洞利用行为。
848 0
警惕主动外联!云防火墙检测拦截勒索、Muhstik僵尸网络等 Log4j2漏洞利用
|
2月前
|
算法
m基于log-MPA检测算法的SCMA通信链路matlab误码率仿真
MATLAB 2022a仿真实现了稀疏码多址接入(SCMA)算法,该算法利用码本稀疏性实现多用户高效接入。每个用户从码本中选取码字发送,接收端采用Log-MPA算法进行多用户检测。由于MAP检测计算复杂度高,故采用Log-MPA降低复杂性。仿真展示了不同迭代次数(1, 5, 10, 30)对误码率(BER)的影响,通过比较各次迭代的BER曲线,研究算法性能与迭代次数的关系。
25 0
|
10月前
|
Shell Perl
检测网卡流量,并按规定格式记录在日志中
检测网卡流量,并按规定格式记录在日志中
57 2
|
12月前
|
JSON 安全 Java
使用goby检测log4j漏洞
使用goby检测log4j漏洞
|
JSON 监控 Kubernetes
如何使用 Deepfence 检测和修复 Log4j2 漏洞
log4j2 漏洞(如 OpenSSL Heartbleed 和 Apache Struts 漏洞之前出现的漏洞)向互联网企业发出了深刻的提醒,一旦补丁可用,通过重新部署应用程序来响应漏洞并不够,您还必须能够发现在您的生产平台中实时利用漏洞并阻止它们。在本教程中,我们将向您展示如何使用 Deepfence ThreatMapper 和 ThreatStryker 来帮助您做到这一点。
120 0
|
安全 前端开发 fastjson
浅谈Log4j2不借助dnslog的检测(二)
浅谈Log4j2不借助dnslog的检测
217 0
浅谈Log4j2不借助dnslog的检测(二)
|
Apache
Apache HttpClient库里的日志实现检测原理
Apache HttpClient库里的日志实现检测原理
124 0
Apache HttpClient库里的日志实现检测原理
|
监控 安全 测试技术
如何通过审计安全事件日志检测密码喷洒(Password Spraying)攻击
许多渗透测试人员和攻击者通常都会使用一种被称为“密码喷洒(Password Spraying)”的技术来进行测试和攻击。对密码进行喷洒式的攻击,这个叫法很形象,因为它属于自动化密码猜测的一种。这种针对所有用户的自动密码猜测通常是为了避免帐户被锁定,因为针对同一个用户的连续密码猜测会导致帐户被锁定。
1417 0
|
1天前
|
XML Java Maven
Springboot整合与使用log4j2日志框架【详解版】
该文介绍了如何在Spring Boot中切换默认的LogBack日志系统至Log4j2。首先,需要在Maven依赖中排除`spring-boot-starter-logging`并引入`spring-boot-starter-log4j2`。其次,创建`log4j2-spring.xml`配置文件放在`src/main/resources`下,配置包括控制台和文件的日志输出、日志格式和文件切分策略。此外,可通过在不同环境的`application.yml`中指定不同的log4j2配置文件。最后,文章提到通过示例代码解释了日志格式中的各种占位符含义。