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# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 

2# 

3# This software is provided under under a slightly modified version 

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

5# for more information. 

6# 

7import array 

8 

9from impacket.ImpactPacket import Header, ImpactPacketException, PacketBuffer 

10 

11class IP6_Extension_Header(Header): 

12# --------------------------------- - - - - - - - 

13# | Next Header | Header Ext Len | Options 

14# --------------------------------- - - - - - - - 

15 

16 HEADER_TYPE_VALUE = -1 

17 EXTENSION_HEADER_FIELDS_SIZE = 2 

18 

19 EXTENSION_HEADER_DECODER = None 

20 

21 def __init__(self, buffer = None): 

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

23 self._option_list = [] 

24 if buffer: 

25 self.load_header(buffer) 

26 else: 

27 self.reset() 

28 

29 def __str__(self): 

30 header_type = self.get_header_type() 

31 next_header_value = self.get_next_header() 

32 header_ext_length = self.get_header_extension_length() 

33 

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

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

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

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

38 s += "Options:\n" 

39 

40 for option in self._option_list: 

41 option_str = str(option) 

42 option_str = option_str.split('\n') 

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

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

45 

46 return s 

47 

48 def load_header(self, buffer): 

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

50 

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

52 remaining_bytes -= self.get_headers_field_size() 

53 

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

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

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

57 

58 while remaining_bytes > 0: 

59 option_type = buffer[0] 

60 if option_type == Option_PAD1.OPTION_TYPE_VALUE: 

61 # Pad1 

62 self._option_list.append(Option_PAD1()) 

63 

64 remaining_bytes -= 1 

65 buffer = buffer[1:] 

66 else: 

67 # PadN 

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

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

70 # of N-2 zero-valued octets. 

71 option_length = buffer[1] 

72 option_length += 2 

73 

74 self._option_list.append(Option_PADN(option_length)) 

75 

76 remaining_bytes -= option_length 

77 buffer = buffer[option_length:] 

78 

79 def reset(self): 

80 pass 

81 

82 @classmethod 

83 def get_header_type_value(cls): 

84 return cls.HEADER_TYPE_VALUE 

85 

86 @classmethod 

87 def get_extension_headers(cls): 

88 header_types = {} 

89 for subclass in cls.__subclasses__(): 

90 subclass_header_types = subclass.get_extension_headers() 

91 if not subclass_header_types: 

92 # If the subclass did not return anything it means 

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

94 # type value 

95 header_types[subclass.get_header_type_value()] = subclass 

96 else: 

97 # Else we extend the list of the obtained types 

98 header_types.update(subclass_header_types) 

99 return header_types 

100 

101 @classmethod 

102 def get_decoder(cls): 

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

104 

105 def get_header_type(self): 

106 return self.__class__.get_header_type_value() 

107 

108 def get_headers_field_size(self): 

109 return IP6_Extension_Header.EXTENSION_HEADER_FIELDS_SIZE 

110 

111 def get_header_size(self): 

112 header_size = self.get_headers_field_size() 

113 for option in self._option_list: 

114 header_size += option.get_len() 

115 return header_size 

116 

117 def get_next_header(self): 

118 return self.get_byte(0) 

119 

120 def get_header_extension_length(self): 

121 return self.get_byte(1) 

122 

123 def set_next_header(self, next_header): 

124 self.set_byte(0, next_header & 0xFF) 

125 

126 def set_header_extension_length(self, header_extension_length): 

127 self.set_byte(1, header_extension_length & 0xFF) 

128 

129 def add_option(self, option): 

130 self._option_list.append(option) 

131 

132 def get_options(self): 

133 return self._option_list 

134 

135 def get_packet(self): 

136 data = self.get_data_as_string() 

137 

138 # Update the header length 

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

140 

141 # Build the entire extension header packet 

142 header_bytes = self.get_buffer_as_string() 

143 for option in self._option_list: 

144 header_bytes += option.get_buffer_as_string() 

145 

146 if data: 

147 return header_bytes + data 

148 else: 

149 return header_bytes 

150 

151 def contains(self, aHeader): 

152 Header.contains(self, aHeader) 

153 if isinstance(aHeader, IP6_Extension_Header): 

154 self.set_next_header(aHeader.get_header_type()) 

155 

156 def get_pseudo_header(self): 

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

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

159 return self.parent().get_pseudo_header() 

160 

161class Extension_Option(PacketBuffer): 

162 MAX_OPTION_LEN = 256 

163 OPTION_TYPE_VALUE = -1 

164 

165 def __init__(self, option_type, size): 

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

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

168 PacketBuffer.__init__(self, size) 

169 self.set_option_type(option_type) 

170 

171 def __str__(self): 

172 option_type = self.get_option_type() 

173 option_length = self.get_option_length() 

174 

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

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

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

178 

179 return s 

180 

181 def set_option_type(self, option_type): 

182 self.set_byte(0, option_type) 

183 

184 def get_option_type(self): 

185 return self.get_byte(0) 

186 

187 def set_option_length(self, length): 

188 self.set_byte(1, length) 

189 

190 def get_option_length(self): 

191 return self.get_byte(1) 

192 

193 def set_data(self, data): 

194 self.set_option_length(len(data)) 

195 option_bytes = self.get_bytes() 

196 

197 option_bytes = self.get_bytes() 

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

199 self.set_bytes(option_bytes) 

200 

201 def get_len(self): 

202 return len(self.get_bytes()) 

203 

204class Option_PAD1(Extension_Option): 

205 OPTION_TYPE_VALUE = 0x00 # Pad1 (RFC 2460) 

206 OPTION_DESCRIPTION = "Pad1 Option" 

207 

208 def __init__(self): 

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

210 

211 def get_len(self): 

212 return 1 

213 

214class Option_PADN(Extension_Option): 

215 OPTION_TYPE_VALUE = 0x01 # Pad1 (RFC 2460) 

216 OPTION_DESCRIPTION = "PadN Option" 

217 

218 def __init__(self, padding_size): 

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

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

221 

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

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

224 

225class Basic_Extension_Header(IP6_Extension_Header): 

226 MAX_OPTIONS_LEN = 256 * 8 

227 MIN_HEADER_LEN = 8 

228 MAX_HEADER_LEN = MIN_HEADER_LEN + MAX_OPTIONS_LEN 

229 

230 def __init__(self, buffer = None): 

231 self.padded = False 

232 IP6_Extension_Header.__init__(self, buffer) 

233 

234 def reset(self): 

235 self.set_next_header(0) 

236 self.set_header_extension_length(0) 

237 self.add_padding() 

238 

239 def add_option(self, option): 

240 if self.padded: 

241 self._option_list.pop() 

242 self.padded = False 

243 

244 IP6_Extension_Header.add_option(self, option) 

245 

246 self.add_padding() 

247 

248 def add_padding(self): 

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

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

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

252 

253 # Insert Pad1 or PadN to fill the necessary octets 

254 if 0 < required_octets < 8: 

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

256 self.add_option(Option_PAD1()) 

257 else: 

258 self.add_option(Option_PADN(required_octets)) 

259 self.padded = True 

260 else: 

261 self.padded = False 

262 

263class Hop_By_Hop(Basic_Extension_Header): 

264 HEADER_TYPE_VALUE = 0x00 

265 HEADER_EXTENSION_DESCRIPTION = "Hop By Hop Options" 

266 

267 @classmethod 

268 def get_decoder(self): 

269 from impacket import ImpactDecoder 

270 return ImpactDecoder.HopByHopDecoder 

271 

272class Destination_Options(Basic_Extension_Header): 

273 HEADER_TYPE_VALUE = 0x3c 

274 HEADER_EXTENSION_DESCRIPTION = "Destination Options" 

275 

276 @classmethod 

277 def get_decoder(self): 

278 from impacket import ImpactDecoder 

279 return ImpactDecoder.DestinationOptionsDecoder 

280 

281class Routing_Options(IP6_Extension_Header): 

282 HEADER_TYPE_VALUE = 0x2b 

283 HEADER_EXTENSION_DESCRIPTION = "Routing Options" 

284 ROUTING_OPTIONS_HEADER_FIELDS_SIZE = 8 

285 

286 def reset(self): 

287 self.set_next_header(0) 

288 self.set_header_extension_length(0) 

289 self.set_routing_type(0) 

290 self.set_segments_left(0) 

291 

292 def __str__(self): 

293 header_type = self.get_header_type() 

294 next_header_value = self.get_next_header() 

295 header_ext_length = self.get_header_extension_length() 

296 routing_type = self.get_routing_type() 

297 segments_left = self.get_segments_left() 

298 

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

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

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

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

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

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

305 

306 return s 

307 

308 @classmethod 

309 def get_decoder(self): 

310 from . import ImpactDecoder 

311 return ImpactDecoder.RoutingOptionsDecoder 

312 

313 def get_headers_field_size(self): 

314 return Routing_Options.ROUTING_OPTIONS_HEADER_FIELDS_SIZE 

315 

316 def set_routing_type(self, routing_type): 

317 self.set_byte(2, routing_type) 

318 

319 def get_routing_type(self): 

320 return self.get_byte(2) 

321 

322 def set_segments_left(self, segments_left): 

323 self.set_byte(3, segments_left) 

324 

325 def get_segments_left(self): 

326 return self.get_byte(3)