Lecture Overview
In this lecture, we will take a look at TCP session hijacking attacks. One
challenging part when we launch this attack is figuring out the TCP sequence
numbers. So we will cover this topic too.
Telnet Session Hijacking
Telnet is not secure
- Telnet doesn't provide confidentiality (no encryption) nor integrity (no
MAC check). In other words, all user commands and replies from the server are
just sent over the network in the bare form.
- Indeed, we will show how to hijack a Telnet session. So, you should not use
the protocol.
- A secure replacement of Telnet is SSH (secure shell).
How the attack works
Consider the following scenario:
- Alice logs in the server using the Telnet service.
- Now, what will happen if an attacker does the following?
- Send a fake TCP packet into the telnet session between Alice and the
server.
- The command is "create a reverse shell to me"!
- If this is successful, the attacker can freely use Alice's account. This
session has been hijacked!
In the Lab
In the lab, you will perform this session hijacking attack. How hard should it
be to send a fake TCP packet?
- The answer is "easy"! If you recall a TCP protocol, the only thing that
matters is to make sure that the "sequence number" and "checksum" field are
correct.
How TCP Sequence and Acknowledgement Numbers Work
To see how these numbers work, we will create a simple packet sniffer using
Scapy. This allows us to see the necessary information nicely without being
overwhelmed by huge information from Wireshark.
The pieces of information that we want to see is
- The IP address and port number (source and destination).
- We will filter our all irrelevant packets. We will sniff a simple netcat
chat where the server listens at port 9000. So, we can check whether a given
packet is relevant by seeing if the source (or destination) port number is
9000.
- Whether SYN, ACK, PUSH and/or FIN flags are set.
- The seq number and the ack number
- The actual message (i.e., data payload).
Packet sniffing code
Read the code (and comments) carefully and understand what the code does. You
will need to do something similar in the lab.
#!/usr/bin/python3
# sniff.py
from scapy.all import *
def show_pkt(pkt):
# if port number is not irrelevant, ignore pkt
if 9000 not in (pkt[TCP].sport, pkt[TCP].dport):
return
# print src/dst IP/port
print("\n"+pkt[IP].src + "(" + str(pkt[TCP].sport) + ") -> " +
pkt[IP].dst + "(" + str(pkt[TCP].dport) + "):", end = "")
# print flags (SYN/ACK/FIN) and seq/ack
print(pkt[TCP].flags, " seq=", pkt[TCP].seq, ", ack=", pkt[TCP].ack)
# print the payload (Raw means data payload)
if Raw in pkt:
print(pkt[Raw])
sniff(filter="tcp", prn=show_pkt)
Netcat chats
From 192.168.172.4:
choi@it432a:~/Desktop$ nc -lnv 9000
Listening on 0.0.0.0 9000
Connection received on 192.168.172.6 49178
from c to a
from a to c
|
From 192.168.172.6:
choi@it432c:~/Desktop$ nc 192.168.172.4 9000
from c to a
from a to c
|
Sniffing data
choi@it432a:~/Desktop$ sudo ./sniff.py
192.168.172.6(49178) -> 192.168.172.4(9000):S seq= 3463125348 , ack= 0
192.168.172.4(9000) -> 192.168.172.6(49178):SA seq= 557292906 , ack= 3463125349
192.168.172.6(49178) -> 192.168.172.4(9000):A seq= 3463125349 , ack= 557292907
192.168.172.6(49178) -> 192.168.172.4(9000):PA seq= 3463125349 , ack= 557292907
b'from c to a\n'
192.168.172.4(9000) -> 192.168.172.6(49178):A seq= 557292907 , ack= 3463125361
192.168.172.4(9000) -> 192.168.172.6(49178):PA seq= 557292907 , ack= 3463125361
b'from a to c\n'
192.168.172.6(49178) -> 192.168.172.4(9000):A seq= 3463125361 , ack= 557292919
Notes about how seq/ack numbers work
- It's helpful to think about two virtual arrays.
- C-to-S buffer: One is the client's buffer
to be sent to the server.
- S-to-C buffer: The other is the server's buffer to be sent to the
client.
- The index for the C-to-S buffer is managed through seq number in C-to-S packets and the ack number in S-to-C packets.
- The index for the S-to-C buffer is managed through seq number in S-to-C packets and the ack number in C-to-S packets.
- Three-way handshake:
client server
[SIN] seq = x (random), ack = 0 --->
<--- [SYN/ACK] seq = y (random), ack = x+1
[ACK] seq = x+1, ack = y+1 --->
- Data transfer example:
client server
seq= 3463125349 (12 bytes) --->
[Hey, I am sending 12 bytes starting with index 3463125349]
<----- ack= 3463125361
[I got everything right before index 3463125361.
So, next time you can send data starting with index 3463125361]
[OK, I can clear up the buffer before index 3463125361]
Quick check
Can you figure out what the numbers should be in the blanks? (You will see the answer by dragging the mouse over the blanks).