Skip to content
Browse files

Better IP spoofing support (udpraw and icmp)

- [client] Added '-P udpraw' to allow the client to send SPA packets over
  UDP with a spoofed source IP address.  This is in addition to the
  original 'tcpraw' and 'icmp' protocols that also support a spoofed
  source IP.
- [server] Bug fix to accept SPA packets over ICMP if the fwknop client
  is executed with '-P icmp' and the user has the required privileges.
  • Loading branch information...
1 parent bb1743d commit 229a36625b24c01d5883d65586dff7670c467064 @mrash committed
View
6 ChangeLog
@@ -13,6 +13,12 @@ fwknop-2.0.4 (09/20/2012):
been checked in under extras/openbsd/.
- [server] Bug fix to allow GPG_ALLOW_NO_PW to result in not also having
to specify a Rijndael key.
+ - [client] Added '-P udpraw' to allow the client to send SPA packets over
+ UDP with a spoofed source IP address. This is in addition to the
+ original 'tcpraw' and 'icmp' protocols that also support a spoofed
+ source IP.
+ - [server] Bug fix to accept SPA packets over ICMP if the fwknop client
+ is executed with '-P icmp' and the user has the required privileges.
fwknop-2.0.3 (09/03/2012):
- [server] Fernando Arnaboldi from IOActive found several DoS/code
View
2 Makefile.am
@@ -154,6 +154,8 @@ EXTRA_DIST = \
test/conf/fuzzing_source_access.conf \
test/conf/fuzzing_open_ports_access.conf \
test/conf/fuzzing_restrict_ports_access.conf \
+ test/conf/tcp_pcap_filter_fwknopd.conf \
+ test/conf/icmp_pcap_filter_fwknopd.conf \
test/hardening-check \
test/local_spa.key \
test/test-fwknop.pl \
View
4 client/config_init.c
@@ -57,7 +57,9 @@ digest_strtoint(const char *dt_str)
static int
proto_strtoint(const char *pr_str)
{
- if (strcasecmp(pr_str, "udp") == 0)
+ if (strcasecmp(pr_str, "udpraw") == 0)
+ return(FKO_PROTO_UDP_RAW);
+ else if (strcasecmp(pr_str, "udp") == 0)
return(FKO_PROTO_UDP);
else if (strcasecmp(pr_str, "tcpraw") == 0)
return(FKO_PROTO_TCP_RAW);
View
106 client/spa_comm.c
@@ -316,6 +316,105 @@ send_spa_packet_tcp_raw(const char *spa_data, const int sd_len,
#endif /* !WIN32 */
}
+/* Send the SPA data via raw UDP packet.
+*/
+static int
+send_spa_packet_udp_raw(const char *spa_data, const int sd_len,
+ const struct sockaddr_in *saddr, const struct sockaddr_in *daddr,
+ const fko_cli_options_t *options)
+{
+#ifdef WIN32
+ fprintf(stderr,
+ "send_spa_packet_udp_raw: raw packets are not yet supported.\n");
+ return(-1);
+#else
+ int sock, res = 0;
+ char pkt_data[2048] = {0}; /* Should be enough for our purposes */
+
+ struct iphdr *iph = (struct iphdr *) pkt_data;
+ struct udphdr *udph = (struct udphdr *) (pkt_data + sizeof (struct iphdr));
+
+ int hdrlen = sizeof(struct iphdr) + sizeof(struct udphdr);
+
+ /* Values for setsockopt.
+ */
+ int one = 1;
+ const int *so_val = &one;
+
+ if (options->test)
+ {
+ fprintf(stderr,
+ "test mode enabled, SPA packet not actually sent.\n");
+ return res;
+ }
+
+ sock = socket (PF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (sock < 0)
+ {
+ perror("send_spa_packet_udp_raw: create socket: ");
+ return(sock);
+ }
+
+ /* Put the spa data in place.
+ */
+ memcpy((pkt_data + hdrlen), spa_data, sd_len);
+
+ /* Construct our own header by filling in the ip/udp header values,
+ * starting with the IP header values.
+ */
+ iph->ihl = 5;
+ iph->version = 4;
+ iph->tos = 0;
+ /* Total size is header plus payload */
+ iph->tot_len = hdrlen + sd_len;
+ /* The value here does not matter */
+ iph->id = random() & 0xffff;
+ iph->frag_off = 0;
+ iph->ttl = 255;
+ iph->protocol = IPPROTO_UDP;
+ iph->check = 0;
+ iph->saddr = saddr->sin_addr.s_addr;
+ iph->daddr = daddr->sin_addr.s_addr;
+
+ /* Now the UDP header values.
+ */
+ udph->source = saddr->sin_port;
+ udph->dest = daddr->sin_port;
+ udph->check = 0;
+ udph->len = sd_len + sizeof(struct udphdr);
+
+ /* No we can compute our checksum.
+ */
+ iph->check = chksum((unsigned short *)pkt_data, iph->tot_len);
+
+ /* Make sure the kernel knows the header is included in the data so it
+ * doesn't try to insert its own header into the packet.
+ */
+ if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, so_val, sizeof(one)) < 0)
+ perror("send_spa_packet_udp_raw: setsockopt HDRINCL: ");
+
+ res = sendto (sock, pkt_data, iph->tot_len, 0,
+ (struct sockaddr *)daddr, sizeof(*daddr));
+
+ if(res < 0)
+ {
+ perror("send_spa_packet_udp_raw: sendto error: ");
+ }
+ else if(res != sd_len + hdrlen) /* account for the header ?*/
+ {
+ fprintf(stderr,
+ "[#] Warning: bytes sent (%i) not spa data length (%i).\n",
+ res, sd_len
+ );
+ }
+
+ close(sock);
+
+ return(res);
+
+#endif /* !WIN32 */
+}
+
/* Send the SPA data via ICMP packet.
*/
static int
@@ -378,7 +477,7 @@ send_spa_packet_icmp(const char *spa_data, const int sd_len,
/* Now the ICMP header values.
*/
- icmph->type = ICMP_ECHOREPLY; /* Make it an echo reply */
+ icmph->type = ICMP_ECHO; /* Make it an echo reply */
icmph->code = 0;
icmph->checksum = 0;
@@ -556,6 +655,7 @@ send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options)
res = send_spa_packet_http(spa_data, sd_len, options);
}
else if (options->spa_proto == FKO_PROTO_TCP_RAW
+ || options->spa_proto == FKO_PROTO_UDP_RAW
|| options->spa_proto == FKO_PROTO_ICMP)
{
memset(&saddr, 0, sizeof(saddr));
@@ -597,6 +697,10 @@ send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options)
{
res = send_spa_packet_tcp_raw(spa_data, sd_len, &saddr, &daddr, options);
}
+ else if (options->spa_proto == FKO_PROTO_UDP_RAW)
+ {
+ res = send_spa_packet_udp_raw(spa_data, sd_len, &saddr, &daddr, options);
+ }
else
{
res = send_spa_packet_icmp(spa_data, sd_len, &saddr, &daddr, options);
View
1 common/common.h
@@ -89,6 +89,7 @@
enum {
FKO_PROTO_UDP,
+ FKO_PROTO_UDP_RAW,
FKO_PROTO_TCP,
FKO_PROTO_TCP_RAW,
FKO_PROTO_ICMP,
View
10 doc/fwknop.man.asciidoc
@@ -240,11 +240,11 @@ SPA OPTIONS
over UDP port 62201.
*-P, --server-proto*='<protocol>'::
- Set the protocol (udp, tcp, http, tcpraw, or icmp) for the outgoing SPA
- packet. Note: The *tcpraw* and *icmp* modes use raw sockets and thus
- require root access to run. Also note: The *tcp* mode expects to establish
- a TCP connection to the server before sending the SPA packet. This is
- not normally done, but is useful for compatibility with the Tor for
+ Set the protocol (udp, tcp, http, udpraw, tcpraw, or icmp) for the outgoing
+ SPA packet. Note: The *udpraw*, *tcpraw*, and *icmp* modes use raw sockets
+ and thus require root access to run. Also note: The *tcp* mode expects to
+ establish a TCP connection to the server before sending the SPA packet.
+ This is not normally done, but is useful for compatibility with the Tor for
strong anonymity; see 'http://tor.eff.org/'. In this case, the
*fwknopd* server will need to be configured to listen on the target TCP
port (which is 62201 by default).
View
15 server/process_packet.c
@@ -47,6 +47,7 @@ process_packet(unsigned char *args, const struct pcap_pkthdr *packet_header,
struct iphdr *iph_p;
struct tcphdr *tcph_p;
struct udphdr *udph_p;
+ struct icmphdr *icmph_p;
unsigned char *pkt_data;
unsigned short pkt_data_len;
@@ -58,8 +59,8 @@ process_packet(unsigned char *args, const struct pcap_pkthdr *packet_header,
unsigned int src_ip;
unsigned int dst_ip;
- unsigned short src_port;
- unsigned short dst_port;
+ unsigned short src_port = 0;
+ unsigned short dst_port = 0;
unsigned short eth_type;
@@ -165,6 +166,16 @@ process_packet(unsigned char *args, const struct pcap_pkthdr *packet_header,
pkt_data = ((unsigned char*)(udph_p + 1));
pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p);
}
+ else if (proto == IPPROTO_ICMP)
+ {
+ /* Process ICMP packet
+ */
+ icmph_p = (struct icmphdr*)((unsigned char*)iph_p + (ip_hdr_words << 2));
+
+ pkt_data = ((unsigned char*)(icmph_p + 1));
+ pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p);
+ }
+
else
return;
View
5 test/conf/icmp_pcap_filter_fwknopd.conf
@@ -0,0 +1,5 @@
+#
+# The default fwknopd.conf contains only comments since defaults are defined in
+# code and modified via the config file
+#
+PCAP_FILTER icmp;
View
5 test/conf/tcp_pcap_filter_fwknopd.conf
@@ -0,0 +1,5 @@
+#
+# The default fwknopd.conf contains only comments since defaults are defined in
+# code and modified via the config file
+#
+PCAP_FILTER port 62201;
View
50 test/test-fwknop.pl
@@ -35,6 +35,8 @@
'dual_key_access' => "$conf_dir/dual_key_usage_access.conf",
'gpg_access' => "$conf_dir/gpg_access.conf",
'gpg_no_pw_access' => "$conf_dir/gpg_no_pw_access.conf",
+ 'tcp_pcap_filter' => "$conf_dir/tcp_pcap_filter_fwknopd.conf",
+ 'icmp_pcap_filter' => "$conf_dir/icmp_pcap_filter_fwknopd.conf",
'open_ports_access' => "$conf_dir/open_ports_access.conf",
'multi_gpg_access' => "$conf_dir/multi_gpg_access.conf",
'multi_stanza_access' => "$conf_dir/multi_stanzas_access.conf",
@@ -74,6 +76,7 @@
my $non_std_spa_port = 12345;
my $spoof_user = 'testuser';
+my $spoof_ip = '1.2.3.4';
my $cmd_exec_test_file = '/tmp/fwknoptest';
#================== end config ===================
@@ -813,6 +816,53 @@
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
+
+ ### spoof the source IP on the SPA packet
+ {
+ 'category' => 'Rijndael SPA',
+ 'subcategory' => 'client+server',
+ 'detail' => "udpraw spoof src IP (tcp/22 ssh)",
+ 'err_msg' => "could not spoof source IP",
+ 'function' => \&spa_cycle,
+ 'cmdline' => "$default_client_args -P udpraw -Q $spoof_ip",
+ 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
+ "$fwknopdCmd $default_server_conf_args $intf_str",
+ 'fw_rule_created' => $NEW_RULE_REQUIRED,
+ 'fw_rule_removed' => $NEW_RULE_REMOVED,
+ 'server_positive_output_matches' => [qr/SPA\sPacket\sfrom\sIP\:\s$spoof_ip\s/],
+ 'fatal' => $NO
+ },
+ {
+ 'category' => 'Rijndael SPA',
+ 'subcategory' => 'client+server',
+ 'detail' => "tcpraw spoof src IP (tcp/22 ssh)",
+ 'err_msg' => "could not spoof source IP",
+ 'function' => \&spa_cycle,
+ 'cmdline' => "$default_client_args -P tcpraw -Q $spoof_ip",
+ 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
+ "$fwknopdCmd -c $cf{'tcp_pcap_filter'} -a $cf{'def_access'} " .
+ "-d $default_digest_file -p $default_pid_file $intf_str",
+ 'fw_rule_created' => $NEW_RULE_REQUIRED,
+ 'fw_rule_removed' => $NEW_RULE_REMOVED,
+ 'server_positive_output_matches' => [qr/SPA\sPacket\sfrom\sIP\:\s$spoof_ip\s/],
+ 'fatal' => $NO
+ },
+ {
+ 'category' => 'Rijndael SPA',
+ 'subcategory' => 'client+server',
+ 'detail' => "icmp spoof src IP (tcp/22 ssh)",
+ 'err_msg' => "could not spoof source IP",
+ 'function' => \&spa_cycle,
+ 'cmdline' => "$default_client_args -P icmp -Q $spoof_ip",
+ 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
+ "$fwknopdCmd -c $cf{'icmp_pcap_filter'} -a $cf{'def_access'} " .
+ "-d $default_digest_file -p $default_pid_file $intf_str",
+ 'fw_rule_created' => $NEW_RULE_REQUIRED,
+ 'fw_rule_removed' => $NEW_RULE_REMOVED,
+ 'server_positive_output_matches' => [qr/SPA\sPacket\sfrom\sIP\:\s$spoof_ip\s/],
+ 'fatal' => $NO
+ },
+
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',

0 comments on commit 229a366

Please sign in to comment.
Something went wrong with that request. Please try again.