diff --git a/include/crypto.h b/include/crypto.h index 25cd45b..b5de0c8 100644 --- a/include/crypto.h +++ b/include/crypto.h @@ -67,18 +67,14 @@ namespace Crypto { /** * */ - template class WEPDecrypter { public: typedef Dot11::address_type address_type; /** - * \brief Constructs a WEPDecrypter from a Functor object. - * - * \param func The functor which will be used to handle decrypted - * packets. + * \brief Constructs a WEPDecrypter object. */ - WEPDecrypter(Functor func); + WEPDecrypter(); /** * \brief Adds a decryption password. @@ -102,104 +98,136 @@ namespace Crypto { * * A Dot11Data PDU is looked up inside the provided PDU chain. * If no such PDU exists or there is no password associated - * with the Dot11 packet's BSSID, then the functor is called - * using the pdu parameter as its argument. + * with the Dot11 packet's BSSID, then the PDU is left intact. * - * Otherwise, the packet is decrypted using the given password - * and the functor is called using the decrypted packet as its - * argument. If the CRC found after decrypting it is invalid, - * then the packet is discarded. + * Otherwise, the packet is decrypted using the given password. + * If the CRC found after decrypting it is invalid, + * then false is returned. * + * \return false if decryption failed due to invalid CRC, true + * otherwise. */ - bool operator()(PDU &pdu); + bool decrypt(PDU &pdu); private: typedef std::map passwords_type; PDU *decrypt(RawPDU &raw, const std::string &password); - Functor functor; passwords_type passwords; std::vector key_buffer; }; + /** + * \brief Pluggable decrypter object which can be used to decrypt + * data on sniffing sessions. + * + * This class holds a decrypter object and a functor, and implements + * a suitable operator() to be used on BaseSniffer::sniff_loop, which + * decrypts packets and forwards them to the given functor. + */ + template + class DecrypterProxy { + public: + /** + * The type of the functor object. + */ + typedef Functor functor_type; + + /** + * The type of the decrypter object. + */ + typedef Decrypter decrypter_type; + + /** + * \brief Constructs an object from a functor and a decrypter. + * \param func The functor to be used to forward decrypted + * packets. + * \param decrypter The decrypter which will be used to decrypt + * packets + */ + DecrypterProxy(const functor_type &func, + const decrypter_type &decr = decrypter_type()); + + /** + * \brief Retrieves a reference to the decrypter object. + */ + decrypter_type &decrypter(); + + /** + * \brief Retrieves a const reference to the decrypter object. + */ + const decrypter_type &decrypter() const; + + /** + * \brief The operator() which decrypts packets and forwards + * them to the functor. + */ + bool operator() (PDU &pdu); + private: + Functor functor_; + decrypter_type decrypter_; + }; + + /** + * \brief Performs RC4 encription/decryption of the given byte range, + * using the provided key. + * + * The decrypted range will be copied to the OutputIterator provided. + * + * \param start The beginning of the range. + * \param start The end of the range. + * \param key The key to be used. + * \param output The iterator in which to write the output. + */ template void rc4(ForwardIterator start, ForwardIterator end, RC4Key &key, OutputIterator output); + /** + * \brief Wrapper function to create DecrypterProxyes using a + * WEPDecrypter as the Decrypter template parameter. + * + * \param functor The functor to be forwarded to the DecrypterProxy + * constructor. + */ + template + DecrypterProxy make_wep_decrypter_proxy(const Functor &functor); // Implementation section - // WEP Decrypter + // DecrypterProxy - template - WEPDecrypter::WEPDecrypter(Functor func) - : functor(func), key_buffer(4) { + template + DecrypterProxy::DecrypterProxy( + const functor_type &func, const decrypter_type& decr) + : functor_(func), decrypter_(decr) + { } - - template - void WEPDecrypter::add_password(const address_type &addr, const std::string &password) { - passwords[addr] = password; - key_buffer.resize(std::max(3 + password.size(), key_buffer.size())); + + template + typename DecrypterProxy::decrypter_type & + DecrypterProxy::decrypter() + { + return decrypter_; + } + + template + const typename DecrypterProxy::decrypter_type & + DecrypterProxy::decrypter() const + { + return decrypter_; + } + + template + bool DecrypterProxy::operator() (PDU &pdu) + { + return decrypter_.decrypt(pdu) ? functor_(pdu) : true; } template - void WEPDecrypter::remove_password(const address_type &addr) { - passwords.erase(addr); - } - - template - bool WEPDecrypter::operator() (PDU &pdu) { - Dot11Data *dot11 = pdu.find_pdu(); - if(dot11) { - RawPDU *raw = dot11->find_pdu(); - if(raw) { - address_type addr; - if(!dot11->from_ds() && !dot11->to_ds()) - addr = dot11->addr3(); - else if(!dot11->from_ds() && dot11->to_ds()) - addr = dot11->addr1(); - else if(dot11->from_ds() && !dot11->to_ds()) - addr = dot11->addr2(); - else - // ???? - addr = dot11->addr3(); - passwords_type::iterator it = passwords.find(addr); - if(it != passwords.end()) { - dot11->inner_pdu(decrypt(*raw, it->second)); - // Invalid WEP packet(CRC check failed). Skip it. - if(!dot11->inner_pdu()) - return true; - } - } - } - return functor(pdu); - } - - template - PDU *WEPDecrypter::decrypt(RawPDU &raw, const std::string &password) { - RawPDU::payload_type &pload = raw.payload(); - // We require at least the IV, the encrypted checksum and something to decrypt - if(pload.size() <= 8) - return 0; - std::copy(pload.begin(), pload.begin() + 3, key_buffer.begin()); - std::copy(password.begin(), password.end(), key_buffer.begin() + 3); - - // Generate the key - RC4Key key(key_buffer.begin(), key_buffer.begin() + password.size() + 3); - rc4(pload.begin() + 4, pload.end(), key, pload.begin()); - uint32_t crc = Utils::crc32(&pload[0], pload.size() - 8); - if(pload[pload.size() - 8] != (crc & 0xff) || - pload[pload.size() - 7] != ((crc >> 8) & 0xff) || - pload[pload.size() - 6] != ((crc >> 16) & 0xff) || - pload[pload.size() - 5] != ((crc >> 24) & 0xff)) - return 0; - - try { - return new SNAP(&pload[0], pload.size() - 8); - } - catch(std::runtime_error&) { - return 0; - } + DecrypterProxy make_wep_decrypter_proxy(const Functor &functor) + { + return DecrypterProxy(functor); } // RC4 stuff diff --git a/include/packet_writer.h b/include/packet_writer.h index 83e9a7e..4c21a53 100644 --- a/include/packet_writer.h +++ b/include/packet_writer.h @@ -51,6 +51,7 @@ public: */ enum LinkType { RADIOTAP = DLT_IEEE802_11_RADIO, + DOT11 = DLT_IEEE802_11, ETH2 = DLT_EN10MB }; diff --git a/include/tins.h b/include/tins.h index 9d92c74..bbba0a6 100644 --- a/include/tins.h +++ b/include/tins.h @@ -52,5 +52,6 @@ #include "utils.h" #include "dns.h" #include "tcp_stream.h" +#include "crypto.h" #endif // TINS_TINS_H diff --git a/src/crypto.cpp b/src/crypto.cpp new file mode 100644 index 0000000..735a725 --- /dev/null +++ b/src/crypto.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012, Nasel + * 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 "crypto.h" + +namespace Tins { +namespace Crypto { +WEPDecrypter::WEPDecrypter() +: key_buffer(4) { + +} + +void WEPDecrypter::add_password(const address_type &addr, const std::string &password) { + passwords[addr] = password; + key_buffer.resize(std::max(3 + password.size(), key_buffer.size())); +} + +void WEPDecrypter::remove_password(const address_type &addr) { + passwords.erase(addr); +} + +bool WEPDecrypter::decrypt(PDU &pdu) { + Dot11Data *dot11 = pdu.find_pdu(); + if(dot11) { + RawPDU *raw = dot11->find_pdu(); + if(raw) { + address_type addr; + if(!dot11->from_ds() && !dot11->to_ds()) + addr = dot11->addr3(); + else if(!dot11->from_ds() && dot11->to_ds()) + addr = dot11->addr1(); + else if(dot11->from_ds() && !dot11->to_ds()) + addr = dot11->addr2(); + else + // ???? + addr = dot11->addr3(); + passwords_type::iterator it = passwords.find(addr); + if(it != passwords.end()) { + dot11->inner_pdu(decrypt(*raw, it->second)); + dot11->wep(0); + // Invalid WEP packet(CRC check failed). Skip it. + if(!dot11->inner_pdu()) + return false; + } + } + } + return true; +} + +PDU *WEPDecrypter::decrypt(RawPDU &raw, const std::string &password) { + RawPDU::payload_type &pload = raw.payload(); + // We require at least the IV, the encrypted checksum and something to decrypt + if(pload.size() <= 8) + return 0; + std::copy(pload.begin(), pload.begin() + 3, key_buffer.begin()); + std::copy(password.begin(), password.end(), key_buffer.begin() + 3); + + // Generate the key + RC4Key key(key_buffer.begin(), key_buffer.begin() + password.size() + 3); + rc4(pload.begin() + 4, pload.end(), key, pload.begin()); + uint32_t crc = Utils::crc32(&pload[0], pload.size() - 8); + if(pload[pload.size() - 8] != (crc & 0xff) || + pload[pload.size() - 7] != ((crc >> 8) & 0xff) || + pload[pload.size() - 6] != ((crc >> 16) & 0xff) || + pload[pload.size() - 5] != ((crc >> 24) & 0xff)) + return 0; + + try { + return new SNAP(&pload[0], pload.size() - 8); + } + catch(std::runtime_error&) { + return 0; + } +} +} +} diff --git a/tests/depends.d b/tests/depends.d index 9b12a09..b446d19 100644 --- a/tests/depends.d +++ b/tests/depends.d @@ -111,7 +111,8 @@ src/ipaddress.o: src/ipaddress.cpp ../include/ip_address.h \ ../include/hw_address.h: src/ip.o: src/ip.cpp ../include/ip.h ../include/pdu.h \ ../include/small_uint.h ../include/endianness.h ../include/ip_address.h \ - ../include/pdu_option.h ../include/ip_address.h ../include/utils.h \ + ../include/pdu_option.h ../include/tcp.h ../include/udp.h \ + ../include/icmp.h ../include/ip_address.h ../include/utils.h \ ../include/hw_address.h ../include/ip.h: @@ -126,6 +127,12 @@ src/ip.o: src/ip.cpp ../include/ip.h ../include/pdu.h \ ../include/pdu_option.h: +../include/tcp.h: + +../include/udp.h: + +../include/icmp.h: + ../include/ip_address.h: ../include/utils.h: @@ -213,9 +220,9 @@ src/tcp_stream.o: src/tcp_stream.cpp ../include/tcp_stream.h \ ../include/sniffer.h ../include/pdu.h ../include/ethernetII.h \ ../include/endianness.h ../include/hw_address.h \ ../include/network_interface.h ../include/ip_address.h \ - ../include/radiotap.h ../include/tcp.h ../include/small_uint.h \ - ../include/pdu_option.h ../include/ip.h ../include/tcp.h \ - ../include/utils.h + ../include/radiotap.h ../include/loopback.h ../include/dot11.h \ + ../include/small_uint.h ../include/pdu_option.h ../include/tcp.h \ + ../include/ip.h ../include/tcp.h ../include/utils.h ../include/tcp_stream.h: @@ -235,12 +242,16 @@ src/tcp_stream.o: src/tcp_stream.cpp ../include/tcp_stream.h \ ../include/radiotap.h: -../include/tcp.h: +../include/loopback.h: + +../include/dot11.h: ../include/small_uint.h: ../include/pdu_option.h: +../include/tcp.h: + ../include/ip.h: ../include/tcp.h: @@ -269,6 +280,40 @@ src/utils_test.o: src/utils_test.cpp ../include/utils.h \ ../include/endianness.h: ../include/ip_address.h: +src/wep_decrypt.o: src/wep_decrypt.cpp ../include/crypto.h \ + ../include/dot11.h ../include/pdu.h ../include/endianness.h \ + ../include/hw_address.h ../include/small_uint.h ../include/pdu_option.h \ + ../include/network_interface.h ../include/ip_address.h \ + ../include/utils.h ../include/snap.h ../include/rawpdu.h \ + ../include/radiotap.h ../include/arp.h + +../include/crypto.h: + +../include/dot11.h: + +../include/pdu.h: + +../include/endianness.h: + +../include/hw_address.h: + +../include/small_uint.h: + +../include/pdu_option.h: + +../include/network_interface.h: + +../include/ip_address.h: + +../include/utils.h: + +../include/snap.h: + +../include/rawpdu.h: + +../include/radiotap.h: + +../include/arp.h: src/dot11/ack.o: src/dot11/ack.cpp ../include/dot11.h ../include/pdu.h \ ../include/endianness.h ../include/hw_address.h ../include/small_uint.h \ ../include/pdu_option.h ../include/network_interface.h \ @@ -764,6 +809,35 @@ include/tests/dot11.h: ../include/ip_address.h: ../include/hw_address.h: +../src/crypto.o: ../src/crypto.cpp ../include/crypto.h ../include/dot11.h \ + ../include/pdu.h ../include/endianness.h ../include/hw_address.h \ + ../include/small_uint.h ../include/pdu_option.h \ + ../include/network_interface.h ../include/ip_address.h \ + ../include/utils.h ../include/snap.h ../include/rawpdu.h + +../include/crypto.h: + +../include/dot11.h: + +../include/pdu.h: + +../include/endianness.h: + +../include/hw_address.h: + +../include/small_uint.h: + +../include/pdu_option.h: + +../include/network_interface.h: + +../include/ip_address.h: + +../include/utils.h: + +../include/snap.h: + +../include/rawpdu.h: ../src/dhcp.o: ../src/dhcp.cpp ../include/endianness.h ../include/dhcp.h \ ../include/bootp.h ../include/pdu.h ../include/endianness.h \ ../include/ip_address.h ../include/hw_address.h ../include/pdu_option.h \ @@ -867,7 +941,8 @@ include/tests/dot11.h: ../include/pdu.h ../include/endianness.h ../include/hw_address.h \ ../include/network_interface.h ../include/ip_address.h \ ../include/packet_sender.h ../include/rawpdu.h ../include/ip.h \ - ../include/small_uint.h ../include/pdu_option.h ../include/arp.h + ../include/small_uint.h ../include/pdu_option.h ../include/arp.h \ + ../include/constants.h ../include/ethernetII.h: @@ -892,6 +967,8 @@ include/tests/dot11.h: ../include/pdu_option.h: ../include/arp.h: + +../include/constants.h: ../src/icmp.o: ../src/icmp.cpp ../include/icmp.h ../include/pdu.h \ ../include/endianness.h ../include/rawpdu.h ../include/utils.h \ ../include/ip_address.h ../include/hw_address.h @@ -980,6 +1057,30 @@ include/tests/dot11.h: ../include/endianness.h: +../include/rawpdu.h: +../src/loopback.o: ../src/loopback.cpp ../include/loopback.h \ + ../include/pdu.h ../include/packet_sender.h ../include/ip.h \ + ../include/small_uint.h ../include/endianness.h ../include/ip_address.h \ + ../include/pdu_option.h ../include/llc.h ../include/rawpdu.h + +../include/loopback.h: + +../include/pdu.h: + +../include/packet_sender.h: + +../include/ip.h: + +../include/small_uint.h: + +../include/endianness.h: + +../include/ip_address.h: + +../include/pdu_option.h: + +../include/llc.h: + ../include/rawpdu.h: ../src/network_interface.o: ../src/network_interface.cpp \ ../include/network_interface.h ../include/hw_address.h \ @@ -1083,7 +1184,8 @@ include/tests/dot11.h: ../src/sniffer.o: ../src/sniffer.cpp ../include/sniffer.h \ ../include/pdu.h ../include/ethernetII.h ../include/endianness.h \ ../include/hw_address.h ../include/network_interface.h \ - ../include/ip_address.h ../include/radiotap.h + ../include/ip_address.h ../include/radiotap.h ../include/loopback.h \ + ../include/dot11.h ../include/small_uint.h ../include/pdu_option.h ../include/sniffer.h: @@ -1100,6 +1202,14 @@ include/tests/dot11.h: ../include/ip_address.h: ../include/radiotap.h: + +../include/loopback.h: + +../include/dot11.h: + +../include/small_uint.h: + +../include/pdu_option.h: ../src/tcp.o: ../src/tcp.cpp ../include/tcp.h ../include/pdu.h \ ../include/endianness.h ../include/small_uint.h ../include/pdu_option.h \ ../include/ip.h ../include/ip_address.h ../include/constants.h \ @@ -1130,8 +1240,9 @@ include/tests/dot11.h: ../include/pdu.h ../include/tcp_stream.h ../include/sniffer.h \ ../include/ethernetII.h ../include/endianness.h ../include/hw_address.h \ ../include/network_interface.h ../include/ip_address.h \ - ../include/radiotap.h ../include/tcp.h ../include/small_uint.h \ - ../include/pdu_option.h ../include/ip.h + ../include/radiotap.h ../include/loopback.h ../include/dot11.h \ + ../include/small_uint.h ../include/pdu_option.h ../include/tcp.h \ + ../include/ip.h ../include/rawpdu.h: @@ -1153,12 +1264,16 @@ include/tests/dot11.h: ../include/radiotap.h: -../include/tcp.h: +../include/loopback.h: + +../include/dot11.h: ../include/small_uint.h: ../include/pdu_option.h: +../include/tcp.h: + ../include/ip.h: ../src/udp.o: ../src/udp.cpp ../include/udp.h ../include/pdu.h \ ../include/endianness.h ../include/constants.h ../include/utils.h \ diff --git a/tests/src/pdu.cpp b/tests/src/pdu.cpp new file mode 100644 index 0000000..5d1e6c4 --- /dev/null +++ b/tests/src/pdu.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include "ip.h" +#include "tcp.h" +#include "rawpdu.h" +#include "pdu.h" + +using namespace std; +using namespace Tins; + +class PDUTest : public testing::Test { +public: +}; + +TEST_F(PDUTest, OperatorConcat) { + std::string raw_payload = "Test"; + IP ip = IP("192.168.0.1") / TCP(22, 52) / RawPDU(raw_payload); + EXPECT_EQ(ip.dst_addr(), "192.168.0.1"); + ASSERT_TRUE(ip.inner_pdu()); + TCP *tcp = ip.find_pdu(); + ASSERT_TRUE(tcp); + EXPECT_EQ(tcp->dport(), 22); + EXPECT_EQ(tcp->sport(), 52); + ASSERT_TRUE(tcp->inner_pdu()); + RawPDU *raw = tcp->find_pdu(); + ASSERT_TRUE(raw); + ASSERT_EQ(raw->payload_size(), raw_payload.size()); + EXPECT_TRUE(std::equal(raw_payload.begin(), raw_payload.end(), raw->payload().begin())); +} + diff --git a/tests/src/wep_decrypt.cpp b/tests/src/wep_decrypt.cpp new file mode 100644 index 0000000..0db5399 --- /dev/null +++ b/tests/src/wep_decrypt.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include "crypto.h" +#include "radiotap.h" +#include "arp.h" + +using namespace Tins; + +class WEPDecryptTest : public testing::Test { +public: + static const uint8_t expected_packet[]; +}; + +// packet taken from aircrack's site. + +const uint8_t WEPDecryptTest::expected_packet[] = { + '\x08', 'B', '\x00', '\x00', '\xff', '\xff', '\xff', '\xff', '\xff', + '\xff', '\x00', '\x12', '\xbf', '\x12', '2', ')', '\x00', '\r', 'T', + '\xa1', '\xa0', 'L', '\xe0', '{', '\xcd', '\xd2', ':', '\x00', '\xc5', + '\xe4', '\xb0', '\xc3', '\xea', '\x87', '\xa1', '\xcd', '\x9b', 'K', + '#', '\xf7', '\x07', '`', '\x11', '\xea', '\x0f', '\x8d', '\x89', + '\xfb', '\x14', 'D', '0', '\xab', '\x1b', '\x0b', '\xf4', 'L', '+', + '2', '\x82', '(', '\x81', '%', '\x1e', '=', '\x08', ')', '\x91', ']', + 'X', '7', '\xc2', '\xd2', '\xf7', '\xed', '\xec', '\x86', '\xb6', + '\xd8', 'U', '\xe1', 'f', '\x8b', ']', '\xb2', '\xd6', '\x9a' +}; + +TEST_F(WEPDecryptTest, Decrypt1) { + Dot11Data dot11(expected_packet, sizeof(expected_packet)); + Crypto::WEPDecrypter decrypter; + decrypter.add_password("00:12:bf:12:32:29", "\x1f\x1f\x1f\x1f\x1f"); + + ASSERT_TRUE(decrypter.decrypt(dot11)); + + ARP *arp = dot11.find_pdu(); + ASSERT_TRUE(arp); + EXPECT_EQ(arp->sender_hw_addr(), "00:0e:a6:6b:fb:69"); + EXPECT_EQ(arp->target_hw_addr(), "00:00:00:00:00:00"); + EXPECT_EQ(arp->sender_ip_addr(), "172.16.0.1"); + EXPECT_EQ(arp->target_ip_addr(), "172.16.0.240"); + + decrypter.add_password("00:12:bf:12:32:29", "\x1f\x1f\x1f\x1f\x1e"); + EXPECT_FALSE(decrypter.decrypt(dot11)); +}