Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 

# 

# This software is provided under under a slightly modified version 

# of the Apache Software License. See the accompanying LICENSE file 

# for more information. 

# 

import array 

 

from impacket.ImpactPacket import Header, ImpactPacketException, PacketBuffer 

 

class IP6_Extension_Header(Header): 

# --------------------------------- - - - - - - - 

# | Next Header | Header Ext Len | Options 

# --------------------------------- - - - - - - - 

 

HEADER_TYPE_VALUE = -1 

EXTENSION_HEADER_FIELDS_SIZE = 2 

 

EXTENSION_HEADER_DECODER = None 

 

def __init__(self, buffer = None): 

Header.__init__(self, self.get_headers_field_size()) 

self._option_list = [] 

if buffer: 

self.load_header(buffer) 

else: 

self.reset() 

 

def __str__(self): 

header_type = self.get_header_type() 

next_header_value = self.get_next_header() 

header_ext_length = self.get_header_extension_length() 

 

s = "Header Extension Name: " + self.__class__.HEADER_EXTENSION_DESCRIPTION + "\n" 

s += "Header Type Value: " + str(header_type) + "\n" 

s += "Next Header: " + str(next_header_value) + "\n" 

s += "Header Extension Length: " + str(header_ext_length) + "\n" 

s += "Options:\n" 

 

for option in self._option_list: 

option_str = str(option) 

option_str = option_str.split('\n') 

option_str = [(' ' * 4) + s for s in option_str] 

s += '\n'.join(option_str) + '\n' 

 

return s 

 

def load_header(self, buffer): 

self.set_bytes_from_string(buffer[:self.get_headers_field_size()]) 

 

remaining_bytes = (self.get_header_extension_length() + 1) * 8 

remaining_bytes -= self.get_headers_field_size() 

 

buffer = array.array('B', buffer[self.get_headers_field_size():]) 

55 ↛ 56line 55 didn't jump to line 56, because the condition on line 55 was never true if remaining_bytes > len(buffer): 

raise ImpactPacketException("Cannot load options from truncated packet") 

 

while remaining_bytes > 0: 

option_type = buffer[0] 

if option_type == Option_PAD1.OPTION_TYPE_VALUE: 

# Pad1 

self._option_list.append(Option_PAD1()) 

 

remaining_bytes -= 1 

buffer = buffer[1:] 

else: 

# PadN 

# From RFC 2460: For N octets of padding, the Opt Data Len 

# field contains the value N-2, and the Option Data consists 

# of N-2 zero-valued octets. 

option_length = buffer[1] 

option_length += 2 

 

self._option_list.append(Option_PADN(option_length)) 

 

remaining_bytes -= option_length 

buffer = buffer[option_length:] 

 

def reset(self): 

pass 

 

@classmethod 

def get_header_type_value(cls): 

return cls.HEADER_TYPE_VALUE 

 

@classmethod 

def get_extension_headers(cls): 

header_types = {} 

for subclass in cls.__subclasses__(): 

subclass_header_types = subclass.get_extension_headers() 

if not subclass_header_types: 

# If the subclass did not return anything it means 

# that it is a leaf subclass, so we take its header 

# type value 

header_types[subclass.get_header_type_value()] = subclass 

else: 

# Else we extend the list of the obtained types 

header_types.update(subclass_header_types) 

return header_types 

 

@classmethod 

def get_decoder(cls): 

raise RuntimeError("Class method %s.get_decoder must be overridden." % cls) 

 

def get_header_type(self): 

return self.__class__.get_header_type_value() 

 

def get_headers_field_size(self): 

return IP6_Extension_Header.EXTENSION_HEADER_FIELDS_SIZE 

 

def get_header_size(self): 

header_size = self.get_headers_field_size() 

for option in self._option_list: 

header_size += option.get_len() 

return header_size 

 

def get_next_header(self): 

return self.get_byte(0) 

 

def get_header_extension_length(self): 

return self.get_byte(1) 

 

def set_next_header(self, next_header): 

self.set_byte(0, next_header & 0xFF) 

 

def set_header_extension_length(self, header_extension_length): 

self.set_byte(1, header_extension_length & 0xFF) 

 

def add_option(self, option): 

self._option_list.append(option) 

 

def get_options(self): 

return self._option_list 

 

def get_packet(self): 

data = self.get_data_as_string() 

 

# Update the header length 

self.set_header_extension_length(self.get_header_size() // 8 - 1) 

 

# Build the entire extension header packet 

header_bytes = self.get_buffer_as_string() 

for option in self._option_list: 

header_bytes += option.get_buffer_as_string() 

 

if data: 

return header_bytes + data 

else: 

return header_bytes 

 

def contains(self, aHeader): 

Header.contains(self, aHeader) 

if isinstance(aHeader, IP6_Extension_Header): 

self.set_next_header(aHeader.get_header_type()) 

 

def get_pseudo_header(self): 

# The pseudo-header only contains data from the IPv6 header. 

# So we pass the message to the parent until it reaches it. 

return self.parent().get_pseudo_header() 

 

class Extension_Option(PacketBuffer): 

MAX_OPTION_LEN = 256 

OPTION_TYPE_VALUE = -1 

 

def __init__(self, option_type, size): 

166 ↛ 167line 166 didn't jump to line 167, because the condition on line 166 was never true if size > Extension_Option.MAX_OPTION_LEN: 

raise ImpactPacketException("Option size of % is greater than the maximum of %d" % (size, Extension_Option.MAX_OPTION_LEN)) 

PacketBuffer.__init__(self, size) 

self.set_option_type(option_type) 

 

def __str__(self): 

option_type = self.get_option_type() 

option_length = self.get_option_length() 

 

s = "Option Name: " + str(self.__class__.OPTION_DESCRIPTION) + "\n" 

s += "Option Type: " + str(option_type) + "\n" 

s += "Option Length: " + str(option_length) + "\n" 

 

return s 

 

def set_option_type(self, option_type): 

self.set_byte(0, option_type) 

 

def get_option_type(self): 

return self.get_byte(0) 

 

def set_option_length(self, length): 

self.set_byte(1, length) 

 

def get_option_length(self): 

return self.get_byte(1) 

 

def set_data(self, data): 

self.set_option_length(len(data)) 

option_bytes = self.get_bytes() 

 

option_bytes = self.get_bytes() 

option_bytes[2:2+len(data)] = array.array('B', data) 

self.set_bytes(option_bytes) 

 

def get_len(self): 

return len(self.get_bytes()) 

 

class Option_PAD1(Extension_Option): 

OPTION_TYPE_VALUE = 0x00 # Pad1 (RFC 2460) 

OPTION_DESCRIPTION = "Pad1 Option" 

 

def __init__(self): 

Extension_Option.__init__(self, Option_PAD1.OPTION_TYPE_VALUE, 1) 

 

def get_len(self): 

return 1 

 

class Option_PADN(Extension_Option): 

OPTION_TYPE_VALUE = 0x01 # Pad1 (RFC 2460) 

OPTION_DESCRIPTION = "PadN Option" 

 

def __init__(self, padding_size): 

219 ↛ 220line 219 didn't jump to line 220, because the condition on line 219 was never true if padding_size < 2: 

raise ImpactPacketException("PadN Extension Option must be greater than 2 bytes") 

 

Extension_Option.__init__(self, Option_PADN.OPTION_TYPE_VALUE, padding_size) 

self.set_data(b'\x00' * (padding_size - 2)) 

 

class Basic_Extension_Header(IP6_Extension_Header): 

MAX_OPTIONS_LEN = 256 * 8 

MIN_HEADER_LEN = 8 

MAX_HEADER_LEN = MIN_HEADER_LEN + MAX_OPTIONS_LEN 

 

def __init__(self, buffer = None): 

self.padded = False 

IP6_Extension_Header.__init__(self, buffer) 

 

def reset(self): 

self.set_next_header(0) 

self.set_header_extension_length(0) 

self.add_padding() 

 

def add_option(self, option): 

if self.padded: 

self._option_list.pop() 

self.padded = False 

 

IP6_Extension_Header.add_option(self, option) 

 

self.add_padding() 

 

def add_padding(self): 

required_octets = 8 - (self.get_header_size() % 8) 

250 ↛ 251line 250 didn't jump to line 251, because the condition on line 250 was never true if self.get_header_size() + required_octets > Basic_Extension_Header.MAX_HEADER_LEN: 

raise Exception("Not enough space for the padding") 

 

# Insert Pad1 or PadN to fill the necessary octets 

if 0 < required_octets < 8: 

255 ↛ 256line 255 didn't jump to line 256, because the condition on line 255 was never true if required_octets == 1: 

self.add_option(Option_PAD1()) 

else: 

self.add_option(Option_PADN(required_octets)) 

self.padded = True 

else: 

self.padded = False 

 

class Hop_By_Hop(Basic_Extension_Header): 

HEADER_TYPE_VALUE = 0x00 

HEADER_EXTENSION_DESCRIPTION = "Hop By Hop Options" 

 

@classmethod 

def get_decoder(self): 

from impacket import ImpactDecoder 

return ImpactDecoder.HopByHopDecoder 

 

class Destination_Options(Basic_Extension_Header): 

HEADER_TYPE_VALUE = 0x3c 

HEADER_EXTENSION_DESCRIPTION = "Destination Options" 

 

@classmethod 

def get_decoder(self): 

from impacket import ImpactDecoder 

return ImpactDecoder.DestinationOptionsDecoder 

 

class Routing_Options(IP6_Extension_Header): 

HEADER_TYPE_VALUE = 0x2b 

HEADER_EXTENSION_DESCRIPTION = "Routing Options" 

ROUTING_OPTIONS_HEADER_FIELDS_SIZE = 8 

 

def reset(self): 

self.set_next_header(0) 

self.set_header_extension_length(0) 

self.set_routing_type(0) 

self.set_segments_left(0) 

 

def __str__(self): 

header_type = self.get_header_type() 

next_header_value = self.get_next_header() 

header_ext_length = self.get_header_extension_length() 

routing_type = self.get_routing_type() 

segments_left = self.get_segments_left() 

 

s = "Header Extension Name: " + self.__class__.HEADER_EXTENSION_DESCRIPTION + "\n" 

s += "Header Type Value: " + str(header_type) + "\n" 

s += "Next Header: " + str(next_header_value) + "\n" 

s += "Header Extension Length: " + str(header_ext_length) + "\n" 

s += "Routing Type: " + str(routing_type) + "\n" 

s += "Segments Left: " + str(segments_left) + "\n" 

 

return s 

 

@classmethod 

def get_decoder(self): 

from . import ImpactDecoder 

return ImpactDecoder.RoutingOptionsDecoder 

 

def get_headers_field_size(self): 

return Routing_Options.ROUTING_OPTIONS_HEADER_FIELDS_SIZE 

 

def set_routing_type(self, routing_type): 

self.set_byte(2, routing_type) 

 

def get_routing_type(self): 

return self.get_byte(2) 

 

def set_segments_left(self, segments_left): 

self.set_byte(3, segments_left) 

 

def get_segments_left(self): 

return self.get_byte(3)