Trang chủTin tứcViết script sử dụng IPTABLES chặn các kết nối SSH sai quá nhiều
Viết script sử dụng IPTABLES chặn các kết nối SSH sai quá nhiều

Bài viết sẽ hướng dẫn bạn cách viết một tập lệnh “script” sử dụng iptables để chặn các kết nối SSH bị lỗi quá nhiều. Tìm hiểu chi tiết ngay sau đây nhé.

IPTABLES là một công cụ cho phép bạn kiểm soát lưu lượng truy cập đến và đi khỏi hệ thống của mình. Bằng cách sử dụng IPTABLES, bạn có thể chặn các địa chỉ IP đã cố gắng kết nối sai quá nhiều lần. Trong hướng dẫn này, chúng tôi sẽ chỉ cho bạn cách viết một script sử dụng IPTABLES để chặn các kết nối SSH sai quá nhiều.

>>> Xem thêm: IPTABLES là gì? Cấu trúc thành phần của IPTABLES và cách sử dụng

Viết script sử dụng IPTABLES chặn các kết nối SSH
Viết script sử dụng IPTABLES chặn các kết nối SSH

1. Tại sao cần chặn các kết nối SSH sai quá nhiều?

Kết nối SSH là một cổng vào quan trọng để quản lý từ xa, nhưng cũng là mục tiêu phổ biến của tấn công Brute Force.

Các hacker có thể thử đăng nhập bằng cách liên tục thử các tên người dùng và mật khẩu khác nhau để xâm nhập vào hệ thống.

Nếu một tình huống Brute Force thành công, hacker có thể lấy được quyền truy cập vào hệ thống. Việc này gây lỗ hổng về bảo mật rất lớn.

Các kết nối SSH sai quá nhiều không chỉ tăng nguy cơ bị tấn công mà còn có thể ảnh hưởng đến hiệu suất hệ thống. Tình trạng này tăng tải cho máy chủ và có thể gây ra sự gián đoạn dịch vụ.

>>> Xem thêm: SSH là gì? Kiến thức tổng hợp về giao thức SSH từ A - Z

2. Mục tiêu đề ra

Cứ 5 phút file sẽ chạy 1 lần để tìm ra danh sách các IP đã SSH thất bại quá 10 lần và đưa nó vào file lưu trữ.

Sử dụng IPTABLES để ban IP nằm trong danh sách đó.

Sử dụng IPTABLES để unban những IP đã quá thời hạn quy định.

Sử dụng Crontab để có thể lập ra chu trình chạy file.

3. Xác định ngưỡng kết nối sai

Tất cả các kết nối SSH dù thành công hay thất bại sẽ nằm ở trong file log và đường dẫn của nó là /var/log/secure đối với Centos. Việc của chúng ta cần làm là lọc các lần đăng nhập ssh thất bại.

Kết nối SSH thất bại
Kết nối SSH thất bại

cat /var/log/secure | grep  "sshd.*Failed password"

Ta nhận ra rằng cần phải dùng lệnh awk để có thể lọc ra các dòng nằm trong khoảng thời gian quy định. Và các trường $1, $2, $3 là các trường chứa thời gian SSH thất bại nên việc ta cần làm là quy đổi các mốc thời gian theo định dạng của trường $1, $2, $3 và kết hợp option -v của lệnh awk làm mốc thời gian so sánh.

Quy đổi các mốc thời gian

current_time=$(date "+%b %d %H:%M:%S")

five_minute_ago=$(date -d '5 minute ago' '+%b %d %H:%M:%S')

Sử dụng hàm awk để so sánh

awk -v start_time="$five_minute_ago" -v end_time="$current_time" '$1 " " $2 " " $3 >= start_time && $1 " " $2 " " $3 <= end_time {print $(NF-3)}'

Từ đây ta mới chỉ tìm ra các IP đã SSH thất bại trong 5 phút. Việc tiếp theo ta cần lọc ra các IP trùng và đưa nó vào bộ đếm sau đó tìm ra IP đã SSH thất bại quá 10 lần trong vòng 5 phút.

sort | uniq -c | awk '$1 > 10 {print $2}'

Kết hợp tất cả lại ta sẽ có danh sách các IP đã SSH thất bại quá 10 lần trong vòng 5 phút. Lưu ý rằng chúng ta phải lưu các danh sách này vào list.

failed_ips=($(grep "sshd.*Failed password" "$LOG_FILE" | awk -v start_time="$five_minute_ago" -v end_time="$current_time" '$1 " " $2 " " $3 >= start_time && $1 " " $2 " " $3 <= end_time {print $(NF-3)}' | sort | uniq -c | awk '$1 > 10 {print $2}'))

4. Sử dụng IPTABLES chặn IP có SSH lỗi quá nhiều

Sau khi có được list các danh sách IP, để viết được script sử dụng IPTABLES ta cần thì ta cần sử dụng vòng lặp để lấy ra từng IP sau đó mới thao tác với từng IP đó.

if [ ${#failed_ips[@]} -gt 0 ]; then

    for failed_ip in "${failed_ips[@]}"; do

    done

fi

Tiếp theo ta sử dụng IPTABLES để ban IP đó.

sudo iptables -A INPUT -s "$failed_ip" -j DROP

Tiếp theo ta cần lưu lại các IP và mốc thời gian ban IP để từ đó lấy làm căn cứ unban IP về sau.

echo "$formatted_time $failed_ip" >> "$STATE_FILE"

Trong đó ta cần phải quy đổi các mốc thời gian ra một quy chuẩn để có thể dùng làm căn cứ khi so sánh về sau.

formatted_time1=$(date -d "$one_minute_ago" "+%d%H%M%S")

formatted_time=$(date -d "$current_time" "+%d%H%M%S")

Kết hợp các ý trên ta có hàm hoàn chỉnh.

if [ ${#failed_ips[@]} -gt 0 ]; then

    for failed_ip in "${failed_ips[@]}"; do

        sudo iptables -A INPUT -s "$failed_ip" -j DROP

        echo "$formatted_time $failed_ip" >> "$STATE_FILE"

    done

fi

5. Mở ban sau 1 thời gian bị chặn

Việc tìm IP để unban cũng tương tự như việc tìm IP để ban vậy. Khác biệt ở đây là ta sẽ tìm IP để unban trong file $STATE_FILE. Việc tìm ra IP unban sẽ kết hợp với mộc thời gian trước đó 5 phút mà ta đã đặt ở trên.

ip_unbans=($(grep "$formatted_time1" "$STATE_FILE" | awk '{print $2}'))

Lúc này ta cũng đã có được danh sách các IP cần được unban. Việc của ta cần làm tiếp theo là sử dụng vòng lặp để lấy ra danh sách từng IP và thực hiện unban cho IP đó.

if [ ${#ip_unbans[@]} -gt 0 ]; then

    for ip_unban in "${ip_unbans[@]}"; do

        echo $ip_unban

        sudo iptables -D INPUT -s "$ip_unban" -j DROP

    done

fi

Hãy lưu ý rằng khi sử dụng IPTABLES và thao tác nó bằng các câu lệnh thì chúng ta cần phải lưu lại và tiến hành reload lại dịch vụ.

sudo service iptables save

sudo service iptables reload

6. Script hoàn chỉnh

Dưới đây là nội dung script sử dụng IPTABLES hoàn chỉnh sau khi mình đã tổng kết và gộp lại tất cả các ý ở trên. Nhưng do mình thực hiện lab và cần thời gian nhanh chóng nên mình sẽ đổi thành chặn IP có kết nối SSH thất bại quá 3 lần trong vòng 1 phút và gỡ ban sau 1 phút.

#!/bin/bash

LOG_FILE="/var/log/secure"

STATE_FILE="/tmp/bad_ip"

# Tạo tệp bad_ip nếu nó không tồn tại

touch "$STATE_FILE"

# Lấy ip ssh failed trong 1 phút

current_time=$(date "+%b %d %H:%M:%S")

one_minute_ago=$(date -d '1 minute ago' '+%b %d %H:%M:%S')

formatted_time1=$(date -d "$one_minute_ago" "+%d%H%M%S")

formatted_time=$(date -d "$current_time" "+%d%H%M%S")

failed_ips=($(grep "sshd.*Failed password" "$LOG_FILE" | awk -v start_time="$one_minute_ago" -v end_time="$current_time" '$1 " " $2 " " $3 >= start_time && $1 " " $2 " " $3 <= end_time {print $(NF-3)}' | sort | uniq -c | awk '$1 > 3 {print $2}'))

if [ ${#failed_ips[@]} -gt 0 ]; then

    for failed_ip in "${failed_ips[@]}"; do

        sudo iptables -A INPUT -s "$failed_ip" -j DROP

        echo "$formatted_time $failed_ip" >> "$STATE_FILE"

    done

fi

# Unban IP sau thời gian đủ

ip_unbans=($(grep "$formatted_time1" "$STATE_FILE" | awk '{print $2}'))

if [ ${#ip_unbans[@]} -gt 0 ]; then

    for ip_unban in "${ip_unbans[@]}"; do

        echo $ip_unban

        sudo iptables -D INPUT -s "$ip_unban" -j DROP

    done

fi

sudo service iptables save

sudo service iptables reload

# Đây là script kết hợp với crontab chạy 1 phút 1 lần. và đây chỉ là test thôi nên tôi để biến $one_minute_ago là 1 phút trước

# Nếu các bạn muốn thay đổi thì có thể đặt biến $one_minute_ago thành thời gian theo ý muốn của các bạn và sửa lại thời gian chạy file của crontab trùng với $one_minute_ago

Việc tiếp theo chúng ta cần làm là sử dụng crontab để lập lịch chạy script này.

crontab -e

* * * * * /root/test1.sh

Bây giờ ta hãy tiến hành SSH thất bại nhiều lần và kiểm tra kết quả.

Viết script sử dụng iptables chặn các kết nối ssh
Kết quả hiển thị sau khi viết script sử dụng iptables chặn các kết nối SSH

7. Tổng kết

Việc script sử dụng IPTABLES chặn các kết nối SSH sai quá nhiều là một việc cần thiết, nó giúp nhằm giảm tải cho hệ thống và cũng tránh các trường hợp spam việc đăng nhập bằng user ngẫu nhiên. Script này chính là giải pháp cho việc tránh cho những trường hợp tồi tệ không xảy ra. Để có thể tự viết script như này bạn cần có một kiến thức rất sâu về bash shell và phải vận dụng thành thạo các câu lệnh grep và awk. Nhưng nếu bạn chỉ muốn làm được bài toán mà mình đã đặt ra như trên thì chỉ cần đọc kỹ những hướng dẫn ở trên là đủ. Script này vẫn sẽ còn có rất nhiều hướng phát triển thêm nữa. Nếu bạn có hứng thú phát triển hay góp ý gì thì hãy comment nhé.

Tác giả:
author avatar
Mình là Huy, hiện mình đang là kỹ sư hệ thống tại SunCloud. Mình có nhiều năm kinh nghiệm, kiến thức chuyên môn về mạng, hệ thống, điện toán mây và an ninh bảo mật. Mình đã triển khai và vận hành rất nhiều dự án thực tế cho doanh nghiệp, cơ quan. Mình đã đạt được một số chứng chỉ quốc tế như CCNP, LPI, VCP, đồng thời mình vẫn đang tiếp tục học tập để trau dồi kiến thức mỗi ngày. Mình rất yêu thích công nghệ, đam mê chia sẻ những kiến thức, thông tin hữu ích cho mọi người.

Tin tức nổi bật