CVE2018-6789是一個off-by-one的漏洞,文章對該漏洞的利用流程進行了詳細的表述。
off-by-one漏洞
??off-by-one意為一個字節溢出。
棧:
??這里從網上引用一個demo便于理解
#include <stdio.h>
#include <string.h>
void foo(char* arg);
void bar(char* arg);
void foo(char* arg) {
bar(arg); /* [1] */
}
void bar(char* arg) {
char buf[256];
strcpy(buf, arg); /* [2] */
}
int main(int argc, char *argv[]) {
if(strlen(argv[1])>256) { /* [3] */
printf("Attempted Buffer Overflow\n");
fflush(stdout);
return -1;
}
foo(argv[1]); /* [4] */
return 0;
}
結合代碼和圖片來看,從代碼可以看到當用戶輸入256字節的數據,foo函數調用strcpy(buf, arg); 執行時,foo的EBP的LSB會被覆蓋。從圖中可以看出當EBP被一個NULL字節所覆蓋時,ebp從0xbffff2d8變為0xbffff200,由于用戶輸入被復制到該目標緩沖區,攻擊者可以控制這個堆棧位置(0xbffff200),因此可以實現任意代碼執行。
堆:
??由于ptmalloc的堆塊驗證機制的不完善,使得即使只有一個字節的溢出也使堆的off-by-one漏洞變得可利用。簡單舉個例子。
假設有這樣3個塊:
之后A發生了off-by-one于是堆結構變成了這個樣子
圖中的紅色區域我們可以改掉Bblock的大小,使其增加到C,之后我們free掉B,再分配B+C大小的塊,這樣可以間接實現對CBlock的讀寫。
ACL訪問控制列表
??ACL使Access Control List的縮寫,主要的目的是在提供傳統的owner,group,others的read,write,execute權限之外的細部權限設定。ACL可以針對單一的使用者,單一的檔案或目錄來進行r,w,x的權限規范,對于需要特殊權限的使用狀況非常有幫助。
傳統的Linux下,上面的權限分配正常但是當下面的情況出現時,就出現了問題:
上圖情況出現時,就出現了問題,而這也是ACL所解決的。
OverView
我們在2018年2月5日報告了Exim的base64解碼函數中的溢出漏洞,標識為CVE-2018-6789。 自從exim第一次發布以來就存在這個錯誤,因此所有版本都受到影響。 根據我們的研究,可以利用它來獲得預授權遠程代碼執行,并且至少有400,000臺服務器處于風險之中。 補丁版本4.90.1已經發布,我們建議立即升級exim。
Affected
??所有低于4.90.1版本的Exim
One byte overflow in base64 decoding
Vulnerability Analysis
漏洞的成因在b64decode函數中解碼緩沖區長度的計算錯誤:
base64.c:153b64decode
b64decode(const uschar* code, uschar **ptr)
{
Int x, y;
Uschar* result = store_get(3*(Ustrlen(code)/4)+1);
*ptr = result;
//perform decoding
}
如上所示,exim分配一個3 *(len / 4)+1字節的緩沖區來存儲解碼后的base64數據。 但是,當輸入不是有效的base64字符串且長度為4n + 3時,exim分配3n + 1,但在解碼時會占用3n + 2個字節。 這會導致單字節堆溢出(aka逐個)。
一般來說,這個錯誤是無害的,因為被覆蓋的通常是未使用的內存。 但是,當字符串適合某些特定長度時,該字節會覆蓋一些關鍵數據。 值得注意的是,由于這個字節是可控的,使得對其利用更加可行。另外,Base64解碼是一個基本功能,因此這個錯誤可以很容易地觸發,導致遠程代碼執行。
Exploitation
為了評估這個錯誤的嚴重程度,我們開發了一個針對exim的SMTP守護進程的攻擊。 以下段落描述了用于實現pre-auth遠程代碼執行的開發機制。 為了利用這一個字節的溢出,我們有必要誘騙內存管理機制。此外在閱讀本節之前,強烈建議您具有堆漏洞利用的基本知識。
我們的EXP需要一下幾樣東西:
Debain(stretch) and Ubuntu(zesty)
SMTP daemon of Exim4 package installed with apt-get(4.89/4.88)
Config enabled(uncommented in default config)CRAM-MD5 authenticator(any other authenticator using base64 alse works)
Basic SMTP sommands(EHLO,MAIL FROM/RCPT TO)and AUTH
Memory allocation
??首先,我們回顧一下源代碼并搜索有用的內存分配。 正如我們在前一篇文章中提到的,exim使用自定義函數進行動態分配:
extern BOOL store_extend_3(void *, int, int, const char *, int); /* The */
extern void store_free_3(void *, const char *, int); /* value of the */
extern void *store_get_3(int, const char *, int); /* 2nd arg is */
extern void *store_get_perm_3(int, const char *, int); /* __FILE__ in */
extern void *store_malloc_3(int, const char *, int); /* every call, */
extern void store_release_3(void *, const char *, int); /* so give its */
extern void store_reset_3(void *, const char *, int); /* correct type */
函數store_free()和store_malloc()直接調用glibc的malloc()和free()。 Glibc需要一個稍大的(0x10字節)塊,并將其元數據存儲在每個分配的第一個0x10字節(x86-64)中,然后返回數據的位置。 下面的插圖描述了塊的結構:
元數據包括前一個塊的大小(正好在內存中的那個),當前塊的大小和一些標志。 大小的前三位用于存儲標志。 在這個例子中,0x81的大小意味著當前塊是0x80字節,并且前一個塊正在使用中。
在exim中,大部分被釋放的塊被放入一個雙向鏈表中,稱為unsorted bin。 Glibc根據標志位維護它為了避免碎片化,Glibc會將相鄰的已被釋放塊合并到一個更大的塊。 對于每個分配請求,glibc都會以FIFO(先進先出)順序檢查這些塊,并重新使用這些塊。
針對一些性能問題,exim使用store_get(),store_release(),store_extend()和store_reset()維護自己的鏈表結構。
storeblocks的主要特點是每塊至少有0x2000字節,這使我們的漏洞利用受到限制。 請注意,storeblock也是數據塊。 因此,如果我們查看內存,其內存結構看起來就像這個樣子:
這里我們列舉出用來部署堆數據的函數:
smtp_in.c: 1833 check_helo
/* Discard any previous helo name */
if (sender_helo_name != NULL)
{
store_free(sender_helo_name);
sender_helo_name = NULL;
}
...
if (yield) sender_helo_name = string_copy_malloc(start);
return yield;
smtp_in.c: 5725 smtp_setup_msg
done = synprot_error(L_smtp_syntax_error, 500, NULL,
US"unrecognized command");
smtp_in.c: 3771 smtp_setup_msg
int
smtp_setup_msg(void)
{
int done = 0;
BOOL toomany = FALSE;
BOOL discarded = FALSE;
BOOL last_was_rcpt = FALSE;
void *reset_point = store_get(0);
DEBUG(D_receive) debug_printf("smtp_setup_msg entered\n");
/* Reset for start of new message. We allow one RSET not to be counted as a
nonmail command, for those MTAs that insist on sending it between every
message. Ditto for EHLO/HELO and for STARTTLS, to allow for going in and out of
TLS between messages (an Exim client may do this if it has messages queued up
for the host). Note: we do NOT reset AUTH at this point. */
smtp_reset(reset_point);
Exploit steps
??為了充分利用off-by-one,解碼后的base64數據下的塊應該易于釋放和控制。 經過多次嘗試,我們發現sender_host_name是一個不錯的選擇。 我們安排堆布局,為base64數據留下一個空閑的塊,高于sender_host_name。我們在sender_host_name之前留下一個空閑快給base64數據
uschar *acl_smtp_auth;
uschar *acl_smtp_data;
uschar *acl_smtp_etrn;
uschar *acl_smtp_expn;
uschar *acl_smtp_helo;
uschar *acl_smtp_mail;
uschar *acl_smtp_quit;
uschar *acl_smtp_rcpt
這些指針在exim進程開始時根據配置進行初始化設置。 例如,如果configure中有一行acl_smtp_mail = acl_check_mail,則指針acl_smtp_mail指向字符串acl_check_mail。 無論何時使用MAIL FROM,exim都會先擴展acl_check_mail來執行ACL檢查。 在擴展時,如果遇到$ {run {cmd}},exim會嘗試執行命令,所以只要我們控制ACL字符串,就可以實現代碼執行。 另外,我們不需要直接劫持程序控制流程,因此我們可以輕松地繞過諸如PIE(位置獨立可執行文件),NX等保護機制。
原文:
https://devco.re/blog/2018/03/06/exim-off-by-one-RCE-exploiting-CVE-2018-6789-en/
參考鏈接:
https://googleprojectzero.blogspot.com/
https://sploitfun.wordpress.com/2015/06/09/off-by-one-vulnerability-heap-based/
https://sploitfun.wordpress.com/2015/02/26/heap-overflow-using-unlink/
https://bbs.pediy.com/thread-217390.htm
https://www.contextis.com/resources/white-papers/glibc-adventures-the-forgotten-chunks
http://linux.vbird.org/linux_basic/0410accountmanager.php#acl_talk_what
https://sploitfun.wordpress.com/2015/06/07/off-by-one-vulnerability-stack-based-2/