0x01 前言
前兩天爆了一個LDAP漏洞,據說存在了8年現在才被發現,感概一下,不知這8年來有多少站被搞了。。。
想著復現這個漏洞,就先復習一下LDAP注入的相關知識吧,差了很多資料,記一下筆記。
0x02 LDAP介紹
在學習LDAP注入之前,首先要了解LDAP的運行機制。
什么是LDAP?LDAP(Lightweight Directory Access Protocol):輕量級目錄訪問協議,是一種在線目錄訪問協議。LDAP主要用于目錄中資源的搜索和查詢,是X.500的一種簡便的實現。
簡單來說,可以理解為LDAP是某種搜索協議,就像我們熟知的數據庫一樣,我們利用SQL語句進行查詢數據庫中的數據。而LDAP也有一套自己的查詢語句,來進行查詢。
LDAP查詢語法
search語法:attribute operator value
search filter options:( "&" or "|" (filter1) (filter2) (filter3) ...) ("!" (filter))
LDAP的搜索語法其實很容易,這里看不明白的話,往下看一下具體實例就會明白的。
0x03 LDAP注入攻擊
輕量級目錄訪問協議是通過TCP/IP查詢和修改目錄服務的協議,使用最廣泛的LDAP服務如微軟的ADAM(Active Directory Application Mode)和OpenLDAP。
(&(attribute=value)(injected_filter)) (second_filter)
需要注意的是,在OpenLDAP中,第二個過濾器會被忽略,只有第一個會被執行,那么類似上面的這種注入就可以成功的。而在ADAM中,有兩個過濾器的查詢是不被允許的,那么這種注入是沒什么用的。
- AND LDAP注入
當后端的代碼如下
(&(parameter1=value1)(parameter2=value2))
這里value1和value2都會被查詢,其中value1和value2是用戶可控的,如果過濾不完善,就會存在LDAP注入的可能。
比如一個用戶登錄的場景,用戶輸入username和password,應用會構造一個過濾器并發給LDAP服務器進行查詢。
(&(username=uname)(password=pwd))
當用戶輸入一個有效的用戶名,例如admin,那么就有可能在username字段后面進行注入,從而在不知道密碼的情況下進行登陸。
payload: admin)(&))
result: (&(username=admin)(&))(password=123))
LDAP服務器只會處理第一個過濾器,而第一個過濾器永真,因此繞過了登錄框
- OR LDAP注入
當后端代碼如下:
(|(parameter1=value1)(parameter2=value2))
一個典型的OR LDAP注入的場景就是:
假設一個資源管理器允許用戶了解系統中可用的資源(打印機、掃描器、存儲系統等)。用于展示可用資源的查詢為:
(|(type=Rsc1)(type=Rsc2))
Rsc1和Rsc2表示系統中不同種類的資源,例如,Rsc1=printer,Rsc2=scanner用于列出系統中所以可用的打印機和掃描器。
payload: Rsc1=printer)(uid=*)
result: (|(type=printer)(uid=*))(type=scanner))
LDAP服務器會響應所有的打印機和用戶對象
- LDAP盲注
- LDAP AND盲注
假設一個Web應用想從一個LDAP目錄列出所有可用的Epson打印機,錯誤信息不會返回,應用發送如下的過濾器:
(&(objectclass=printer)(type=Epson*))
使用這個查詢,如果有可用的Epson打印機,其圖標就會顯示給客戶端,否則沒有圖標出現。如果攻擊者進行LDAP盲注入攻擊”)(objectClass=))(&(objectClass=void”,Web應用會構造如下查詢:
(&(objectclass=*)(objectClass=*))(&(objectClass=void)(type=Epson*))
僅對第一個過濾器進行處理:
(&(objectclass=*)(objectClass=*))
結果是,打印機的圖標會一定顯示出來,因為該查詢永遠會有結果,過濾器objectClass=*總是返回一個對象。當圖標被顯示時響應為真,否則為假。
例如構造如下的注入:
(&(objectClass=*)(objectClass=users))(&(objectClass=foo)(type=Epson*))
(&(objectClass=*)(objectClass=resources))(&(objectClass=foo)(type=Epson*))
這種代碼注入的設置允許攻擊者推測可能存在于LDAP目錄服務中不同對象類的值。當響應Web頁面至少包含一個打印機圖標時,對象類的值就是存在的,另一方面而言,如果對象類的值不存在或沒有對它的訪問,就不會有圖標出現。
- LDAP OR盲注
這種情況下,用于推測想要的信息的邏輯是相反的,因為使用的是OR邏輯操作符。接下來使用的是同一個例子,OR環境的注入為:
(|(objectClass=void)(objectClass=void))(&(objectClass=void)(type=Epson*))
這個LDAP查詢沒有從LDAP目錄服務獲得任何對象,打印機的圖標也不會顯示給客戶端(FALSE)。如果在響應的Web頁面中有任何圖標,則響應為TRUE。故攻擊者可以注入下列LDAP過濾器來收集信息:
(|(objectClass=void)(objectClass=users))(&(objectClass=void)(type=Epson*))
(|(objectClass=void)(objectClass=resources))(&(objectClass=void)(type=Epson*))
0x04 LDAP注入防御
LDAP注入的防御跟SQL注入的防御其實差不多,主要就是要把用戶輸入的東西過濾好,基本就可以防御了。
下圖包含了LDAP中用到的特殊字符和需要轉義處理的字符:
左邊的字符在正常情況下是不會用到的,如果在用戶的輸入中出現了需要用反斜杠轉義處理。而右邊的圓括號這些如果不過濾的話就會導致過濾器閉合而生產攻擊者需要的filter,這里看到不僅是用反斜杠處理,還將字符變成了相應的ASCII碼值,這些符號本不該出現。
這段php防御代碼可以記錄一下:
function ldapspecialchars($string) {
$sanitized=array('\\' => '\5c',
'*' => '\2a',
'(' => '\28',
')' => '\29',
"\x00" => '\00');
return str_replace(array_keys($sanitized),array_values($sanitized),$string);
}
LDAP服務開啟的端口是389,如果發現某個服務器上開啟了該端口很可能就是開啟了LDAP服務
0x05 參考文獻
http://www.cnblogs.com/r00tgrok/p/LDAP_INJECTION_AND_PREVENTION.html