Tunelowanie szyfrowanych informacji z wykorzystaniem datagramów protokołu ICMP

Osoby, które zawodowo zajmują się przekazywaniem innym wiedzy o sieci czy bezpieczeństwie sieciowym, prędzej czy później, w toku swojej działalności, uświadamiają sobie potrzebę posiadania narzędzi niezbędnych, by pozwolić swoim uczniom tak naprawdę „dotknąć” sieci i organoleptycznie doświadczyć, jak działają poszczególne protokoły sieciowe. Na slajdach prezentacji, ramki, pakiety, datagramy, segmenty i inne protokołowe jednostki danych, nie wzbudzają przeważnie dreszczyków emocji – ot bity, bajty, pola nagłówków, flagi i nic więcej. Oczywiście, w celu zwizualizowania pakietów protokołów sieciowych można posłużyć się gotowym oprogramowaniem, na przykład snifferem, choćby Wiresharkiem czy TCPDumpem, ale o wiele lepszą zabawą jest stworzenie własnych narzędzi. Wystarczy w tym celu odrobina wiedzy programistycznej i chęć jej pogłębiania metodą – dla mnie osobiście – bardzo przyjemnych ćwiczeń.

Sami możemy pisać generatory pakietów czy sniffery, a nawet – razie potrzeby – eksploity.

Artykuł powstał jako komentarz do napisanego przez mnie skryptu, służącego do tunelowania szyfrowanego ruchu w segmentach danych datagramów protokołu ICMP. Możemy przy pomocy tego właśnie skryptu przeczytać zawartość tekstowego pliku z danymi, a następnie wiersz po wierszu spakować odczytane dane w pakiety ICMP i skierować je do dowolnego adresu IP. Przed takim „zapakowaniem” danych, możemy je poddać szyfrowaniu, do wyboru mając w tym celu algorytmy 3DES, AES z kluczem 256 bitowym i Blowfish, by zapobiec ich „podsłuchowi” czy przejęciu przez sniffery sieciowe na ścieżce transmisji. Jeśli nie zależy nam na szyfrowaniu tunelowanych danych, możemy wybrać opcję ‘plaintext’, co oczywiście oznacza brak szyfrowania.

Image

Oprócz wysłania w opisany sposób „spreparowanych” pakietów, mamy możliwość skorzystania jeszcze z dwóch opcji ich prezentacji: na konsoli komputera albo w postaci pliku PCAP. Jeśli zdecydujemy się na pierwszą z opcji, otrzymamy na konsoli znakowej pakiety zakodowane w systemie Base64. Opcja druga daje nam plik, który możemy innym narzędziem skryptowym lub na przykład snifferem wstrzyknąć do sieci z takim samym skutkiem, jakbyśmy to zrobili od razu wysyłając pakiety do interfejsu sieciowego.

Na docelowym hoście można „słuchać” tunelowanych pakietów przy pomocy sniffera lub bez trudu napisać własny receptor, stosując w tym celu na przykład, a jakże, skrypt w języku Ruby, oparty o bibliotekę PacketFu. Jeśli u nadawcy zastosowaliśmy szyfrowanie, to rzecz jasna sukces przedsięwzięcia, polegający na odbiorze przetunelowanych danych po stronie odbiorcy, będzie zależał od możliwości ich odszyfrowania. W kodzie skryptu zawarłem również funkcję odszyfrowującą, jako przykład do wykorzystania.

Do opracowania graficznego interfejsu użytkownika wykorzystałem bibliotekę GTK2.

W celu poprawnego uruchomienia skryptu, wymagane jest wcześniejsze zainstalowanie wykorzystanych w nimbibliotek.

gem install gtk2

gem install ezcrypto

gem install ipaddress

gem install packetfu

Napisany przeze mnie skrypt ma charakter poznawczy – uczy, mam nadzieję skutecznie, jak rozwijając zaprezentowane idee i korzystając z bazowych narzędzi oraz bibliotek programistycznych, pisać użyteczne narzędzia do szkoleń, pen-testów i nie tylko w tych celach.

Biblioteka PacketFu pozwala na „fabrykowanie” pakietów, czyli swobodne ich konstruowanie od poziomu pól nagłówka, aż po segment danych. Tym narzędziem możemy tworzyć jednostki danych (PDU – protocol data units) różnych protokołów stosu TCP/IP: od ramek warstwy łącza danych, przez datagramy IP i ICMP, aż po segmenty czy datagramy warstwy transportowej (TCP i UDP). Możemy też konstruować pakiety z „payloadami” czyli segmentami danych przygotowanymi przy pomocy innych, zewnętrznych narzędzi, jak choćby środowisko Metasploit, a w nich kodować nie tylko dane, ale też nagłówki protokołów warstwy sesji, warstwy prezentacji i warstwy aplikacji.

Do zaimplementowania w moim skrypcie (całkiem) silnej kryptografii symetrycznej użyłem funkcji biblioteki ‘ezcrypto’.

Zdaję sobie sprawę z faktu, że skrypt w opublikowanej postaci jest daleki od doskonałości, że można go dodatkowo wzbogacić choćby o walidację pól formularza do pobierania danych wejściowych. Można też popracować nad jego lepszą parametryzacją i interfejsem użytkownika, ale te zmiany zostawiam sobie na później. Zostawiam je też do samodzielnego wykonania drogim czytelnikom mojego artykułu i sympatykom bloga.

Zachęcam oczywiście do zabawy nad dalszym rozwojem skryptu, by na jego podstawie tworzyć inne użyteczne narzędzia. Widzę tu następujące, potencjalnie możliwe, dalsze zastosowania:

  • Skaner podatności;
  • Narzędzie do testów skuteczności i optymalności konfiguracji polityk na firewallach sieciowych oraz list dostępowych na routerach;
  • Narzędzie do testowania reguł na IPS-ach;
  • Narzędzie do przemycania zaciemnionych danych, poza kontrolą sieciowych systemów DLP (oczywiście w celach testowych i poznawczych ;-));
  • Bardzo dobre narzędzia edukacyjne, do wykorzystania na szkoleniach z podstaw teorii protokołów komunikacyjnych i bezpieczeństwa sieci;
  • Narzędzia do przeprowadzania demonstracji mechanizmów takich choćby ataków, jak ataki z wykorzystaniem pofragmentowanych datagramów IP, spoofing ARP i IP, ataki z wykorzystaniem różnych ustawień flag w nagłówku TCP (na przykład ataki klasy low-and-slow DDoS).

Być może pokuszę się o rozwinięcie pierwszego i ostatniego tematu z podanej listy, bo planuję przeprowadzenie w nieodległej przyszłości warsztatów z pisania skryptowych narzędzi wspomagających zarządzanie bezpieczeństwem. Tymczasem życzę miłej i owocnej zabawy ze skryptowaniem i jak zwykle zapraszam do wizyty na moim blogu w przyszłości. Już wkrótce kolejna porcja – mam nadzieję – interesujących informacji.

Kod skryptu jest tutaj:

# -*- 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 = "Simple data tunnelling within ICMP datagrams"

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: