From 8147a2bfb7a4628915992fa1f90ee81177e9e19f Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Sat, 25 May 2013 18:00:20 -0300 Subject: [PATCH] Added RSNHandshakeCapturer class. --- Makefile.am | 2 + Makefile.in | 25 ++++-- include/handshake_capturer.h | 162 +++++++++++++++++++++++++++++++++++ include/tcp_stream.h | 54 ++++++------ include/tins.h | 1 + src/handshake_capturer.cpp | 92 ++++++++++++++++++++ 6 files changed, 300 insertions(+), 36 deletions(-) create mode 100644 include/handshake_capturer.h create mode 100644 src/handshake_capturer.cpp diff --git a/Makefile.am b/Makefile.am index 4e7a82b..ca0adfe 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,6 +13,7 @@ AM_CXXFLAGS = -Wall -pedantic -I@LIBTINS_INCLUDE_DIR@ libtins_la_SOURCES=src/arp.cpp \ src/bootp.cpp \ + src/handshake_capturer.cpp \ src/stp.cpp \ src/pppoe.cpp \ src/crypto.cpp \ @@ -60,6 +61,7 @@ libtins_include_HEADERS = include/internals.h \ include/eapol.h \ include/tcp_stream.h \ include/pppoe.h \ + include/handshake_capturer.h \ include/ipv6.h \ include/icmpv6.h \ include/ieee802_3.h \ diff --git a/Makefile.in b/Makefile.in index 8a0ffcd..0885244 100644 --- a/Makefile.in +++ b/Makefile.in @@ -58,8 +58,9 @@ subdir = . DIST_COMMON = README $(am__configure_deps) $(libtins_include_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/libtins.pc.in $(top_srcdir)/configure \ - $(top_srcdir)/include/config.h.in AUTHORS THANKS TODO \ - config.guess config.sub depcomp install-sh ltmain.sh missing + $(top_srcdir)/include/config.h.in AUTHORS COPYING INSTALL \ + THANKS TODO config.guess config.sub depcomp install-sh \ + ltmain.sh missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ @@ -105,12 +106,13 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" \ LTLIBRARIES = $(lib_LTLIBRARIES) libtins_la_LIBADD = am__dirstamp = $(am__leading_dot)dirstamp -am_libtins_la_OBJECTS = src/arp.lo src/bootp.lo src/stp.lo \ - src/pppoe.lo src/crypto.lo src/dhcp.lo src/dhcpv6.lo \ - src/dns.lo src/dns_record.lo src/dot11.lo src/dot3.lo \ - src/dot1q.lo src/eapol.lo src/ethernetII.lo src/icmp.lo \ - src/icmpv6.lo src/internals.lo src/ip.lo src/ip_address.lo \ - src/ipv6.lo src/ipv6_address.lo src/llc.lo src/loopback.lo \ +am_libtins_la_OBJECTS = src/arp.lo src/bootp.lo \ + src/handshake_capturer.lo src/stp.lo src/pppoe.lo \ + src/crypto.lo src/dhcp.lo src/dhcpv6.lo src/dns.lo \ + src/dns_record.lo src/dot11.lo src/dot3.lo src/dot1q.lo \ + src/eapol.lo src/ethernetII.lo src/icmp.lo src/icmpv6.lo \ + src/internals.lo src/ip.lo src/ip_address.lo src/ipv6.lo \ + src/ipv6_address.lo src/llc.lo src/loopback.lo \ src/network_interface.lo src/packet_sender.lo \ src/packet_writer.lo src/pdu.lo src/radiotap.lo src/rawpdu.lo \ src/rsn_information.lo src/sll.lo src/snap.lo src/sniffer.lo \ @@ -295,6 +297,7 @@ libtins_la_LDFLAGS = -version-info @LIBTINS_VERSION@ AM_CXXFLAGS = -Wall -pedantic -I@LIBTINS_INCLUDE_DIR@ libtins_la_SOURCES = src/arp.cpp \ src/bootp.cpp \ + src/handshake_capturer.cpp \ src/stp.cpp \ src/pppoe.cpp \ src/crypto.cpp \ @@ -342,6 +345,7 @@ libtins_include_HEADERS = include/internals.h \ include/eapol.h \ include/tcp_stream.h \ include/pppoe.h \ + include/handshake_capturer.h \ include/ipv6.h \ include/icmpv6.h \ include/ieee802_3.h \ @@ -477,6 +481,8 @@ src/$(DEPDIR)/$(am__dirstamp): @: > src/$(DEPDIR)/$(am__dirstamp) src/arp.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/bootp.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +src/handshake_capturer.lo: src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) src/stp.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/pppoe.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/crypto.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) @@ -545,6 +551,8 @@ mostlyclean-compile: -rm -f src/eapol.lo -rm -f src/ethernetII.$(OBJEXT) -rm -f src/ethernetII.lo + -rm -f src/handshake_capturer.$(OBJEXT) + -rm -f src/handshake_capturer.lo -rm -f src/icmp.$(OBJEXT) -rm -f src/icmp.lo -rm -f src/icmpv6.$(OBJEXT) @@ -611,6 +619,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/dot3.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/eapol.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/ethernetII.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/handshake_capturer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/icmp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/icmpv6.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/internals.Plo@am__quote@ diff --git a/include/handshake_capturer.h b/include/handshake_capturer.h new file mode 100644 index 0000000..2af5c99 --- /dev/null +++ b/include/handshake_capturer.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2012, Matias Fontanini + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef TINS_HANDSHAKE_CAPTURER_H +#define TINS_HANDSHAKE_CAPTURER_H + +#include +#include +#include +#include "hw_address.h" +#include "eapol.h" + +// .h +namespace Tins { + /** + * \brief Generic EAPOL handshake. + * + * Stores both the client and supplicant addresses, as well as + * all of the EAPOL packets used during the handshake. + */ + template + class EAPOLHandshake { + public: + typedef std::vector container_type; + typedef HWAddress<6> address_type; + + /** + * Constructs an EAPOLHandshake object. + * + * \param client_address The client address. + * \param supplicant_address The supplicant address. + * \param cont The container that holds the EAPOL packets used + * in the handshake. + */ + EAPOLHandshake(const address_type &client_address, + const address_type &supplicant_address, const container_type &cont) + : cl_address_(client_address), suppl_address_(supplicant_address), + handshake_(cont) + { + + } + + /** + * \return const address_type& + */ + const address_type &client_address() const { + return cl_address_; + } + + /** + * \return const address_type& + */ + const address_type &supplicant_address() const { + return suppl_address_; + } + + /** + * \return const container_type& + */ + const container_type &handshake() const { + return handshake_; + } + private: + address_type cl_address_, suppl_address_; + container_type handshake_; + }; + + /** + * The type used to store RSN handshakes. + */ + typedef EAPOLHandshake RSNHandshake; + + /** + * Captures 802.1X RSN handshakes. + */ + class RSNHandshakeCapturer { + public: + /** + * The type of handshakes that will be captured. + */ + typedef RSNHandshake handshake_type; + + /** + * The type in which all of the captured handshakes + * will be stored. + */ + typedef std::vector handshakes_type; + + /** + * \brief Processes a packet. + * + * This will fetch the RSNEAPOL layer, if any, and store + * it in an intermediate storage. When a handshake is + * completed, it will be stored separately. + * + * \sa RSNHandshakeCapturer::handshakes + */ + bool process_packet(const PDU &pdu); + + /** + * \brief Retrieves the completed handshakes. + * + * This will return the handshakes that have been completed + * so far. A handshake is completed when the 4-way handshake + * is captured. + * + * \sa RSNHandshakeCapturer::clear_handshakes + */ + const handshakes_type &handshakes() const { + return completed_handshakes_; + } + + /** + * \brief Clears the completed handshakes. + * + * Since completed handshakes are stored in a std::vector, + * it is advisable to remove all of them once they have been + * processed. + */ + void clear_handshakes() { + completed_handshakes_.clear(); + } + private: + typedef handshake_type::address_type address_type; + typedef handshake_type::container_type eapol_list; + typedef std::map, eapol_list> handshake_map; + + bool do_insert(const handshake_map::key_type &key, const RSNEAPOL *eapol, + size_t expected); + + handshake_map handshakes_; + handshakes_type completed_handshakes_; + }; +} + +#endif // TINS_HANDSHAKE_CAPTURER_H \ No newline at end of file diff --git a/include/tcp_stream.h b/include/tcp_stream.h index 7b81b3c..abfe7d4 100644 --- a/include/tcp_stream.h +++ b/include/tcp_stream.h @@ -345,36 +345,34 @@ void TCPStreamFollower::follow_streams(ForwardIterator start, ForwardIterator en template bool TCPStreamFollower::callback(PDU &pdu, const DataFunctor &data_fun, const EndFunctor &end_fun) { - IP *ip = pdu.find_pdu(); - TCP *tcp = pdu.find_pdu(); - if(ip && tcp) { - TCPStream::StreamInfo info( - ip->src_addr(), ip->dst_addr(), - tcp->sport(), tcp->dport() - ); - sessions_type::iterator it = sessions.find(info); - if(it == sessions.end()) { - std::swap(info.client_addr, info.server_addr); - std::swap(info.client_port, info.server_port); - if((it = sessions.find(info)) == sessions.end()) { - if(tcp->get_flag(TCP::SYN) && !tcp->get_flag(TCP::ACK)) { - sessions.insert( - std::make_pair( - info, - TCPStream(ip, tcp, last_identifier++) - ) - ); - } - return true; + IP &ip = pdu.rfind_pdu(); + TCP &tcp = pdu.rfind_pdu(); + TCPStream::StreamInfo info( + ip.src_addr(), ip.dst_addr(), + tcp.sport(), tcp.dport() + ); + sessions_type::iterator it = sessions.find(info); + if(it == sessions.end()) { + std::swap(info.client_addr, info.server_addr); + std::swap(info.client_port, info.server_port); + if((it = sessions.find(info)) == sessions.end()) { + if(tcp.get_flag(TCP::SYN) && !tcp.get_flag(TCP::ACK)) { + sessions.insert( + std::make_pair( + info, + TCPStream(&ip, &tcp, last_identifier++) + ) + ); } + return true; } - if(it->second.update(ip, tcp)) - data_fun(it->second); - // We're done with this stream - if(it->second.is_finished()) { - end_fun(it->second); - sessions.erase(it); - } + } + if(it->second.update(&ip, &tcp)) + data_fun(it->second); + // We're done with this stream + if(it->second.is_finished()) { + end_fun(it->second); + sessions.erase(it); } return true; } diff --git a/include/tins.h b/include/tins.h index a2d6f06..b410a30 100644 --- a/include/tins.h +++ b/include/tins.h @@ -67,5 +67,6 @@ #include "dhcpv6.h" #include "pppoe.h" #include "stp.h" +#include "handshake_capturer.h" #endif // TINS_TINS_H diff --git a/src/handshake_capturer.cpp b/src/handshake_capturer.cpp new file mode 100644 index 0000000..80e546d --- /dev/null +++ b/src/handshake_capturer.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2012, Matias Fontanini + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "handshake_capturer.h" +#include "dot11.h" + +namespace Tins { + bool RSNHandshakeCapturer::process_packet(const PDU &pdu) { + const RSNEAPOL *eapol = pdu.find_pdu(); + const Dot11Data *dot11 = pdu.find_pdu(); + if(!eapol || !dot11) + return false; + + + std::pair addresses; + if(dot11->to_ds()) { + addresses.first = dot11->addr1(); + addresses.second = dot11->addr2(); + } + else if(dot11->from_ds()) { + addresses.first = dot11->addr2(); + addresses.second = dot11->addr1(); + } + else + return false; + + // 1st + if(eapol->key_t() && eapol->key_ack() && !eapol->key_mic() && !eapol->install()) { + handshakes_[addresses].assign(eapol, eapol + 1); + } + else if(eapol->key_t() && eapol->key_mic() && !eapol->install() && !eapol->key_ack()) { + if(!eapol->secure()) + do_insert(addresses, eapol, 1); + else if(do_insert(addresses, eapol, 3)) { + completed_handshakes_.push_back( + handshake_type( + addresses.first, + addresses.second, + handshakes_[addresses] + ) + ); + handshakes_.erase(addresses); + return true; + } + } + else if(eapol->key_t() && eapol->install() && eapol->key_ack() && eapol->key_mic()) { + do_insert(addresses, eapol, 2); + } + return false; + } + + bool RSNHandshakeCapturer::do_insert(const handshake_map::key_type &key, + const RSNEAPOL *eapol, size_t expected) + { + handshake_map::iterator iter = handshakes_.find(key); + if(iter != handshakes_.end()) { + if(iter->second.size() != expected) + iter->second.clear(); + else { + iter->second.push_back(*eapol); + return true; + } + } + return false; + } +} // namespace Tins; \ No newline at end of file