Environment Setup
Sơ đồ mạng:
Container của các host:
Địa chỉ IP và MAC của interface eth0
trên từng host:
Host | IP | MAC |
---|---|---|
M | 10.9.0.105 | 02:42:0a:09:00:69 |
A | 10.9.0.5 | 02:42:0a:09:00:05 |
B | 10.9.0.6 | 02: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:
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:
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
:
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ụ:
Để 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:
Gói tin ARP request gửi đi có các thuộc tính như sau:
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 IPv4 là0x0800
(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ới1
) cho biết rằng đây là gói tin ARP request.hwsrc
vàpsrc
là địa chỉ MAC và IP của bên gửi là host M.hwdst
vàpdst
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:
Có thể thấy:
- Opcode là
'is-at'
(tương ứng với2
) 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.
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:
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:
Host A có thêm một entry như sau vào ARP table:
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:
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:
- Địa chỉ IP của host B đã có trong ARP table của host A.
- Đị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:
ARP table của host A:
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:
ARP table của host A:
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:
Bật tunable arp_accept
lên thì có lỗi như sau:
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:
Gói tin gratuitous ARP được gửi đi có dạng như sau:
Trong trường hợp host A đã có một entry chứa địa chỉ IP của host B trước đó:
Thì chúng ta có thể tạo được entry ở trong ARP table:
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:
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ế:
Sau khi chạy script thì ARP table của host A là:
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:
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:
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ế:
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:
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:
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:
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:
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:
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:
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
:
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:
Gói tin giả mạo mà host M gửi đến host B:
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:
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:
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:
Gói tin giả mạo mà host M gửi cho host B:
Related
Resources
Footnotes
-
xem thêm ARP Cache Poisoning (ARP Spoofing) ↩
-
xem thêm Gratuitous ARP ↩