压在透明的玻璃上c-国产精品国产一级A片精品免费-国产精品视频网-成人黄网站18秘 免费看|www.tcsft.com

CVE2018-6789利用及保護機制的繞過

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也是數據塊。 因此,如果我們查看內存,其內存結構看起來就像這個樣子:

這里我們列舉出用來部署堆數據的函數:

  1. EHLO主機名
    對于每個EHLO(或HELO)命令,exim將主機名的指針存儲在sender_host_name中。
    store_free()舊名稱
    store_malloc()新名稱

    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;
    
  2. 無法識別的命令
    對于每個無法識別的帶有不可打印字符的命令,exim都會分配一個緩沖區來將其轉換為可打印的
    store_get()存儲錯誤消息

    smtp_in.c: 5725 smtp_setup_msg
    done = synprot_error(L_smtp_syntax_error, 500, NULL,
     US"unrecognized command");
    
  3. AUTH
    在大多數身份驗證過程中,exim使用base64編碼與客戶端進行通信。 編碼和解碼字符串存儲在由store_get()分配的緩沖區中。
    store_get()用于字符串
    可以包含不可打印的字符,NULL字節
    不一定是null終止
  4. 重置EHLO / HELO,MAIL,RCPT
    每當有命令正確完成時,exim就會調用smtp_reset()。 此函數調用store_reset()將塊鏈重置為重置點,這意味著在last命令后所有通過store_get()分配的storeblocks都會被釋放。
    store_reset()重置點(在函數的開始處設置)
    在釋放塊的時候添加

    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數據

  1. Put a huge chunk into unsorted bin
    首先,我們發送一個包含巨大主機名的EHLO消息,以使其在堆中分配和釋放,留下一個0x6060長度的unsorted bin。
  2. Cut the first storeblock
    然后我們發送一個無法識別的字符串來觸發store_get()并在釋放的塊內分配storeblock。
  3. Cut the second storeblock and release the first one
    我們再次發送EHLO消息以獲得第二個存儲區。 由于EHLO完成后調用了smtp_reset,所以第一個塊被順序釋放。
    堆布局準備好后,我們可以使用off-by-one覆蓋原始塊大小。 我們將0x2021修改為0x20f1,這稍微擴展了塊。
  4. Send base64 data and trigger off-by-one
    要觸發off-by-one,我們啟動一個AUTH命令來發送base64數據。 溢出字節正好覆蓋下一個塊的第一個字節并擴展下一個塊。
  5. Forge a reasonable chunk size
    由于塊已擴展,下一塊塊的開始被更改為原始塊的內部。 因此,我們需要讓它看起來像一個正常的塊來通過glibc的理智檢查。 我們在這里發送另一個base64字符串,因為它需要空字節和不可打印字符來偽造塊大小。
  6. Release the extended chunk
    要控制擴展塊的內容,我們需要首先釋放塊,因為我們無法直接編輯塊。 也就是說,我們應該發送一個新的EHLO消息來釋放舊的主機名。 但是,正常的EHLO消息在成功之后會調用smtp_reset,這可能會導致程序中止或崩潰。 為了避免這種情況,我們發送一個無效的主機名稱,如a+。
  7. Overwrite the next pointer of overlapped storeblock

    塊釋放后后,我們可以使用AUTH檢索它并覆蓋部分重疊的存儲塊。 這里我們使用一種稱為partial write的技巧。 有了這個,我們可以在不破壞ASLR(地址空間布局隨機化)的情況下修改指針。 我們部分地改變了包含ACL(訪問控制列表)字符串的storeblock的下一個指針。 ACL字符串是由一組全局指針指向的,例如:

    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等保護機制。

  8. Reset storeblocks and retrieve the ACL storeblock
    現在,ACL存儲塊位于鏈接列表鏈中。 一旦smtp_reset()被觸發,它將被釋放,然后我們可以通過分配多個塊來再次檢索它。
  9. Overwrite ACL strings and trigger ACL check
    最后,我們覆蓋包含ACL字符串的整個塊。 現在我們發送諸如EHLO,MAIL,RCPT等命令來觸發ACL檢查。 一旦我們觸及配置中定義的acl,我們就可以實現遠程代碼執行。

原文:

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/

上一篇:解密美國駐古巴使館遭遇的聲波攻擊

下一篇:Encryption 101:一個惡意軟件分析師的入門書