From 0a5c5bf8bf81dabdc7a1dde0ace67217252aa685 Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 18 Dec 2014 17:42:17 +0800 Subject: [PATCH] icmp file transfer --- Icmp-File-Transfer/.gitignore | 2 + Icmp-File-Transfer/ICMP/IcmpApp.py | 73 +++++++++++++++++ Icmp-File-Transfer/ICMP/IcmpPacket.py | 110 ++++++++++++++++++++++++++ Icmp-File-Transfer/ICMP/IcmpSocket.py | 32 ++++++++ Icmp-File-Transfer/ICMP/__init__.py | 0 Icmp-File-Transfer/README | 38 +++++++++ Icmp-File-Transfer/icmp.py | 50 ++++++++++++ 7 files changed, 305 insertions(+) create mode 100644 Icmp-File-Transfer/.gitignore create mode 100644 Icmp-File-Transfer/ICMP/IcmpApp.py create mode 100644 Icmp-File-Transfer/ICMP/IcmpPacket.py create mode 100644 Icmp-File-Transfer/ICMP/IcmpSocket.py create mode 100644 Icmp-File-Transfer/ICMP/__init__.py create mode 100644 Icmp-File-Transfer/README create mode 100755 Icmp-File-Transfer/icmp.py diff --git a/Icmp-File-Transfer/.gitignore b/Icmp-File-Transfer/.gitignore new file mode 100644 index 0000000..b948985 --- /dev/null +++ b/Icmp-File-Transfer/.gitignore @@ -0,0 +1,2 @@ +*.swp +*.pyc diff --git a/Icmp-File-Transfer/ICMP/IcmpApp.py b/Icmp-File-Transfer/ICMP/IcmpApp.py new file mode 100644 index 0000000..bd91cd7 --- /dev/null +++ b/Icmp-File-Transfer/ICMP/IcmpApp.py @@ -0,0 +1,73 @@ +#-*- coding: utf-8 -*- + +# Copyright (C) 2012-2014 Daniel Vidal de la Rubia +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation version 2. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +from IcmpSocket import * +from IcmpPacket import * + + +class IcmpApp (object): + def __init__ (self): + self.socket = IcmpSocket() + self.file = None + + def __enter__ (self): + return self + + def __exit__ (self, type, value, traceback): + if self._file is not None and not self._file.closed: + self._file.closed + + +class IcmpSender (IcmpApp): + + def __init__ (self, file_to_send): + super(IcmpSender, self).__init__() + self._file = open(file_to_send, 'r') + + def send (self, dst_addr): + seq_n = 0 + while True: + data = self._file.read(56) + if not data: + packet = IcmpPacket(ECHO_REQUEST, seq_n=seq_n, payload=data, + code=2) + self.socket.sendto(packet, dst_addr) + break + packet = IcmpPacket(ECHO_REQUEST, seq_n=seq_n, payload=data) + self.socket.sendto(packet, dst_addr) + seq_n += 1 + + + +class IcmpReceiver (IcmpApp): + + def __init__ (self, file_to_receive): + super(IcmpReceiver, self).__init__() + self._file = open(file_to_receive, 'w') + + def receive (self): + buff = [] + while True: + icmp = self.socket.recv() + if icmp.code is 2: break + buff.append((icmp.seq_n, icmp.payload)) + buff.sort() + str_buff = '' + for elem in buff: + str_buff += elem[1] + self._file.write(str_buff) + + diff --git a/Icmp-File-Transfer/ICMP/IcmpPacket.py b/Icmp-File-Transfer/ICMP/IcmpPacket.py new file mode 100644 index 0000000..624c590 --- /dev/null +++ b/Icmp-File-Transfer/ICMP/IcmpPacket.py @@ -0,0 +1,110 @@ +#-*- coding: utf-8 -*- + + +# IcmpPacket: Little library to manage icmp protocol +# Copyright (C) 2012-2014 Daniel Vidal de la Rubia +# +# Based on ping.py package by George Notaras +# http://www.g-loaded.eu/2009/10/30/python-ping/ + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation version 2. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +import os +import struct +import socket + +ECHO_REPLY = 0 +# (...) +ECHO_REQUEST= 8 +# (...) + +ICMP_PACKET_SIZE = 64 +ICMP_PAYLOAD_SIZE = ICMP_PACKET_SIZE - 8 + +class IcmpPacket (object): + + def __init__ (self, type_packet=0, code=0, seq_n=0, payload=0, raw_p=None): + if raw_p : + p = struct.unpack('bbHHh56s', raw_p) + self.type_packet = p[0] + self.code = p[1] + self.checksum = p[2] + self.identifier = p[3] + self.seq_n = p[4] + self.payload = p[5] + else: + self.type_packet = type_packet + self.code = code + self.checksum = 0 + self.identifier = os.getpid() & 0xFFFF + self.seq_n = seq_n + self.payload = payload + + self.packet = None + + header_fmt = 'bbHHh' + payload_fmt = '%ds' % (ICMP_PAYLOAD_SIZE) + packet_fmt = '!' + header_fmt + payload_fmt + + self.packet = struct.pack(packet_fmt, self.type_packet, self.code, + self.checksum, self.identifier, + self.seq_n, str(self.payload)) + self.calcule_checksum() + self.packet = struct.pack(packet_fmt, self.type_packet, self.code, + self.checksum, self.identifier, + self.seq_n, str(self.payload)) + + + def __repr__ (self): + if self.type_packet is ECHO_REPLY: + type_packet = 'ECHO_REPLY' + elif self.type_packet is ECHO_REQUEST: + type_packet = 'ECHO_REQUEST' + else: + print "TODO: aƱadir moar tipos: %d" % (self.type_packet) + type_packet = 'NOT_DEFINED_BY_IcmpPacket' + + return "ICMP "+ type_packet +" seq:" + str(self.seq_n) +" payload:" +\ + self.payload + + + def calcule_checksum (self): + """ + I'm not too confident that this is right but testing seems + to suggest that it gives the same answers as in_cksum in ping.c + """ + sum = 0 + countTo = (len(self.packet)/2)*2 + count = 0 + while count> 16) + (sum & 0xffff) + sum = sum + (sum >> 16) + answer = ~sum + answer = answer & 0xffff + + # Swap bytes. Bugger me if I know why. + answer = answer >> 8 | (answer << 8 & 0xff00) + + self.checksum = answer + diff --git a/Icmp-File-Transfer/ICMP/IcmpSocket.py b/Icmp-File-Transfer/ICMP/IcmpSocket.py new file mode 100644 index 0000000..74bc8ca --- /dev/null +++ b/Icmp-File-Transfer/ICMP/IcmpSocket.py @@ -0,0 +1,32 @@ +#-*- coding: utf-8 -*- + +# Copyright (C) 2012-2014 Daniel Vidal de la Rubia +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation version 2. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +from socket import * +from IcmpPacket import IcmpPacket + +class IcmpSocket (object): + + def __init__ (self): + self.socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP) + + def recv (self): + return IcmpPacket(raw_p=self.socket.recv(1024)[20:]) + + def sendto (self, packet, dst_addr): + self.socket.sendto(packet.packet, (dst_addr,1)) + + + diff --git a/Icmp-File-Transfer/ICMP/__init__.py b/Icmp-File-Transfer/ICMP/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Icmp-File-Transfer/README b/Icmp-File-Transfer/README new file mode 100644 index 0000000..d1117ea --- /dev/null +++ b/Icmp-File-Transfer/README @@ -0,0 +1,38 @@ +Icmp File Transfer -- Send files using ICMP as the transport protocol. (ICMP/IP) + + +USAGE: + icmp.py recv + icmp.py send + + +DESCRIPTION: + Icmp File Transfer is a simple tool to test if a network user can exfiltrate + information without being noticed using ICMP. It uses the data field of the + ICMP ECHO REQUEST packets in order to hide this information. + + +COMMANDS + recv: + Listens for ICMP packets and tries to assemble them into a file and store it + on path. At this point it cannot discern if a received + packet is from a file transmission or not, so if it receives normal ICMP + packets it can fail to assemble the file, this should be fixed on a future + release. + + send: + Reads and sends it to using the ICMP/IP + stack. + + +AUTHOR + Daniel Vidal de la Rubia. + + +BUGS + https://github.com/Vidimensional/Icmp-File-Transfer/issues + + +SEE ALSO + http://vidimensional.wordpress.com/2013/06/21/sending-files-through-icmp/ + diff --git a/Icmp-File-Transfer/icmp.py b/Icmp-File-Transfer/icmp.py new file mode 100755 index 0000000..cb651c2 --- /dev/null +++ b/Icmp-File-Transfer/icmp.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +#-*- coding: utf-8 -*- + +# Copyright (C) 2012-2014 Daniel Vidal de la Rubia +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation version 2. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import sys + +from ICMP.IcmpApp import IcmpSender, IcmpReceiver + + +def show_usage (): + print """ + USAGE: + icmp.py recv + icmp.py send + """ + exit() + + +if __name__ == '__main__': + try: + action = sys.argv[1] + filename = sys.argv[2] + except IndexError: + show_usage() + + if action == 'send': + try: dst_addr = sys.argv[3] + except: show_usage() + + with IcmpSender(filename) as sender: + sender.send(dst_addr) + + elif action == 'recv': + with IcmpReceiver(filename) as receiver: + receiver.receive() + +