Tunneling encrypted data using ICMP datagrams

The persons who professionally teach other people about internetworks or network security, sooner or later will realize the need to have some kind of decent tools necessary to allow their students actually „touch” the network and organoleptically experience, how the various network protocols actually work. To be honest, on presentation slides, the frames, packets, datagrams, segments, and other protocol data units usually do not arouse any emotions – just bits, bytes, headers, flags and nothing more. Of course, in order to visualize the network protocol data units, you can use a ready-made tool, such as a sniffer, for instance Wireshark or tcpdump, but much more fun is to create your own toolset. Just for this purpose you need a little bit of programming knowledge and a desire to deepen and broaden it to some extent while – of course – having fun. So, we can develop our own packet generators, network sniffers and even exploits if necessary .

This article was prepared as a comment to my script designed for network traffic tunneling, utilizing ICMP datagrams, with possible encrypted payloads. This script allows you to read data from a text file, and then line by line pack them into the payload of ICMP packets, to ultimately route them to any given IP destination. Before „packaging”, we can apply quite strong encryption to the chunks of data, using 3DES, AES-256 or Blowfish, to prevent them from „eavesdropping” or takeover by network sniffers on the transmission path. If you do not care about data cryptographic protection, you can select the ‚plaintext‚ option as well, which of course means no encryption.

Screenshot

In addition to directly sending „crafted” packets to the network, we can still take advantage of the two other options of data presentation offered by the script: (1) at the computer console or (2) in the form of PCAP file. If you choose the first option, you’ll obtain the Base64 encoded packets directly on the console. The second option results in generating PCAP file, that can be further injected into the network, with the same effect, as if we did so right away, by sending packets directly to the network interface.

On the target host, you can „listen” to the tunneled packets using a sniffer or your own „receptor”, which can be easily developed, using for this purpose, for example also Ruby and PacketFu library. If the sender of the packets applied encryption to them, it is of course necessary to apply decryption on the receiver side. How can it be achieved – the sample decryption function is included in the script code as an example.

The GTK2 library has been used to develop a graphical user interface of the script.

In order to successfully execute the script, some libraries should be installed in advance:

gem install gtk2
gem install ezcrypto
gem install ipaddress
gem install packetfu

I admit that the script has mainly a learning or cognitive significance. I hope that it learns efficiently how to use presented prototypical solutions to develop them to more and more useful tools for training, pen-testing and maybe not only for these purposes.

The core functionality of the script is based on PacketFu library. This library is very useful when you need to „fabricate” for any reason both headers and payloads of protocol data units. With this tool you can create PDUs of different protocol from TCP/IP stack: from the data link layer frames, through IP and ICMP datagrams on the level of network layer, to the transport layer segments or datagrams (TCP and UDP respectively). You can also construct payloads of PDU using other external tools, such as for instance Metasploit, which additionally extend functionality of your scripting tools.

To implement (pretty) strong cryptography in my script I used ‚ezcrypto‚ library functions.

I am aware that for the time being the script is far from perfect, as it used to be with any kind of solutions prototypes. It can be further improved by for instance better data validation implementation, parameterization and improving graphical user interface, but these changes I intentionally left for later. After all, it can also be done by my dear post readers and blog supporters🙂

I encourage you to make the further development of the script, to finally create some tools useful for you. I see the following, potentially possible areas of applications:

  • A vulnerability scanner;
  • A tool for testing the efficiency and optimality of network firewall policies and routers’ access lists configuration;
  • A tool for testing the rules on IPS;
  • A tool for smuggling obfuscated data beyond network-level DLP control;
  • A very good educational tools for use during the training devoted to communication protocols and network security;
  • A tools to demonstrate some type of  attacks mechanisms (for instance attacks utilizing fragmented IP datagrams, ARP and IP spoofing,  attacks using various settings of flags in the TCP header, low-and-slow DDoS attacks);

Perhaps I undertake the development of the first and the last topic from the list, because in the nearest future I plan to carry out a workshops in writing scripts facilitating various security management tasks. Meanwhile, I wish you a lot of fun with scripting and as usual, I invite you to visit my blog in the future. Soon, another bunch of – I hope – interesting information.

The source code of the script is here:

# -*- coding: binary -*-
# (C) Janusz Nawrat - for educational purposes - 2014
require 'gtk2'			# Building graphical user interface
require 'ezcrypto'		# Encryption and decryption
require 'packetfu'		# IP/ICMP/TCP/UDP Packet creation and manipulation routinnes
require 'Base64'		# String encoding
require 'ipaddress'		# Operations on IP addresses in various possible notations

$system_salt = 'Some salt to hash the key'		# Salt to strengthen encryption
$key = ""						# Password for encryption key generation
$network_interfece = 'wlan0'				# Network interface to inject packets into 

def message_box(message)
   dialog = Gtk::Dialog.new("Attention please...!",
      $main_application_window,
      Gtk::Dialog::DESTROY_WITH_PARENT,
      [ Gtk::Stock::OK, Gtk::Dialog::RESPONSE_NONE ])
   dialog.signal_connect('response') { dialog.destroy }
   dialog.vbox.add(Gtk::Label.new(message))
   dialog.show_all
end

# ---------------------------------------------------------------------------------
# Dialogue for opening the file. Returns chosen file name.
# ---------------------------------------------------------------------------------
def pick_the_file(parent, btt)
   filename = ""
   dialog = Gtk::FileChooserDialog.new(
      "Choose the file with text to insert into packets payload ...",
      parent,
      Gtk::FileChooser::ACTION_OPEN,
      nil,
      [ Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL ],
      [ Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT ]
   )
   dialog.signal_connect('response') do |w, r|
      odg = case r
         when Gtk::Dialog::RESPONSE_ACCEPT
            filename = dialog.filename
            btt.label = filename
            "'ACCEPT' (#{r}) button pressed -- filename is {{ #{filename} }}"
         when Gtk::Dialog::RESPONSE_CANCEL;   "'CANCEL' (#{r}) button pressed"
         else; "Undefined response ID; perhaps Close-x? (#{r})"
      end
      puts odg
      dialog.destroy 
   end
   dialog.run
   return filename
end

# ---------------------------------------------------------------------------------
# Encryption of given plaintext using the key dependent from the password provided
# Salt is provided by global variable $system_salt
# Crypto algorithm is given by the parameter provided to the function.
# ---------------------------------------------------------------------------------
def encrypt(alg, password, string)
   begin
      case alg
         when "3des" then key = EzCrypto::Key.with_password(password, $system_salt, :algorithm => 'des3')
         when "aes" then key = EzCrypto::Key.with_password(password, $system_salt, :algorithm => 'aes256')
         when "blowfish" then key = EzCrypto::Key.with_password(password, $system_salt, :algorithm => 'blowfish')
         when "plaintext" then return string
         else key = EzCrypto::Key.with_password(password, $system_salt, :algorithm => 'aes256')
      end
      encrypted_text = key.encrypt64(string)
   rescue => e
      p e.message
      p e.backtrace
   end
   return encrypted_text
end

# ---------------------------------------------------------------------------------
# Decryption of given ciphertext using the key dependent from the password provided
# Salt is provided by global variable $system_salt
# Crypto algorithm is given by the parameter provided to the function.
# ---------------------------------------------------------------------------------
def decrypt(alg, password, cipher)
   begin
      case alg
         when "3des" then key = EzCrypto::Key.with_password(password, $system_salt, :algorithm => 'des3')
         when "aes" then key = EzCrypto::Key.with_password(password, $system_salt, :algorithm => 'aes256')
         when "blowfish" then key = EzCrypto::Key.with_password(password, $system_salt, :algorithm => 'blowfish')
         when "plaintext" then return cipher
         else key = EzCrypto::Key.with_password(password, $system_salt, :algorithm => 'aes256')
      end
      decrypted_text = key.decrypt64(cipher)
   rescue => e
      p e.message
      p e.backtrace
   end
   return decrypted_text
end

# ---------------------------------------------------------------------------------
# Creation of ICMP packet of arbitrary header fields and payload
# Specifying presentation method (PCAP file, screen dump or injection 
# to the network interface). 
# ---------------------------------------------------------------------------------
def create_icmp_packet(src, dest, payload, present='pcap')
   begin
      icmp_pkt = PacketFu::ICMPPacket.new
      icmp_pkt.icmp_type = 8
      icmp_pkt.icmp_code = 0
      icmp_pkt.payload = payload
      icmp_pkt.ip_saddr=src
      icmp_pkt.ip_daddr=dest
      icmp_pkt.recalc
   rescue => e
      puts "Exception: #{e}"
   end
   case present
      when 'pcap'
         File.open('icmp.pcap', 'a+b') do |file| 
            file.write icmp_pkt
         end	
      when 'screen' then puts "#{Base64.encode64(icmp_pkt.to_s())}"
      when 'net' then icmp_pkt.to_w($network_interfece); puts "ICMP datagram #{src} --> #{dest}"
      else puts "Unknown option..."
   end
end

def batch_creating_payload(src, dest, filename, present='pcap')
   begin
      file = File.new(filename, "r")
      while (line = file.gets)
         line = encrypt($alg, $key, line)
         create_icmp_packet(src, dest, line, present)
      end
      file.close
   rescue => e
      puts "Exception: #{e}"
   end
end

window=Gtk::Window.new

window.signal_connect("delete_event") do
   Gtk::main_quit
   false
end

window.border_width = 10

window.title = "(C) Janusz Nawrat - for educational purposes - 2014"

action_button = Gtk::Button.new("Action")
quit_button = Gtk::Button.new("Quit")

label_main = Gtk::Label.new("Simple encrypted data tunnelling within ICMP datagrams")
label_source_addr = Gtk::Label.new("Source IP address:")
entry_source_addr = Gtk::Entry.new
label_dest_address = Gtk::Label.new("Destination IP address:")
entry_dest_addr = Gtk::Entry.new
label_data_file = Gtk::Label.new("Data file name:")
button_file = Gtk::Button.new("Choose file")
label_alg = Gtk::Label.new("Encryption type:")
combo_crypt = Gtk::ComboBox.new

["3DES", "AES-256", "BLOWFISH", "PLAINTEXT"].each do |val|
  combo_crypt.append_text(val)
end

combo_crypt.active = 3; $alg = 'plaintext'

combo_crypt.signal_connect('changed') do
   case combo_crypt.active
      when 0 then $alg = '3des'
      when 1 then $alg = 'aes256'
      when 2 then $alg = 'blowfish'
      when 3 then $alg = 'plaintext'
      else puts "Unknown encryption algorithm..."
   end
end

label_key = Gtk::Label.new("Encryption key:")
entry_key = Gtk::Entry.new

entry_key.signal_connect('changed') do
   $key = entry_key.text
end

label_output = Gtk::Label.new("Output form:")

hbox_output = Gtk::HBox.new(false, 2)

radio_output1 = Gtk::RadioButton.new("PCAP file")
radio_output2 = Gtk::RadioButton.new(radio_output1, "on the screen")
radio_output3 = Gtk::RadioButton.new(radio_output1, "inject to the net interface")
radio_output2.active=(true); $present = 'screen'

radio_output1.signal_connect("toggled") do
   $present = 'pcap'
   radio_output2.active=(false)
   radio_output3.active=(false)
end

radio_output2.signal_connect("toggled") do
   $present = 'screen'
   radio_output1.active=(false)
   radio_output3.active=(false)
end

radio_output3.signal_connect("toggled") do
   $present = 'net'
   radio_output1.active=(false)
   radio_output2.active=(false)
end

hbox_output.pack_start(radio_output1, false, true, 0)
hbox_output.pack_start(radio_output2, false, true, 0)
hbox_output.pack_start(radio_output3, false, true, 0)

separator = Gtk::HSeparator.new
next_separator = Gtk::HSeparator.new

table = Gtk::Table.new(10, 2, true)
options = Gtk::EXPAND|Gtk::FILL

button_file.signal_connect("clicked") do
   $filename = pick_the_file(window, button_file)
end

entry_source_addr.signal_connect('changed') do
	$src = entry_source_addr.text
end

entry_dest_addr.signal_connect('changed') do
   $dest = entry_dest_addr.text
end

unless IPAddress.valid?($src)
   $src = "10.1.1.1"
end

unless IPAddress.valid?($dest)
   $dest = "192.168.1.1"
end

action_button.signal_connect("clicked") do
   batch_creating_payload($src, $dest, $filename, $present)
end

quit_button.signal_connect("clicked") do
   Gtk.main_quit
end

table.attach(label_main, 0, 2, 0, 1, options, options, 0, 0)
table.attach(separator, 0, 2, 1, 2, options, options, 0, 0)

table.attach(label_source_addr, 0, 1, 2, 3, options, options, 0, 0)
table.attach(entry_source_addr, 1, 2, 2, 3, options, options, 0, 0)

table.attach(label_dest_address, 0, 1, 3, 4, options, options, 0, 0)
table.attach(entry_dest_addr, 1, 2, 3, 4, options, options, 0, 0)

table.attach(label_data_file, 0, 1, 4, 5, options, options, 0, 0)
table.attach(button_file, 1, 2, 4, 5, options, options, 0, 0)

table.attach(label_alg, 0, 1, 5, 6, options, options, 0, 0)
table.attach(combo_crypt, 1, 2, 5, 6, options, options, 0, 0)

table.attach(label_key, 0, 1, 6, 7, options, options, 0, 0)
table.attach(entry_key, 1, 2, 6, 7, options, options, 0, 0)

table.attach(label_output, 0, 1, 7, 8, options, options, 0, 0)
table.attach(hbox_output, 1, 2, 7, 8, options, options, 0, 0)

table.attach(action_button, 0, 1, 9, 10, options, options, 0, 0) 
table.attach(quit_button, 1, 2, 9, 10, options, options, 0, 0) 
table.attach(next_separator, 0, 2, 8, 9, options, options, 0 ,0)

window.add(table)

window.signal_connect('delete_event') { false }
window.signal_connect('destroy') { Gtk.main_quit }

window.show_all
Gtk.main

Informacje Janusz Nawrat
Just ordinary man who likes thinking...

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s

TOMASZ WEŁNA

artysta grafik | wykładowca

PRACOWNIA OKO

Szkoła Rysunku Malarstwa i Grafiki DR TOMASZA WEŁNY | KRAKÓW | Plac Matejki 10 | tel 691 81 75 74

Piękno neurobiologii

Blog Jerzego Vetulaniego

Teoria muzyki, zasady muzyki, podstawy muzyki

Teoria muzyki, zasady muzyki, podstawy muzyki - czyli to co każdy amator muzyki wiedzieć powinien :)

Personal Development & Inspirations

Przemyślenia i refleksje, którymi warto się podzielić (blog by Janusz Nawrat)

Business IT Cooperation Platform

Biznes i IT - dwa światy, które muszą współdziałać

%d bloggers like this: