Letní škola sítí
Programování vlastních síťových nástrojů od úplných základů
Dnes nepotřebujete být programátoři.
Ukážeme si, jak z Pythonu udělat náš síťový švýcarský nůž.
Proměnná je krabička s názvem, do které si uložíme IP nebo port:
ip_adresa = "192.168.1.1"
port = 80
print(ip_adresa)
print(port)
Po síti nelze posílat obyčejný text, musíme ho převést na bajty!
Předpona b: Přidáme b před uvozovky:
text_bajty = b"Ahoj svete"
Převod textu: "Ahoj".encode()
Kontrola, zda je port otevřený nebo zavřený:
stav = "otevreno"
if stav == "otevreno":
print("Port je dostupný!")
else:
print("Port je zavřený.")
Když chceme zkontrolovat více portů za sebou:
porty = [22, 80, 443]
for p in porty:
print("Testuji port:", p)
Socket je jako telefonní přístroj ve vašem počítači.
socketV Pythonu už je nástroj na sockety vestavěný:
import socket
# Nyní máme přístup k síťovým funkcím!
Řekneme počítači, že chceme standardní síťové spojení (IPv4 + TCP):
import socket
# Vytvoříme spojovací socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
AF_INET = IPv4 adresa | SOCK_STREAM = TCP protokol
Zavoláme funkci connect() s dvojicí (IP, Port):
# Připojíme se na webový server na portu 80
s.connect(("example.com", 80))
print("Úspěšně připojeno!")
Pošleme jednoduchý HTTP požadavek (v bajtech!):
zprava = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
s.sendall(zprava)
Přečteme odpovídající data ze sítě a zavřeme spojení:
# Přečteme maximálně 1024 bajtů
odpoved = s.recv(1024)
print(odpoved.decode())
# Na závěr socket VŽDY zavřeme
s.close()
Všechno dohromady v 6 řádcích kódu:
import socket
s = socket.socket()
s.connect(("example.com", 80))
s.sendall(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
print(s.recv(1024).decode())
s.close()
Server nedvolá ven, ale **čeká na příchozí hovor**.
bind() – Obsadí port na našem počítači.listen() – Zapne přijímač.accept() – Počká, až se někdo připojí.import socket
server = socket.socket()
server.bind(("0.0.0.0", 9999)) # Port 9999
server.listen(1)
print("Server čeká na připojení...")
klient, adresa = server.accept()
print("Připojil se klient z:", adresa)
klient.sendall(b"Vitej na mem serveru!\n")
klient.close()
server.close()
Zkouší postupně porty na cíl a zjišťuje, kde běží služby.
Funguje to tak, že zkusí navázat spojení.
connect_ex()Běžný connect() spadne s chybou, pokud je port zavřený.
connect_ex() vrátí číslo 0, pokud je port OTEVŘENÝ.
Vrátí jiné číslo, pokud je port zavřený.
import socket
s = socket.socket()
vysledek = s.connect_ex(("127.0.0.1", 80))
if vysledek == 0:
print("Port 80 je OTEVŘENÝ!")
else:
print("Port 80 je zavřený.")
s.close()
Pokud počítač neodpovídá, skript by mohl čekat do nekonečna.
Nastavíme časový limit 1 sekundu:
s = socket.socket()
s.settimeout(1.0) # Čekat max 1 sekundu
Spojíme cyklus for a testování portů:
import socket
cil = "127.0.0.1"
porty = [21, 22, 80, 443, 8080]
for port in porty:
s = socket.socket()
s.settimeout(0.5)
if s.connect_ex((cil, port)) == 0:
print(f"[+] Port {port} je OTEVŘENÝ")
s.close()
Chceme vědět, jaký program na otevřeném portu běží!
Služby jako SSH nebo FTP po připojení samy napíší svou verzi (tzv. Banner).
import socket
s = socket.socket()
s.connect(("127.0.0.1", 22))
# Přečteme prvních 100 znaků od serveru
banner = s.recv(100)
print("Na portu 22 běží:", banner.decode())
s.close()
Scapy je jako LEGO stavebnice pro síťové pakety.
Různé vrstvy spojujeme pomocí lomítka /:
from scapy.all import IP, ICMP
# Vytvoříme IP paket mířící na 8.8.8.8
ip_vrstva = IP(dst="8.8.8.8")
# Přidáme ICMP vrstvu (Ping)
paket = ip_vrstva / ICMP()
Použijeme funkci sr1() (Send & Receive 1):
from scapy.all import IP, ICMP, sr1
# Pošleme paket a počkáme na odpověď
odpoved = sr1(IP(dst="8.8.8.8")/ICMP(), timeout=2)
if odpoved:
print("Cíl odpovídá! Doba života TTL:", odpoved.ttl)
else:
print("Cíl neodpovídá.")
Zeptejte se všech počítačů v síti: „Kdo má tuto IP?“
from scapy.all import ARP, Ether, srp
# ARP dotaz na celou lokální síť
dotaz = Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst="192.168.1.0/24")
odpovedi, _ = srp(dotaz, timeout=2)
for odeslano, prijato in odpovedi:
print(prijato.psrc, "->", prijato.hwsrc)
Chcete vidět, co létá po síti? Použijeme sniff():
from scapy.all import sniff
def ukaz_paket(pkt):
print("Odchycen paket:", pkt.summary())
# Odchytí 5 paketů
sniff(count=5, prn=ukaz_paket)
Proč musíme u Scapy psát sudo?
Operační systém chrání síťovou kartu. Nízkoúrovňový přístup k paketům smí dělat jen správce (root).
sudo python3 muj_skript.py
1. Pouze vlastní síť: Skenujeme a testujeme jen na localhost (127.0.0.1) nebo ve vlastní síti.
2. Žádné cizí cíle: Skenování cizích serverů bez povolení je nelegální!
scanner.py.127.0.0.1.socket slouží ke spojení dvou počítačů přes IP a Port.connect_ex() == 0 znamená otevřený port.Scapy staví pakety jako LEGO s operátorem /.