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

# 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 

import struct 

 

from impacket import ImpactPacket 

from impacket.ICMP6 import ICMP6 

 

 

class NDP(ICMP6): 

#ICMP message type numbers 

ROUTER_SOLICITATION = 133 

ROUTER_ADVERTISEMENT = 134 

NEIGHBOR_SOLICITATION = 135 

NEIGHBOR_ADVERTISEMENT = 136 

REDIRECT = 137 

 

############################################################################ 

# Append NDP Option helper 

 

def append_ndp_option(self, ndp_option): 

#As NDP inherits ICMP6, it is, in fact an ICMP6 "header" 

#The payload (where all NDP options should reside) is a child of the header 

self.child().get_bytes().extend(ndp_option.get_bytes()) 

 

 

############################################################################ 

@classmethod 

def Router_Solicitation(class_object): 

message_data = struct.pack('>L', 0) #Reserved bytes 

return class_object.__build_message(NDP.ROUTER_SOLICITATION, message_data) 

 

@classmethod 

def Router_Advertisement(class_object, current_hop_limit, 

managed_flag, other_flag, 

router_lifetime, reachable_time, retransmission_timer): 

flag_byte = 0x00 

if (managed_flag): 

flag_byte |= 0x80 

if (other_flag): 

flag_byte |= 0x40 

 

message_data = struct.pack('>BBHLL', current_hop_limit, flag_byte, router_lifetime, reachable_time, retransmission_timer) 

return class_object.__build_message(NDP.ROUTER_ADVERTISEMENT, message_data) 

 

@classmethod 

def Neighbor_Solicitation(class_object, target_address): 

message_data = struct.pack('>L', 0) #Reserved bytes 

message_data += target_address.as_bytes().tostring() 

return class_object.__build_message(NDP.NEIGHBOR_SOLICITATION, message_data) 

 

 

@classmethod 

def Neighbor_Advertisement(class_object, router_flag, solicited_flag, override_flag, target_address): 

flag_byte = 0x00 

if (router_flag): 

flag_byte |= 0x80 

if (solicited_flag): 

flag_byte |= 0x40 

if (override_flag): 

flag_byte |= 0x20 

 

message_data = struct.pack('>BBBB', flag_byte, 0x00, 0x00, 0x00) #Flag byte and three reserved bytes 

message_data += target_address.as_bytes().tostring() 

return class_object.__build_message(NDP.NEIGHBOR_ADVERTISEMENT, message_data) 

 

 

@classmethod 

def Redirect(class_object, target_address, destination_address): 

message_data = struct.pack('>L', 0)# Reserved bytes 

message_data += target_address.as_bytes().tostring() 

message_data += destination_address.as_bytes().tostring() 

return class_object.__build_message(NDP.REDIRECT, message_data) 

 

 

@classmethod 

def __build_message(class_object, type, message_data): 

#Build NDP header 

ndp_packet = NDP() 

ndp_packet.set_type(type) 

ndp_packet.set_code(0) 

 

#Pack payload 

ndp_payload = ImpactPacket.Data() 

ndp_payload.set_data(message_data) 

ndp_packet.contains(ndp_payload) 

 

return ndp_packet 

 

 

 

 

class NDP_Option(): 

#NDP Option Type numbers 

SOURCE_LINK_LAYER_ADDRESS = 1 

TARGET_LINK_LAYER_ADDRESS = 2 

PREFIX_INFORMATION = 3 

REDIRECTED_HEADER = 4 

MTU_OPTION = 5 

 

############################################################################ 

@classmethod 

#link_layer_address must have a size that is a multiple of 8 octets 

def Source_Link_Layer_Address(class_object, link_layer_address): 

return class_object.__Link_Layer_Address(NDP_Option.SOURCE_LINK_LAYER_ADDRESS, link_layer_address) 

 

@classmethod 

#link_layer_address must have a size that is a multiple of 8 octets 

def Target_Link_Layer_Address(class_object, link_layer_address): 

return class_object.__Link_Layer_Address(NDP_Option.TARGET_LINK_LAYER_ADDRESS, link_layer_address) 

 

@classmethod 

#link_layer_address must have a size that is a multiple of 8 octets 

def __Link_Layer_Address(class_object, option_type, link_layer_address): 

option_length = (len(link_layer_address) / 8) + 1 

option_data = array.array("B", link_layer_address).tostring() 

return class_object.__build_option(option_type, option_length, option_data) 

 

@classmethod 

#Note: if we upgraded to Python 2.6, we could use collections.namedtuples for encapsulating the arguments 

#ENHANCEMENT - Prefix could be an instance of IP6_Address  

def Prefix_Information(class_object, prefix_length, on_link_flag, autonomous_flag, valid_lifetime, preferred_lifetime, prefix): 

 

flag_byte = 0x00 

if (on_link_flag): 

flag_byte |= 0x80 

if (autonomous_flag): 

flag_byte |= 0x40 

 

option_data = struct.pack('>BBLL', prefix_length, flag_byte, valid_lifetime, preferred_lifetime) 

option_data += struct.pack('>L', 0) #Reserved bytes 

option_data += array.array("B", prefix).tostring() 

option_length = 4 

return class_object.__build_option(NDP_Option.PREFIX_INFORMATION, option_length, option_data) 

 

 

@classmethod 

def Redirected_Header(class_object, original_packet): 

option_data = struct.pack('>BBBBBB', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)# Reserved bytes 

option_data += array.array("B", original_packet).tostring() 

option_length = (len(option_data) + 4) / 8 

return class_object.__build_option(NDP_Option.REDIRECTED_HEADER, option_length, option_data) 

 

@classmethod 

def MTU(class_object, mtu): 

option_data = struct.pack('>BB', 0x00, 0x00)# Reserved bytes 

option_data += struct.pack('>L', mtu) 

option_length = 1 

return class_object.__build_option(NDP_Option.MTU_OPTION, option_length, option_data) 

 

 

@classmethod 

def __build_option(class_object, type, length, option_data): 

#Pack data 

data_bytes = struct.pack('>BB', type, length) 

data_bytes += option_data 

ndp_option = ImpactPacket.Data() 

ndp_option.set_data(data_bytes) 

 

return ndp_option