diff --git a/week02/easy/check_interface.py b/week02/easy/check_interface.py new file mode 100644 index 0000000..c3be214 --- /dev/null +++ b/week02/easy/check_interface.py @@ -0,0 +1,17 @@ +import netifaces + + +def print_ethernet_interfaces(): + """Prints all Ethernet interfaces and their IP addresses.""" + + interfaces = netifaces.interfaces() + for interface in interfaces: + addresses = netifaces.ifaddresses(interface) + if netifaces.AF_INET in addresses: + for addr in addresses[netifaces.AF_INET]: + ip_address = addr["addr"] + print(f"Interface: {interface}, IP Address: {ip_address}") + + +if __name__ == "__main__": + print_ethernet_interfaces() diff --git a/week02/easy/client.py b/week02/easy/client.py new file mode 100644 index 0000000..8ed1bc5 --- /dev/null +++ b/week02/easy/client.py @@ -0,0 +1,72 @@ +import hashlib +import logging +import time + +import threading + +from scapy.config import conf +from scapy.layers.inet import TCP, IP +from scapy.packet import Packet +from scapy.sendrecv import send, sniff + +from random import randrange + +log = logging.getLogger(__name__) +TCP_CLIENTS = {} # ((IP, port) -> [sent_packets]) + +# SERVER_IP = '131.159.15.68' # don't use the domain name in this case +SERVER_IP = '192.168.1.4' # don't use the domain name in this case +SERVER_PORT = 20102 +COOKIE_SECRET = 'TASTY_COOKIES123' +INITIAL_SEQ = 1337 +SRC_PORT = randrange(10000, 50000) +first_try = 0 +def generate_syn_cookie(client_ip: str, client_port: int, server_secret: str): + hash_input = f'{client_ip}{client_port}{server_secret}'.encode() + return int(hashlib.sha256(hash_input).hexdigest(), 16) % (2**32) + +def handle_packet(packet: Packet): + # TODO: please implement me! + if packet.haslayer(TCP) and packet[TCP].sport == SERVER_PORT and packet[TCP].dport == SRC_PORT and packet[TCP].flags == "SA": + ip = IP(dst=SERVER_IP) + syn = TCP(sport=SRC_PORT, dport=SERVER_PORT, flags='SA', seq=COOKIE, ack=packet[TCP].seq) + resp = (ip / syn) + send(resp) + packet.show() + +# Function to start the packet sniffing +def start_sniffing(): + sniff( + filter=f'tcp port {SERVER_PORT}', # this should filter all packets relevant for this challenge. + prn=handle_packet, + store=False, + monitor=True, + iface='eth0', # set to your interface. IMPORTANT: SET TO enX0 FOR AUTOGRADER!!! + ) + +COOKIE = generate_syn_cookie(SERVER_IP, SERVER_PORT, COOKIE_SECRET) + +# Run the server in a separate thread +def main(): + conf.use_pcap = False + server_thread = threading.Thread(target=start_sniffing) + server_thread.start() + + time.sleep(1) # wait for the sniffer to start. + + # TODO: send intial first byte + # Create and send SYN packet to initiate the handshake + ip_layer = IP(dst=SERVER_IP) + syn_packet = TCP(sport=SRC_PORT, dport=SERVER_PORT, flags="S", seq=COOKIE) + send(ip_layer / syn_packet) + + +if __name__ == '__main__': + logging.basicConfig( + level=logging.INFO, + format='%(asctime)s %(levelname)s [%(module)s:%(lineno)d] %(message)s', + ) + + logging.getLogger('asyncio').setLevel(logging.WARNING) + + main() diff --git a/week02/easy/description/description.pdf b/week02/easy/description/description.pdf new file mode 100644 index 0000000..1d55630 Binary files /dev/null and b/week02/easy/description/description.pdf differ diff --git a/week02/easy/server.py b/week02/easy/server.py new file mode 100644 index 0000000..784f686 --- /dev/null +++ b/week02/easy/server.py @@ -0,0 +1,127 @@ +import hashlib +import logging +import subprocess + +import threading + +from scapy.config import conf +from scapy.layers.inet import TCP, IP +from scapy.packet import Packet +from scapy.sendrecv import send, sniff + +log = logging.getLogger(__name__) +TCP_CLIENTS = {} # ((IP, port) -> [sent_packets]) + +SERVER_IP = '192.168.1.4' # TODO +SERVER_PORT = 20102 +COOKIE_SECRET = 'TASTY_COOKIES123' +INITIAL_SEQ = 1337 + + +# The cookie is calculated by first taking the sha256 hash of (clientIP || clientPort || serverSecret) and then +# converting the hex digest to an integer +# The cookie is then this result modulo 2^32 to fit the 32-bit field +def generate_syn_cookie(client_ip: str, client_port: int, server_secret: str): + hash_input = f'{client_ip}{client_port}{server_secret}'.encode() + return int(hashlib.sha256(hash_input).hexdigest(), 16) % (2**32) + + +def get_initial_syn(ip, port, ack) -> Packet: + ip = IP(dst=ip) + syn = TCP(sport=SERVER_PORT, dport=port, flags='SA', seq=INITIAL_SEQ, ack=ack) + return ip / syn + + +def get_rst(ip, port, ack) -> Packet: + ip = IP(dst=ip) + syn = TCP(sport=SERVER_PORT, dport=port, flags='R', seq=INITIAL_SEQ, ack=ack) + return ip / syn + + +def handle_packet(packet: Packet): + if packet.haslayer(TCP) and packet[TCP].dport == SERVER_PORT: + if 'F' in packet[TCP].flags or 'R' in packet[TCP].flags: + print('Received FIN or Reset packet:', packet.summary()) + if (packet[IP].src, packet[TCP].sport) in TCP_CLIENTS: + del TCP_CLIENTS[(packet[IP].src, packet[TCP].sport)] + return + + print('Received packet:', packet.summary()) + + # Extract the TCP layer + tcp_layer = packet[TCP] + src_ip = packet[IP].src + src_port = tcp_layer.sport + seq = packet[TCP].seq + ack = packet[TCP].ack + + expected_cookie = generate_syn_cookie(SERVER_IP, SERVER_PORT, COOKIE_SECRET) + + if (src_ip, src_port) not in TCP_CLIENTS: + print('New client:', src_ip, src_port, seq) + # first packet from client to initiate handshake + if (not 'S' in packet[TCP].flags) or (not packet[TCP].seq == expected_cookie): + print(f'Invalid cookie {seq}, expected {expected_cookie}') + rst = get_rst(src_ip, src_port, seq) + send(rst) + else: + TCP_CLIENTS[(src_ip, src_port)] = 1 + initial_syn = get_initial_syn(src_ip, src_port, seq) + + print(f'Cookie {expected_cookie} and packet is correct') + print(f'Sending packet: {initial_syn.summary()}') + send(initial_syn) + + else: + print("i am in this state") + if (0x02 in packet[TCP].flags) or (not seq == expected_cookie) or (not ack == INITIAL_SEQ): + print(f'Invalid cookie {seq}, expected {expected_cookie}') + rst = get_rst(src_ip, src_port, seq) + send(rst) + else: + print(f'Cookie {expected_cookie} and packet is again correct') + + flag = "hello world" + ip = IP(dst=src_ip) + syn_ack = TCP( + sport=SERVER_PORT, + dport=src_port, + flags='A', + seq=ack, + ack=seq, + ) / flag + + send(ip / syn_ack) + + del TCP_CLIENTS[(src_ip, src_port)] + + +# Function to start the packet sniffing +def start_sniffing(): + print('Starting TCP server on port:', SERVER_PORT) + sniff( + filter=f'tcp port {SERVER_PORT}', + prn=handle_packet, + store=False, + monitor=True, + iface='eth0', + ) + + +# Run the server in a separate thread +def main(): + conf.use_pcap = False + server_thread = threading.Thread(target=start_sniffing) + server_thread.start() + + +if __name__ == '__main__': + logging.basicConfig( + level=logging.INFO, + format='%(asctime)s %(levelname)s [%(module)s:%(lineno)d] %(message)s', + ) + + # "INFO:asyncio:poll took 25.960 seconds" is annyoing + logging.getLogger('asyncio').setLevel(logging.WARNING) + + main()