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