Computer >> Máy Tính >  >> Lập trình >> Ruby

Cách viết Port Scanner trong Ruby

Tại sao bạn muốn viết một máy quét cổng?

Viết trình quét cổng là một cách tuyệt vời để tìm hiểu kiến ​​thức cơ bản về giao thức TCP, là lớp truyền tải được hầu hết các giao thức internet (bao gồm HTTP &SSH) sử dụng.

Đây cũng là một bài tập hay để tìm hiểu thêm về cách hoạt động của lập trình mạng Ruby.

Hãy bắt đầu bằng cách nói về các cổng!

Cổng là gì?

Khi chúng ta nói về các cổng, chúng ta thực sự đang nói về điều gì? Một cảng tại O.S. Cấp (Hệ điều hành) chỉ là “bộ mô tả tệp” được liên kết với một quy trình.

Một bộ mô tả tệp chỉ là một số được sử dụng để tham chiếu một kênh I / O mở, như stdout (đầu ra tiêu chuẩn), ổ cắm mạng hoặc tệp.

Khi hệ điều hành nhận được gói TCP / IP, hệ điều hành sẽ nhìn vào cổng đích và cố gắng tìm một quá trình đang lắng nghe trên cổng này.

Sau đó, nếu có một quá trình lắng nghe, gói tin sẽ được chuyển đến nó.

Dãy cảng

Tổng cộng có 65.535 cổng, nhưng trên thực tế không phải tất cả chúng đều được sử dụng thường xuyên.

Các cổng có thể được chia thành 3 nhóm:

Phạm vi Tên Ví dụ
1-1023 Các cổng nổi tiếng 22 (SSH), 80 (HTTP), 443 (HTTPS)
1024-49151 Các cổng đã đăng ký 3306 (MySQL), 5432 (PostgreSQL)
49152-65535 Cổng phù du Chrome, Firefox

Các cổng trong phạm vi thứ 2 được chỉ định bởi IANA (Cơ quan cấp số lượng Internet).

Và phạm vi thứ 3 được sử dụng cho các cổng "động" hoặc "tạm thời", đây là các cổng được phía máy khách của kết nối sử dụng để nhận dữ liệu từ máy chủ.

Khái niệm cơ bản về giao tiếp TCP

Bây giờ bạn sẽ quen thuộc hơn với các cổng, nhưng chúng tôi vẫn chưa sẵn sàng viết trình quét cổng của mình.

Đầu tiên, chúng ta cần thảo luận về ý nghĩa của việc mở một cổng. Sau đó, chúng tôi sẽ kiểm tra hoạt động của cả cổng mở và cổng đóng ở cấp độ mạng để chúng tôi có thể phân biệt chúng.

Làm thế nào bạn có thể biết nếu một cổng đang mở?

Cổng mở chỉ có nghĩa là có một ứng dụng đang lắng nghe ở đầu bên kia và chúng tôi có quyền truy cập vào nó (không bị tường lửa chặn).

Hãy xem cách một kết nối TCP mới được bắt đầu.

Cách viết Port Scanner trong Ruby

Kết nối TCP mới được bắt đầu bằng SYN gói tin. Gói này tượng trưng cho sự bắt đầu của một kết nối mới.

Có ba kết quả có thể xảy ra :

  • Máy chủ trả lời bằng SYN/ACK - điều này có nghĩa là nó đã sẵn sàng để thiết lập kết nối
  • Máy chủ trả lời bằng RST gói - điều này có nghĩa là kết nối bị từ chối
  • Máy chủ hoàn toàn không trả lời (một số tường lửa triển khai điều này làm chính sách DROP)

Nếu máy khách nhận được SYN/ACK sau đó gói tin có thể hoàn tất việc thiết lập kết nối bằng cách gửi ACK gói.

Đây được gọi là “ bắt tay ba bước “.

Lưu ý :Một cách tuyệt vời để theo dõi điều này đang xảy ra là sử dụng một công cụ mạng như tcpdump hoặc Wirehark. Các công cụ này cho phép bạn xem mọi gói tin đang đến &ra khỏi hệ thống của bạn.

Đây là một kết nối mẫu từ tshark (giao diện dòng lệnh của Wirehark):

Cách viết Port Scanner trong Ruby

Bây giờ bạn đã hiểu cơ bản về cách kết nối TCP được thiết lập, chúng ta có thể viết một trình quét cổng đơn giản.

Hãy viết một máy quét cổng!

Cách đơn giản nhất để ghi máy quét của chúng tôi là mở một kết nối TCP mới bằng cách sử dụng TCPSocket &sau đó dựa vào thực tế rằng một kết nối bị từ chối sẽ làm tăng Errno::ECONNREFUSED ngoại lệ.

Đây là mã :

 request 'socket'PORT =ARGV [0] || 22HOST =ARGV [1] || 'localhost'begin socket =TCPSocket.new (HOST, PORT) status ="open" Rescue Errno ::ECONNREFUSED, Errno ::ETIMEDOUT status ="closed" endputs "Cổng # {PORT} là # {status}."  

Mã này có một số hạn chế:

Chúng tôi chỉ có thể quét một cổng tại một thời điểm. Thông thường, bạn muốn quét một loạt các cổng để biết rõ hơn về những dịch vụ nào được hiển thị trên một máy chủ cụ thể.

Một hạn chế khác với mã này là cổng không phản hồi (phần ba trong số các kết quả mà tôi đã đề cập trước đó) sẽ khiến bạn đợi khoảng 20 giây cho đến khi hết thời gian kết nối.

Điều này có thể được giải quyết bằng sự kết hợp của connect_nonblock , IO.select &Socket (thay vì TCPSocket , khởi tạo kết nối ngay sau khi bạn tạo đối tượng).

Ví dụ :

 request 'socket'TIMEOUT =2def scan_port (port) socket =Socket.new (:INET,:STREAM) remote_addr =Socket.sockaddr_in (port,' www.example.com ') bắt đầu cứu hộ socket.connect_nonblock (remote_addr) Errno ::EINPROGRESS end _, sockets, _ =IO.select (nil, [socket], nil, TIMEOUT) if sockets p "Port # {port} is open" else # Port bị đóng endendPORT_LIST =[21,22,23 , 25,53,80,443,3306,8080] chủ đề =[] PORT_LIST.each {| i | thread < 

IO.select cuộc gọi sẽ đợi cho đến khi ổ cắm sẵn sàng nhận dữ liệu (có nghĩa là nó đang mở) hoặc cho đến khi TIMEOUT thời gian đã trôi qua, sau đó chúng tôi có thể giả định rằng cổng đã bị đóng hoặc bỏ qua các yêu cầu kết nối.

Vì vậy, đây là tất cả tuyệt vời như một bài tập học tập, nhưng nếu bạn cần một máy quét cổng thích hợp, bạn nên sử dụng một cái gì đó như nmap.

Nmap là mã nguồn mở và đã được phát triển tích cực trong hơn 15 năm.

Đây là đầu ra nmap trông như thế nào:

Cách viết Port Scanner trong Ruby

Tôi biết đó là rất nhiều thông tin, vì vậy, để giúp bạn nhớ hãy viết bình luận với 2 điều mới bạn học được từ bài đăng này 🙂

Tóm tắt

Trong bài đăng này, bạn đã biết cổng là gì, các phạm vi cổng khác nhau có sẵn, cách kết nối TCP được khởi tạo (bắt tay ba chiều) và cách viết trình quét cổng cơ bản bằng Ruby.

Nếu bạn thích bài viết này, đừng quên chia sẻ nó để nhiều người cùng thưởng thức nhé 🙂