Code ICMP Raw Packet in Python

Posted by Suraj Singh on January 21, 2018 · 13 mins read
hii readers,



In today's tutorial, I am going to tell you about how we can create or write Raw ICMP packet using python struct module.


Introduction

ICMP stands for Internet Control Message Protocol. Icmp protocol is used to provide an error reporting and query management protocol used by various types of Internet Devices like a router.
In simple words, ICMP protocols created to do connection checking, Connection status, Device availability Etc. For Example, With the help of ICMP packet, we can easily find the availability of an IP address into our Network.


How?


Well, To Find The Find the availability of any IP address Into our network. We simply Just need to send an ICMP packet with request codes, IP address and Source IP Address and if that Specific Device contains same IP address will available on our network, it will reply with another ICMP packet that will contain its information. So, With the help of this simple techniques, we can find the availability of any IP in our network but the only condition is, Client need to reply back with ICMP packet. Actually, Almost all device like to reply on ICMP packet but because of security feature, many devices don't reply back.


Format Of ICMP Packet






Requirement


  • Python 2.x Or 3.x
  • Struct Module
  • Pye Project (Only If you want to verify Packet On Wireshark)




Simplest Form Of codes To Make A ICMP Packet


 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class ICMPPacket:
def __init__(self,
icmp_type = ICMP_ECHO_REQUEST,
icmp_code = 0,
icmp_chks = 0,
icmp_id = 1,
icmp_seq = 1,
data ='' ,
):

self.icmp_type = icmp_type
self.icmp_code = icmp_code
self.icmp_chks = icmp_chks
self.icmp_id = icmp_id
self.icmp_seq = icmp_seq
self.data = data
self.raw = None
self.create_icmp_field()

def create_icmp_field(self):
self.raw = struct.pack(ICMP_STRUCTURE_FMT,
self.icmp_type,
self.icmp_code,
self.icmp_chks,
self.icmp_id,
self.icmp_seq,
)

# calculate checksum
self.icmp_chks = self.chksum(self.raw+self.data)

self.raw = struct.pack(ICMP_STRUCTURE_FMT,
self.icmp_type,
self.icmp_code,
self.icmp_chks,
self.icmp_id,
self.icmp_seq,
)

return

def chksum(self, msg):
s = 0 # Binary Sum

# loop taking 2 characters at a time
for i in range(0, len(msg), 2):

a = ord(msg[i])
b = ord(msg[i+1])
s = s + (a+(b << 8))


# One's Complement
s = s + (s >> 16)
s = ~s & 0xffff

return s


Explanation



  • __init__ function to take inputs.
  • create_icmp_feild function to make an ICMP packet structure
  • check_sum function is to calculate packet checksum value






Another Simplest Form To Make ICMP Packet Extractor


 1
2
3
4
5
6
7
8
9
10
11
# ICMP HEADER Extraction
def ext_icmp_header(data):
icmph=struct.unpack(ICMP_STRUCTURE_FMT, data)
data={
'type' : icmph[0],
"code" : icmph[1],
"checksum": icmph[2],
'id' : icmph[3],
'seq' : icmph[4],
}
return data


Complete Codes  (Need Pye Project Scripts To Run it Correctly.



  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# import modules
import struct
import socket
from IP import LoadIP
from Ether import EtherPacket

# Header is type (8), code (8), checksum (16), id (16), sequence (16)
# header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, 0, 0, id, 1)
ICMP_STRUCTURE_FMT = 'bbHHh'
ICMP_ECHO_REQUEST = 8 # Seems to be the same on Solaris.

ICMP_CODE = socket.getprotobyname('icmp')
ERROR_DESCR = {
1: ' - Note that ICMP messages can only be '
'sent from processes running as root.',
10013: ' - Note that ICMP messages can only be sent by'
' users or processes with administrator rights.'
}


class ICMPPacket:
def __init__(self,
icmp_type = ICMP_ECHO_REQUEST,
icmp_code = 0,
icmp_chks = 0,
icmp_id = 1,
icmp_seq = 1,
data ='' ,
):

self.icmp_type = icmp_type
self.icmp_code = icmp_code
self.icmp_chks = icmp_chks
self.icmp_id = icmp_id
self.icmp_seq = icmp_seq
self.data = data
self.raw = None
self.create_icmp_field()

def create_icmp_field(self):
self.raw = struct.pack(ICMP_STRUCTURE_FMT,
self.icmp_type,
self.icmp_code,
self.icmp_chks,
self.icmp_id,
self.icmp_seq,
)

# calculate checksum
self.icmp_chks = self.chksum(self.raw+self.data)

self.raw = struct.pack(ICMP_STRUCTURE_FMT,
self.icmp_type,
self.icmp_code,
self.icmp_chks,
self.icmp_id,
self.icmp_seq,
)

return

def chksum(self, msg):
s = 0 # Binary Sum

# loop taking 2 characters at a time
for i in range(0, len(msg), 2):

a = ord(msg[i])
b = ord(msg[i+1])
s = s + (a+(b << 8))


# One's Complement
s = s + (s >> 16)
s = ~s & 0xffff

return s


# ICMP HEADER Extraction
def ext_icmp_header(data):
icmph=struct.unpack(ICMP_STRUCTURE_FMT, data)
data={
'type' : icmph[0],
"code" : icmph[1],
"checksum": icmph[2],
'id' : icmph[3],
'seq' : icmph[4],
}
return data

def main():
icmp = ICMPPacket()
print ext_icmp_header(icmp.raw)
ip = LoadIP(tcp=icmp, ip_proto=socket.IPPROTO_ICMP)
eth = EtherPacket(data=ip)


try:
from samples.wsk import ShowPacket
pkt = eth.raw +ip.raw+icmp.raw
ShowPacket([pkt], link_type=1)
except Exception as e:
print e
print "[+] Unable To Find pye.samples.wsk script."
return


if __name__=='__main__':
main()



I hope you enjoy this tutorial.

Keep Reading and
have a nice day.