亚洲日本免费-啊轻点灬太粗太长了三男一女-麻豆av电影在线观看-日韩一级片毛片|www.grbbt.com

CVE2018-6789利用及保護(hù)機(jī)制的繞過

CVE2018-6789是一個off-by-one的漏洞,文章對該漏洞的利用流程進(jìn)行了詳細(xì)的表述。

off-by-one漏洞

??off-by-one意為一個字節(jié)溢出。

棧:

??這里從網(wǎng)上引用一個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;
}


結(jié)合代碼和圖片來看,從代碼可以看到當(dāng)用戶輸入256字節(jié)的數(shù)據(jù),foo函數(shù)調(diào)用strcpy(buf, arg); 執(zhí)行時,foo的EBP的LSB會被覆蓋。從圖中可以看出當(dāng)EBP被一個NULL字節(jié)所覆蓋時,ebp從0xbffff2d8變?yōu)?xbffff200,由于用戶輸入被復(fù)制到該目標(biāo)緩沖區(qū),攻擊者可以控制這個堆棧位置(0xbffff200),因此可以實(shí)現(xiàn)任意代碼執(zhí)行。

堆:

??由于ptmalloc的堆塊驗(yàn)證機(jī)制的不完善,使得即使只有一個字節(jié)的溢出也使堆的off-by-one漏洞變得可利用。簡單舉個例子。
假設(shè)有這樣3個塊:

之后A發(fā)生了off-by-one于是堆結(jié)構(gòu)變成了這個樣子

圖中的紅色區(qū)域我們可以改掉Bblock的大小,使其增加到C,之后我們free掉B,再分配B+C大小的塊,這樣可以間接實(shí)現(xiàn)對CBlock的讀寫。

ACL訪問控制列表

??ACL使Access Control List的縮寫,主要的目的是在提供傳統(tǒng)的owner,group,others的read,write,execute權(quán)限之外的細(xì)部權(quán)限設(shè)定。ACL可以針對單一的使用者,單一的檔案或目錄來進(jìn)行r,w,x的權(quán)限規(guī)范,對于需要特殊權(quán)限的使用狀況非常有幫助。


傳統(tǒng)的Linux下,上面的權(quán)限分配正常但是當(dāng)下面的情況出現(xiàn)時,就出現(xiàn)了問題:

上圖情況出現(xiàn)時,就出現(xiàn)了問題,而這也是ACL所解決的。

OverView

我們在2018年2月5日報(bào)告了Exim的base64解碼函數(shù)中的溢出漏洞,標(biāo)識為CVE-2018-6789。 自從exim第一次發(fā)布以來就存在這個錯誤,因此所有版本都受到影響。 根據(jù)我們的研究,可以利用它來獲得預(yù)授權(quán)遠(yuǎn)程代碼執(zhí)行,并且至少有400,000臺服務(wù)器處于風(fēng)險之中。 補(bǔ)丁版本4.90.1已經(jīng)發(fā)布,我們建議立即升級exim。

Affected

??所有低于4.90.1版本的Exim

One byte overflow in base64 decoding

Vulnerability Analysis
漏洞的成因在b64decode函數(shù)中解碼緩沖區(qū)長度的計(jì)算錯誤:

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字節(jié)的緩沖區(qū)來存儲解碼后的base64數(shù)據(jù)。 但是,當(dāng)輸入不是有效的base64字符串且長度為4n + 3時,exim分配3n + 1,但在解碼時會占用3n + 2個字節(jié)。 這會導(dǎo)致單字節(jié)堆溢出(aka逐個)。

一般來說,這個錯誤是無害的,因?yàn)楸桓采w的通常是未使用的內(nèi)存。 但是,當(dāng)字符串適合某些特定長度時,該字節(jié)會覆蓋一些關(guān)鍵數(shù)據(jù)。 值得注意的是,由于這個字節(jié)是可控的,使得對其利用更加可行。另外,Base64解碼是一個基本功能,因此這個錯誤可以很容易地觸發(fā),導(dǎo)致遠(yuǎn)程代碼執(zhí)行。

Exploitation

為了評估這個錯誤的嚴(yán)重程度,我們開發(fā)了一個針對exim的SMTP守護(hù)進(jìn)程的攻擊。 以下段落描述了用于實(shí)現(xiàn)pre-auth遠(yuǎn)程代碼執(zhí)行的開發(fā)機(jī)制。 為了利用這一個字節(jié)的溢出,我們有必要誘騙內(nèi)存管理機(jī)制。此外在閱讀本節(jié)之前,強(qiáng)烈建議您具有堆漏洞利用的基本知識。

我們的EXP需要一下幾樣?xùn)|西:
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

??首先,我們回顧一下源代碼并搜索有用的內(nèi)存分配。 正如我們在前一篇文章中提到的,exim使用自定義函數(shù)進(jìn)行動態(tài)分配:

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 */

函數(shù)store_free()和store_malloc()直接調(diào)用glibc的malloc()和free()。 Glibc需要一個稍大的(0x10字節(jié))塊,并將其元數(shù)據(jù)存儲在每個分配的第一個0x10字節(jié)(x86-64)中,然后返回?cái)?shù)據(jù)的位置。 下面的插圖描述了塊的結(jié)構(gòu):

元數(shù)據(jù)包括前一個塊的大小(正好在內(nèi)存中的那個),當(dāng)前塊的大小和一些標(biāo)志。 大小的前三位用于存儲標(biāo)志。 在這個例子中,0x81的大小意味著當(dāng)前塊是0x80字節(jié),并且前一個塊正在使用中。
在exim中,大部分被釋放的塊被放入一個雙向鏈表中,稱為unsorted bin。 Glibc根據(jù)標(biāo)志位維護(hù)它為了避免碎片化,Glibc會將相鄰的已被釋放塊合并到一個更大的塊。 對于每個分配請求,glibc都會以FIFO(先進(jìn)先出)順序檢查這些塊,并重新使用這些塊。

針對一些性能問題,exim使用store_get(),store_release(),store_extend()和store_reset()維護(hù)自己的鏈表結(jié)構(gòu)。

storeblocks的主要特點(diǎn)是每塊至少有0x2000字節(jié),這使我們的漏洞利用受到限制。 請注意,storeblock也是數(shù)據(jù)塊。 因此,如果我們查看內(nèi)存,其內(nèi)存結(jié)構(gòu)看起來就像這個樣子:

這里我們列舉出用來部署堆數(shù)據(jù)的函數(shù):

  1. EHLO主機(jī)名
    對于每個EHLO(或HELO)命令,exim將主機(jī)名的指針存儲在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都會分配一個緩沖區(qū)來將其轉(zhuǎn)換為可打印的
    store_get()存儲錯誤消息

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

    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數(shù)據(jù)下的塊應(yīng)該易于釋放和控制。 經(jīng)過多次嘗試,我們發(fā)現(xiàn)sender_host_name是一個不錯的選擇。 我們安排堆布局,為base64數(shù)據(jù)留下一個空閑的塊,高于sender_host_name。我們在sender_host_name之前留下一個空閑快給base64數(shù)據(jù)

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

    塊釋放后后,我們可以使用AUTH檢索它并覆蓋部分重疊的存儲塊。 這里我們使用一種稱為partial write的技巧。 有了這個,我們可以在不破壞ASLR(地址空間布局隨機(jī)化)的情況下修改指針。 我們部分地改變了包含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進(jìn)程開始時根據(jù)配置進(jìn)行初始化設(shè)置。 例如,如果configure中有一行acl_smtp_mail = acl_check_mail,則指針acl_smtp_mail指向字符串a(chǎn)cl_check_mail。 無論何時使用MAIL FROM,exim都會先擴(kuò)展acl_check_mail來執(zhí)行ACL檢查。 在擴(kuò)展時,如果遇到$ {run {cmd}},exim會嘗試執(zhí)行命令,所以只要我們控制ACL字符串,就可以實(shí)現(xiàn)代碼執(zhí)行。 另外,我們不需要直接劫持程序控制流程,因此我們可以輕松地繞過諸如PIE(位置獨(dú)立可執(zhí)行文件),NX等保護(hù)機(jī)制。

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

原文:

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:一個惡意軟件分析師的入門書