גילוי פורטים פתוחים בצורה נאיבית

לפני מספר ימים ראיתי הודעה בקבוצת טלגרהם של פיתון עם שאלה איך למצוא פורטים פתוחים.
כולם הציעו לבחור "לרכב" על nmap, ואילו אני הצעתי משהו מעט שונה, אשר זכה להתייחסות.

אני מדבר כרגע על TCP. ובשביל להבין כמה זה לא מסובך, צריך להבין כיצד בקשת TCP עובדת בעצם.

ישנם מספר פעולות אשר נמצאות ברמה נמוכה יותר (בתוך מימוש TCP), אשר מבצעות עבורינו לחיצת יד. פעולות אלו מסוגלות לעשות זאת רק כאשר יש תשובה בצד השני, ומקבלים ack.
אם לא מקבלים אישור, יכולים להיות שני גורמים:

  1. התעבורה עברה, אבל לא קיבלנו אישור – הפורט פתוח אבל מפולטר (מלווה ב Connection Refused).
  2. אין פורט פתוח – אולי מפולטר, ואם כן מקבל drop כאילו אין פורט פתוח.

פעולה זו של SYNchronize היא הדרך עבורינו לגלות האם TCP פתוח.

ההצעה הפשוטה ביותר להתמודד עם זה, זה לנסות לפתוח חיבור TCP בפורט המבוקש לכתובת, במידה ונפתח, החיבור פתוח. במידה והחיבור נכשל (אם קיבלנו timeout או connection refused), אנחנו יודעים שהוא לא פתוח. כאשר האחרון אומר כי הוא מפולטר.

זו לא הדרך היחידה לעשות את זה, אבל זו הדרך הפשוטה ביותר.

יצרתי מימוש לזה בצורה מאוד נאיבית ברובי וגו, בתקוה שאולי תעזור גם לאחרים להבין שאין הרבה קסמים, ולפעמים השקעה של חצי שעה במקום "לרכב" על תוכנה קיימת יכולה להיות נחמדה 🙂

רובי:

#!/usr/bin/env ruby
require 'socket'
def tcp_connect(address, port, timeout: 20)
# making sure we are talking with IP
connected = false
addr = Socket.getaddrinfo(address, nil)
sock_addr = Socket.pack_sockaddr_in(port, addr[0][3])
Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0).tap do |socket|
begin
socket.connect_nonblock(sock_addr)
rescue IO::WaitWritable
if IO.select(nil, [socket], nil, timeout)
begin
# try again, might work
socket.connect_nonblock(sock_addr)
connected = :connected # no other exception, then should be yes
rescue Errno::EISCONN # we have a connection
connected = :connected
rescue Errno::ECONNREFUSED # we are filtered
connected = :filtered
rescue Errno::ETIMEDOUT # timeout
connected = :closed
rescue StandardError # something else :'(
connected = :error
end
else # unable to wait for an answer, but no exception was raised
connected = :error
end
rescue StandardError # ops, something went wrong
connected = false
ensure
socket.close
end
end
connected
end
puts tcp_connect('192.168.97.3', 8823)
view raw scan.rb hosted with ❤ by GitHub

גו:

package main
import (
"fmt"
"net"
"strings"
"time"
)
const (
errUnknown = "Unknown error"
connTimeout = "closed"
connFiltered = "filtered"
resolveError = "Resolve error"
lookupError = "Lookup error"
connSuccess = "open"
)
func tcpConnect(address string, port int, timeout time.Duration) (string, error) {
ipList, err := net.LookupHost(address)
if err != nil {
return lookupError, err
}
if len(ipList) == 0 {
return resolveError, fmt.Errorf("Unable to resolve %s", address)
}
connAddr := fmt.Sprintf("%s:%d", ipList[0], port)
conn, err := net.DialTimeout("tcp", connAddr, timeout)
if err != nil {
sErr := err.Error()
if strings.HasSuffix(sErr, "connection refused") {
return connFiltered, err
}
if strings.HasSuffix(sErr, "i/o timeout") {
return connTimeout, err
}
return errUnknown, err
}
defer conn.Close()
return connSuccess, nil
}
func main() {
addr := "google.com"
port := 443
status, err := tcpConnect(addr, port, time.Duration(3)*time.Second)
fmt.Printf("%s:%d - ", addr, port)
if status == errUnknown {
fmt.Println(err)
} else {
fmt.Println(status)
}
}
view raw scan.go hosted with ❤ by GitHub

2 מחשבות על “גילוי פורטים פתוחים בצורה נאיבית

    1. ik_5 מאת

      אין בעיה איתם, הם כלים ממש טובים.

      כאשר אתה רוצה לעשות את זה תכנותית, לפתוח pipe ל nmap הוא בעייתי, בייחוד כשקל כל כך לעשות את זה ללא תלות כלשהי.

להשאיר תגובה

הזינו את פרטיכם בטופס, או לחצו על אחד מהאייקונים כדי להשתמש בחשבון קיים:

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת /  לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת /  לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת /  לשנות )

מתחבר ל-%s

אתר זו עושה שימוש ב-Akismet כדי לסנן תגובות זבל. פרטים נוספים אודות איך המידע מהתגובה שלך יעובד.