Bangun Pemindai Kerentanan Jaringan Menggunakan GO – Poin Situs – Beragampengetahuan
Pengujian penetrasi memungkinkan organisasi untuk menargetkan kelemahan keamanan potensial dalam jaringan dan perlu mengatasi kerentanan sebelum kompromi aktor jahat.
Dalam artikel ini, kami akan menggunakan Go untuk membuat pemindai kerentanan jaringan yang sederhana dan masuk akal, bahasa yang sempurna untuk pemrograman jaringan karena dirancang untuk diingat dan memiliki perpustakaan standar yang sangat baik.
Contents
1. Siapkan proyek kami
Buat pemindai kerentanan
Kami ingin membangun alat CLI sederhana yang akan dapat memindai jaringan host, menemukan port terbuka, menjalankan layanan dan menemukan kemungkinan kerentanan. Pemindai dimulai dengan sangat mudah, tetapi saat kami melapisi fungsi, pemindai menjadi semakin mampu.
Jadi pertama -tama, kami akan membuat proyek GO baru:
mkdir goscan
cd goscan
go mod init github.com/yourusername/goscan
Ini menginisialisasi modul GO baru untuk proyek kami, yang akan membantu kami mengelola dependensi.
Konfigurasikan paket dan lingkungan
Untuk pemindai kami, kami akan memanfaatkan beberapa kit:
package main
import (
"fmt"
"net"
"os"
"strconv"
"sync"
"time"
)
func main()
fmt.Println("GoScan - Network Vulnerability Scanner")
Ini hanya pengaturan awal kami. Untuk beberapa fitur awal, ini sudah cukup, tetapi kami akan menambahkan lebih banyak impor sesuai permintaan. Sekarang paket perpustakaan standar lainnya (seperti NET) akan memperhatikan menyelesaikan sebagian besar jaringan yang kita butuhkan, dan sinkronisasi akan melakukan konkurensi, dll.
Pertimbangan etis dan risiko pemindaian melalui jaringan
Sekarang, sebelum kita masuk ke implementasi, kita harus berbicara tentang beberapa pertimbangan moral tentang pemindaian jaringan. Di banyak bagian dunia, pemindaian atau pencacahan jaringan yang tidak sah adalah ilegal dan dianggap sebagai vektor serangan dunia maya. Anda harus selalu mengikuti aturan berikut:
- mengizinkan: Hanya memindai jaringan dan sistem yang Anda miliki atau memiliki izin pemindaian yang jelas.
- cakupan: Tentukan ruang lingkup yang jelas untuk pemindaian Anda dan jangan melebihi itu.
- waktu: Jangan melakukan pemindaian super untuk mengurangi layanan atau meningkatkan peringatan keamanan.
- Penyingkapan: Jika kerentanan ditemukan, laporkan itu bertanggung jawab dengan melaporkan kepada pemilik sistem yang sesuai.
- Kepatuhan hukum: Memahami dan mematuhi hukum setempat tentang pemindaian jaringan.
Penyalahgunaan alat pemindaian dapat menyebabkan tindakan hukum, kerusakan sistem, atau penolakan layanan yang tidak disengaja. Pemindai kami akan mencakup perlindungan seperti membatasi tingkat, tetapi pada akhirnya tanggung jawab terletak pada penggunaan etis pengguna itu.
2. Pemindai Port Sederhana
Penilaian kerentanan didasarkan pada pemindaian pelabuhan. Layanan yang berpotensi rentan yang disediakan oleh masing -masing port terbuka ini adalah informasi yang kami cari. Sekarang, mari kita tulis pemindai port sederhana di Go.
Implementasi pemindaian pelabuhan tingkat rendah
Pemindaian Port: Cobalah untuk membuat koneksi ke setiap port yang memungkinkan pada host target. Jika koneksi berhasil, port terbuka; Jika gagal, port akan ditutup atau disaring. Untuk fitur ini, Paket Net GO membuat kami dibahas.
Jadi, inilah versi pemindai port sederhana kami:
package main
import (
"fmt"
"net"
"time"
)
func scanPort(host string, port int, timeout time.Duration) bool
target := fmt.Sprintf("%s:%d", host, port)
conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil
return false
conn.Close()
return true
func main()
host := "localhost"
timeout := time.Second * 2
fmt.Printf("Scanning host: %s\n", host)
for port := 1; port <= 1024; port++
if scanPort(host, port, timeout)
fmt.Printf("Port %d is open\n", port)
fmt.Println("Scan complete")
Menggunakan paket jaringan
Kode di atas menggunakan Paket Perangkat Lunak GO NET, yang menyediakan antarmuka dan fungsi I/O jaringan. Jadi, apa pekerjaan utamanya?
- net.dialtimeout: Fungsi ini mencoba untuk terhubung ke alamat jaringan TCP melalui batas waktu. Ini mengembalikan koneksi dan mengembalikan kesalahan (jika ada).
- Pemrosesan koneksi: Jika terhubung tanpa masalah, kami tahu itu terbuka, kami segera menutup koneksi untuk membuka sumber daya.
- Parameter batas waktu: Kami menentukan jeda untuk menghindari tergantung pada port penyaringan terbuka apa pun. Dua detik adalah nilai awal yang baik, tetapi dapat disesuaikan sesuai dengan kondisi jaringan.
Uji pemindaian pertama kami
Sekarang mari kita lakukan pemindai sederhana di localhost kami, di mana kami mungkin menjalankan beberapa layanan.
- Simpan kode ke file bernama
main.go - Jalankan
go run main.go
Ini akan menunjukkan port lokal mana yang terbuka. Pada mesin pengembangan normal, Anda mungkin memiliki 80 (http), 443 (http), atau sejumlah port basis data tergantung pada layanan yang Anda miliki.
Anda mungkin mendapatkan beberapa output sampel:
Scanning host: localhost
Port 22 is open
Port 80 is open
Port 443 is open
Scan complete
Menggunakan pemindai dasar ini bekerja, tetapi membawa beberapa kelemahan besar:
- kecepatan: Nyeri lambat karena akan memindai port secara berurutan.
- informasi: Beri tahu kami apakah port terbuka dan tidak ada informasi layanan.
- Kisaran terbatas: Kita hanya perlu memindai 1024 port pertama.
Keterbatasan ini membuat pemindai kami tidak praktis untuk digunakan di dunia nyata.
3. Perbaikan dari sini: Pemindaian multithreaded
Mengapa versi pertama lambat
Pemindai pelabuhan pertama kami bekerja, meskipun lambat tersedia. Masalahnya adalah metode berurutan – menyelidiki satu port pada satu waktu. Ketika host memiliki banyak port tertutup/disaring, kami membuang waktu menunggu untuk terhubung ke setiap port sebelum pindah ke port lain.
Untuk menunjukkan masalahnya, mari kita lihat waktu pemindai dasar kami:
- Skenario terburuk pemindaian port 1024 pertama akan memakan waktu hingga 2048 detik (lebih dari 34 menit) dan menggunakan 2 detik
- Namun, bahkan jika koneksi ke port shutdown gagal segera, metode ini kurang efisien karena latensi jaringan.
Pendekatan tunggal ini adalah hambatan untuk alat pemindaian kerentanan nyata.
Tambahkan dukungan utas
GO sangat pandai menggunakan goroutine dan saluran untuk konkurensi. Oleh karena itu, kami menggunakan fitur -fitur ini untuk mencoba memindai beberapa port sekaligus, yang sangat meningkatkan kinerja.
Sekarang, mari kita buat pemindai port multithreaded:
package main
import (
"fmt"
"net"
"sync"
"time"
)
type Result struct
Port int
State bool
func scanPort(host string, port int, timeout time.Duration) Result
target := fmt.Sprintf("%s:%d", host, port)
conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil
return ResultPort: port, State: false
conn.Close()
return ResultPort: port, State: true
func scanPorts(host string, start, end int, timeout time.Duration) []Result
var results []Result
var wg sync.WaitGroup
resultChan := make(chan Result, end-start+1)
semaphore := make(chan struct, 100)
for port := start; port <= end; port++
wg.Add(1)
go func(p int)
defer wg.Done()
semaphore <- struct
defer func() <-semaphore ()
result := scanPort(host, p, timeout)
resultChan <- result
(port)
go func()
wg.Wait()
close(resultChan)
()
for result := range resultChan
if result.State
results = append(results, result)
return results
func main()
host := "localhost"
startPort := 1
endPort := 1024
timeout := time.Millisecond * 500
fmt.Printf("Scanning %s from port %d to %d\n", host, startPort, endPort)
startTime := time.Now()
results := scanPorts(host, startPort, endPort, timeout)
elapsed := time.Since(startTime)
fmt.Printf("\nScan completed in %s\n", elapsed)
fmt.Printf("Found %d open ports:\n", len(results))
for _, result := range results
fmt.Printf("Port %d is open\n", result.Port)
Hasil dari beberapa utas
Sekarang mari kita lihat pertumbuhan kinerja yang kami tambahkan di pemindai yang lebih baik dan mekanisme konkurensi:
- Goroutine: Untuk meningkatkan efisiensi pemindaian, kami memulai goroutine untuk setiap port yang perlu dipindai, jadi ketika kami memeriksa satu port, kami dapat memeriksa port lain secara bersamaan.
- Waitgroup:sinkronis. Tim yang menunggu, kami mendorong Golotis, kami ingin menunggu penyelesaian mereka. WaitGroup membantu kami melacak semua goroutine yang berjalan dan menunggu mereka menyelesaikannya.
- Saluran Hasil: Kami membuat saluran buffer agar hasil dari semua goroutine.
- Mode semaphore: Gunakan semaphores, diimplementasikan menggunakan saluran untuk membatasi jumlah pemindaian yang diizinkan secara paralel. Inilah yang mencegah kita untuk membanjiri sistem target yang sebenarnya dan bahkan tidak dapat membuka banyak mesin yang terhubung.
- Kurangi batas waktu: Karena kami melakukan banyak pemindaian ini secara paralel, kami menggunakan batas waktu yang lebih rendah.
Kesenjangan kinerja sangat besar. Jadi ketika kami menerapkan fungsi ini, memungkinkan kami untuk memindai 1024 port dalam beberapa menit, yang tentu saja kurang dari setengah jam.
Output sampel:
Scanning localhost from port 1 to 1024
Scan completed in 3.2s
Found 3 open ports:
Port 22 is open
Port 80 is open
Port 443 is open
Pendekatan multithreaded baik untuk rentang port yang lebih besar dan beberapa host. Pola semaphore memastikan bahwa meskipun memindai lebih dari seribu port, kami tidak kehabisan sumber daya sistem.
4. Tambahkan Deteksi Layanan
Sekarang kami memiliki pemindai port yang cepat dan efisien, langkah selanjutnya adalah mengetahui layanan yang berjalan di port terbuka ini. Ini sering disebut “sidik jari layanan” atau “crawl spanduk”, yang merupakan proses ketika kami terhubung ke port terbuka dan memeriksa data pengembalian.
Menerapkan Banner Grab
Banner Crawl adalah saat kami membuka layanan dan membaca respons (Banner) itu membawa kami. Jadi ini cara yang bagus untuk menentukan apakah sesuatu berhasil, karena banyak layanan diidentifikasi dalam spanduk ini.
Sekarang mari kita ambil spanduk ke pemindai kami:
package main
import (
"bufio"
"fmt"
"net"
"strings"
"sync"
"time"
)
type ScanResult struct
Port int
State bool
Service string
Banner string
Version string
func grabBanner(host string, port int, timeout time.Duration) (string, error)
target := fmt.Sprintf("%s:%d", host, port)
conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil
return "", err
defer conn.Close()
conn.SetReadDeadline(time.Now().Add(timeout))
if port == 80
func identifyService(port int, banner string) (string, string) strings.Contains(lowerBanner, "apache")
func scanPort(host string, port int, timeout time.Duration) ScanResult
target := fmt.Sprintf("%s:%d", host, port)
conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil
return ScanResultPort: port, State: false
conn.Close()
banner, err := grabBanner(host, port, timeout)
service := "Unknown"
version := "Unknown"
if err == nil && banner != ""
service, version = identifyService(port, banner)
return ScanResult
Port: port,
State: true,
Service: service,
Banner: banner,
Version: version,
func scanPorts(host string, start, end int, timeout time.Duration) []ScanResult
var results []ScanResult
var wg sync.WaitGroup
resultChan := make(chan ScanResult, end-start+1)
semaphore := make(chan struct, 100)
for port := start; port <= end; port++
wg.Add(1)
go func(p int)
defer wg.Done()
semaphore <- struct
defer func() <-semaphore ()
result := scanPort(host, p, timeout)
resultChan <- result
(port)
go func()
wg.Wait()
close(resultChan)
()
for result := range resultChan
if result.State
results = append(results, result)
return results
func main()
host := "localhost"
startPort := 1
endPort := 1024
timeout := time.Millisecond * 800
fmt.Printf("Scanning %s from port %d to %d\n", host, startPort, endPort)
startTime := time.Now()
results := scanPorts(host, startPort, endPort, timeout)
elapsed := time.Since(startTime)
fmt.Printf("\nScan completed in %s\n", elapsed)
fmt.Printf("Found %d open ports:\n\n", len(results))
fmt.Println("PORT\tSERVICE\tVERSION\tBANNER")
fmt.Println("----\t-------\t-------\t------")
for _, result := range results
bannerPreview := ""
if len(result.Banner) > 30
bannerPreview = result.Banner[:30] + "..."
else
bannerPreview = result.Banner
fmt.Printf("%d\t%s\t%s\t%s\n",
result.Port,
result.Service,
result.Version,
bannerPreview)
Identifikasi layanan berjalan
Kami menggunakan dua strategi utama untuk deteksi layanan:
- Identifikasi Berbasis Port: Dengan memetakan nomor port umum (misalnya, port 80 adalah http), kita dapat menebak layanan.
- Analisis spanduk: Kami menggunakan teks spanduk dan mencari pengidentifikasi layanan dan informasi versi.
Fitur pertama Grabbanner mencoba mendapatkan respons pertama dari layanan. Beberapa layanan seperti HTTP mengharuskan kami mengirim permintaan dan menerima balasan, dan kami menggunakan kasus di mana kami menambahkan kasus tertentu.
Deteksi Versi Dasar
Deteksi versi penting untuk mengidentifikasi kerentanan. Jika memungkinkan, pemindai kami mem -parsing spanduk layanan untuk informasi versi:
- Ssh: Informasi versi biasanya disediakan dalam bentuk “ssh-2.0-openssh_7.4”.
- Server http: Informasi versinya biasanya digunakan dalam judul respons untuk merespons, seperti “Server: Apache/2.4.29”
- Server database: Informasi versi dapat diungkapkan dalam pesan selamat datang
Sekarang, output mengembalikan informasi lebih lanjut untuk setiap port terbuka:
Scanning localhost from port 1 to 1024
Scan completed in 5.4s
Found 3 open ports:
PORT SERVICE VERSION BANNER
---- ------- ------- ------
22 SSH 2.0 SSH-2.0-OpenSSH_8.4p1 Ubuntu-6
80 HTTP Apache/2.4.41 Server: Apache/2.4.41 (Ubuntu)
443 HTTPS Unknown Connection closed by foreign...
Informasi yang ditingkatkan ini lebih berharga untuk penilaian kerentanan.
5. Implementasi Deteksi Kerentanan
Sekarang kami dapat menyebutkan layanan yang berjalan dan versi apa mereka, dan kami akan menerapkan deteksi kerentanan. Informasi layanan akan dianalisis dan dibandingkan dengan kerentanan yang diketahui.
Tulis tes kerentanan sederhana
Kami akan membentuk database dari kerentanan yang diketahui berdasarkan layanan umum dan versi. Untuk kesederhanaan, kami akan membuat database kerentanan internal, meskipun pada kenyataannya, pemindai kemungkinan besar akan meminta database kerentanan eksternal (seperti CVE atau NVD).
Sekarang, mari kita perluas kode untuk mendeteksi kerentanan:
package main
import (
"bufio"
"fmt"
"net"
"strings"
"sync"
"time"
)
type ScanResult struct
Port int
State bool
Service string
Banner string
Version string
Vulnerabilities []Vulnerability
type Vulnerability struct
ID string
Description string
Severity string
Reference string
var vulnerabilityDB = []struct
Service string
Version string
Vulnerability Vulnerability
Service: "SSH",
Version: "OpenSSH_7.4",
Vulnerability: Vulnerability
ID: "CVE-2017-15906",
Description: "The process_open function in sftp-server.c in OpenSSH before 7.6 does not properly prevent write operations in read-only mode",
Severity: "Medium",
Reference: "",
,
,
Service: "HTTP",
Version: "Apache/2.4.29",
Vulnerability: Vulnerability
ID: "CVE-2019-0211",
Description: "Apache HTTP Server 2.4.17 to 2.4.38 - Local privilege escalation through mod_prefork and mod_http2",
Severity: "High",
Reference: "https://nvd.nist.gov/vuln/detail/CVE-2019-0211",
,
,
Service: "HTTP",
Version: "Apache/2.4.41",
Vulnerability: Vulnerability
ID: "CVE-2020-9490",
Description: "A specially crafted value for the 'Cache-Digest' header can cause a heap overflow in Apache HTTP Server 2.4.0-2.4.41",
Severity: "High",
Reference: "",
,
,
Service: "MySQL",
Version: "5.7",
Vulnerability: Vulnerability
ID: "CVE-2020-2922",
Description: "Vulnerability in MySQL Server allows unauthorized users to obtain sensitive information",
Severity: "Medium",
Reference: "https://nvd.nist.gov/vuln/detail/CVE-2020-2922",
,
,
func checkVulnerabilities(service, version string) []Vulnerability
var vulnerabilities []Vulnerability
for _, vuln := range vulnerabilityDB
if vuln.Service == service && strings.Contains(version, vuln.Version)
vulnerabilities = append(vulnerabilities, vuln.Vulnerability)
return vulnerabilities
func grabBanner(host string, port int, timeout time.Duration) (string, error) port == 8080
func identifyService(port int, banner string) (string, string)
strings.Contains(lowerBanner, "nginx")
if port == 443
service = "HTTPS"
else
service = "HTTP"
if strings.Contains(banner, "Server:")
parts := strings.Split(banner, "Server:")
if len(parts) >= 2
version = strings.TrimSpace(parts[1])
return service, version
func scanPort(host string, port int, timeout time.Duration) ScanResult
target := fmt.Sprintf("%s:%d", host, port)
conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil
return ScanResultPort: port, State: false
conn.Close()
banner, err := grabBanner(host, port, timeout)
service := "Unknown"
version := "Unknown"
if err == nil && banner != ""
service, version = identifyService(port, banner)
vulnerabilities := checkVulnerabilities(service, version)
return ScanResult
Port: port,
State: true,
Service: service,
Banner: banner,
Version: version,
Vulnerabilities: vulnerabilities,
func scanPorts(host string, start, end int, timeout time.Duration) []ScanResult
var results []ScanResult
var wg sync.WaitGroup
resultChan := make(chan ScanResult, end-start+1)
semaphore := make(chan struct, 100)
for port := start; port <= end; port++
wg.Add(1)
go func(p int)
defer wg.Done()
semaphore <- struct
defer func() <-semaphore ()
result := scanPort(host, p, timeout)
resultChan <- result
(port)
go func()
wg.Wait()
close(resultChan)
()
for result := range resultChan
if result.State
results = append(results, result)
return results
func main()
host := "localhost"
startPort := 1
endPort := 1024
timeout := time.Second * 1
fmt.Printf("Scanning %s from port %d to %d\n", host, startPort, endPort)
startTime := time.Now()
results := scanPorts(host, startPort, endPort, timeout)
elapsed := time.Since(startTime)
fmt.Printf("\nScan completed in %s\n", elapsed)
fmt.Printf("Found %d open ports:\n\n", len(results))
fmt.Println("PORT\tSERVICE\tVERSION")
fmt.Println("----\t-------\t-------")
for _, result := range results
fmt.Printf("%d\t%s\t%s\n",
result.Port,
result.Service,
result.Version)
if len(result.Vulnerabilities) > 0
fmt.Println(" Vulnerabilities:")
for _, vuln := range result.Vulnerabilities
fmt.Printf(" [%s] %s - %s\n",
vuln.Severity,
vuln.ID,
vuln.Description)
fmt.Printf(" Reference: %s\n\n", vuln.Reference)
package main
import (
"bufio"
"fmt"
"net"
"strings"
"sync"
"time"
)
type ScanResult struct
Port int
State bool
Service string
Banner string
Version string
Vulnerabilities []Vulnerability
type Vulnerability struct
ID string
Description string
Severity string
Reference string
var vulnerabilityDB = []struct
Service string
Version string
Vulnerability Vulnerability
Service: "SSH",
Version: "OpenSSH_7.4",
Vulnerability: Vulnerability
ID: "CVE-2017-15906",
Description: "The process_open function in sftp-server.c in OpenSSH before 7.6 does not properly prevent write operations in read-only mode",
Severity: "Medium",
Reference: "",
,
,
Service: "HTTP",
Version: "Apache/2.4.29",
Vulnerability: Vulnerability
ID: "CVE-2019-0211",
Description: "Apache HTTP Server 2.4.17 to 2.4.38 - Local privilege escalation through mod_prefork and mod_http2",
Severity: "High",
Reference: "https://nvd.nist.gov/vuln/detail/CVE-2019-0211",
,
,
Service: "HTTP",
Version: "Apache/2.4.41",
Vulnerability: Vulnerability
ID: "CVE-2020-9490",
Description: "A specially crafted value for the 'Cache-Digest' header can cause a heap overflow in Apache HTTP Server 2.4.0-2.4.41",
Severity: "High",
Reference: "",
,
,
Service: "MySQL",
Version: "5.7",
Vulnerability: Vulnerability
ID: "CVE-2020-2922",
Description: "Vulnerability in MySQL Server allows unauthorized users to obtain sensitive information",
Severity: "Medium",
Reference: "https://nvd.nist.gov/vuln/detail/CVE-2020-2922",
,
,
func checkVulnerabilities(service, version string) []Vulnerability
var vulnerabilities []Vulnerability
for _, vuln := range vulnerabilityDB
if vuln.Service == service && strings.Contains(version, vuln.Version)
vulnerabilities = append(vulnerabilities, vuln.Vulnerability)
return vulnerabilities
func grabBanner(host string, port int, timeout time.Duration) (string, error) port == 8080
func identifyService(port int, banner string) (string, string)
strings.Contains(lowerBanner, "nginx")
if port == 443
service = "HTTPS"
else
service = "HTTP"
if strings.Contains(banner, "Server:")
parts := strings.Split(banner, "Server:")
if len(parts) >= 2
version = strings.TrimSpace(parts[1])
return service, version
func scanPort(host string, port int, timeout time.Duration) ScanResult
target := fmt.Sprintf("%s:%d", host, port)
conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil
return ScanResultPort: port, State: false
conn.Close()
banner, err := grabBanner(host, port, timeout)
service := "Unknown"
version := "Unknown"
if err == nil && banner != ""
service, version = identifyService(port, banner)
vulnerabilities := checkVulnerabilities(service, version)
return ScanResult
Port: port,
State: true,
Service: service,
Banner: banner,
Version: version,
Vulnerabilities: vulnerabilities,
func scanPorts(host string, start, end int, timeout time.Duration) []ScanResult
var results []ScanResult
var wg sync.WaitGroup
resultChan := make(chan ScanResult, end-start+1)
semaphore := make(chan struct, 100)
for port := start; port <= end; port++
wg.Add(1)
go func(p int)
defer wg.Done()
semaphore <- struct
defer func() <-semaphore ()
result := scanPort(host, p, timeout)
resultChan <- result
(port)
go func()
wg.Wait()
close(resultChan)
()
for result := range resultChan
if result.State
results = append(results, result)
return results
func main()
host := "localhost"
startPort := 1
endPort := 1024
timeout := time.Second * 1
fmt.Printf("Scanning %s from port %d to %d\n", host, startPort, endPort)
startTime := time.Now()
results := scanPorts(host, startPort, endPort, timeout)
elapsed := time.Since(startTime)
fmt.Printf("\nScan completed in %s\n", elapsed)
fmt.Printf("Found %d open ports:\n\n", len(results))
fmt.Println("PORT\tSERVICE\tVERSION")
fmt.Println("----\t-------\t-------")
for _, result := range results
fmt.Printf("%d\t%s\t%s\n",
result.Port,
result.Service,
result.Version)
if len(result.Vulnerabilities) > 0
fmt.Println(" Vulnerabilities:")
for _, vuln := range result.Vulnerabilities
fmt.Printf(" [%s] %s - %s\n",
vuln.Severity,
vuln.ID,
vuln.Description)
fmt.Printf(" Reference: %s\n\n", vuln.Reference)
Pencocokan kerentanan berbasis versi
Kami memiliki metode pencocokan versi naif untuk mendeteksi kerentanan:
- Pertandingan langsung: Di sini kami mencocokkan jenis layanan dan versi dengan database kerentanan kami.
- Pertandingan parsial: Untuk pencocokan versi rentan, kami melakukan pemeriksaan penahanan pada string versi, yang dapat mengidentifikasi sistem yang rentan bahkan jika string versi berisi informasi tambahan.
Dalam pemindai sungguhan, pencocokan ini akan lebih kompleks, mengingat:
- Rentang Versi (IE Versi 2.4.0 hingga 2.4.38 terpengaruh)
- Kerentanan spesifik konfigurasi
- Masalah khusus OS
- Perbandingan versi yang lebih halus
Laporkan apa yang kami temukan
Hasil pelaporan adalah langkah terakhir dalam deteksi kerentanan dan perlu diselesaikan dalam format yang ringkas dan jelas. Sekarang pemindai kami:
- Cantumkan semua port terbuka dengan informasi layanan dan versi
- Untuk setiap layanan yang rentan, tunjukkan:
- ID kerentanan (seperti nomor CVE)
- Deskripsi kerentanan
- Tingkat keparahan
- Lihat tautan untuk informasi lebih lanjut
Output sampel:
Scanning localhost from port 1 to 1024
Scan completed in 6.2s
Found 3 open ports:
PORT SERVICE VERSION
---- ------- -------
22 SSH OpenSSH_7.4p1
Vulnerabilities:
[Medium] CVE-2017-15906 - The process_open function in sftp-server.c in OpenSSH before 7.6 does not properly prevent write operations in read-only mode
Reference:
80 HTTP Apache/2.4.41
Vulnerabilities:
[High] CVE-2020-9490 - A specially crafted value for the 'Cache-Digest' header can cause a heap overflow in Apache HTTP Server 2.4.0-2.4.41
Reference:
443 HTTPS Unknown
Data kerentanan yang terperinci ini memandu para ahli keamanan siber untuk dengan cepat mengidentifikasi dan memberi peringkat masalah keamanan yang perlu ditangani.
Sentuhan dan penggunaan terakhir
Sekarang Anda memiliki pemindai kerentanan dasar dengan deteksi layanan dan pencocokan kerentanan; Sekarang, mari kita memoles sedikit untuk membuatnya lebih praktis untuk digunakan di dunia nyata.
Parameter baris perintah
Pemindai kami harus dapat dikonfigurasi melalui bendera baris perintah yang menetapkan opsi target, rentang port, dan pemindaian. Menggunakan paket logo Go sederhana.
Selanjutnya, mari tambahkan parameter baris perintah:
package main
import (
"bufio"
"encoding/json"
"flag"
"fmt"
"net"
"os"
"strings"
"sync"
"time"
)
type ScanResult struct
Port int
State bool
Service string
Banner string
Version string
Vulnerabilities []Vulnerability
type Vulnerability struct
ID string
Description string
Severity string
Reference string
var vulnerabilityDB = []struct
Service string
Version string
Vulnerability Vulnerability
func main()
hostPtr := flag.String("host", "", "Target host to scan (required)")
startPortPtr := flag.Int("start", 1, "Starting port number")
endPortPtr := flag.Int("end", 1024, "Ending port number")
timeoutPtr := flag.Int("timeout", 1000, "Timeout in milliseconds")
concurrencyPtr := flag.Int("concurrency", 100, "Number of concurrent scans")
formatPtr := flag.String("format", "text", "Output format: text, json, or csv")
verbosePtr := flag.Bool("verbose", false, "Show verbose output including banners")
outputFilePtr := flag.String("output", "", "Output file (default is stdout)")
flag.Parse()
if *hostPtr == ""
fmt.Println("Error: host is required")
flag.Usage()
os.Exit(1)
if *startPortPtr < 1
func outputText(w *os.File, results []ScanResult, elapsed time.Duration, verbose bool)
fmt.Fprintf(w, "\nScan completed in %s\n", elapsed)
fmt.Fprintf(w, "Found %d open ports:\n\n", len(results))
if len(results) == 0
fmt.Fprintf(w, "No open ports found.\n")
return
fmt.Fprintf(w, "PORT\tSERVICE\tVERSION\n")
fmt.Fprintf(w, "----\t-------\t-------\n")
for _, result := range results
fmt.Fprintf(w, "%d\t%s\t%s\n",
result.Port,
result.Service,
result.Version)
if verbose
fmt.Fprintf(w, " Banner: %s\n", result.Banner)
if len(result.Vulnerabilities) > 0
fmt.Fprintf(w, " Vulnerabilities:\n")
for _, vuln := range result.Vulnerabilities
fmt.Fprintf(w, " [%s] %s - %s\n",
vuln.Severity,
vuln.ID,
vuln.Description)
fmt.Fprintf(w, " Reference: %s\n\n", vuln.Reference)
func outputJSON(w *os.File, results []ScanResult, elapsed time.Duration)
output := struct
ScanTime string `json:"scan_time"`
ElapsedTime string `json:"elapsed_time"`
TotalPorts int `json:"total_ports"`
OpenPorts int `json:"open_ports"`
Results []ScanResult `json:"results"`
ScanTime: time.Now().Format(time.RFC3339),
ElapsedTime: elapsed.String(),
TotalPorts: 0,
OpenPorts: len(results),
Results: results,
encoder := json.NewEncoder(w)
encoder.SetIndent("", " ")
encoder.Encode(output)
func outputCSV(w *os.File, results []ScanResult, elapsed time.Duration, verbose bool)
fmt.Fprintf(w, "Port,Service,Version,Vulnerability ID,Severity,Description\n")
for _, result := range results
if len(result.Vulnerabilities) == 0
fmt.Fprintf(w, "%d,%s,%s,,,\n",
result.Port,
escapeCSV(result.Service),
escapeCSV(result.Version))
else
for _, vuln := range result.Vulnerabilities
fmt.Fprintf(w, "%d,%s,%s,%s,%s,%s\n",
result.Port,
escapeCSV(result.Service),
escapeCSV(result.Version),
escapeCSV(vuln.ID),
escapeCSV(vuln.Severity),
escapeCSV(vuln.Description))
fmt.Fprintf(w, "\n# Scan completed in %s, found %d open ports\n",
elapsed, len(results))
func escapeCSV(s string) string
if strings.Contains(s, ",")
Format output
Pemindai kami sekarang dapat menghasilkan tiga format:
- teks: Mudah dibaca, mudah ditulis, sempurna untuk penggunaan interaktif.
- Json: Output terstruktur dapat digunakan untuk pemrosesan mesin dan integrasi dengan alat lain.
- CSV: Format kompatibel spreadsheet untuk analisis dan pelaporan.
Jika detail diatur, teks output juga memberikan informasi lebih lanjut, seperti informasi spanduk mentah. Ini juga nyaman untuk debugging atau analisis mendalam.
Contoh Penggunaan dan Hasil
Jadi jika Anda menggunakan pemindai kami pada kesempatan yang berbeda, berikut adalah beberapa kemungkinan:
Pemindaian dasar dari satu host:
$ go run main.go -host example.com
Pindai rentang port spesifik:
$ go run main.go -host example.com -start 80 -end 443
Simpan hasilnya ke file JSON:
$ go run main.go -host example.com -format json -output results.json
Pemindaian waktu yang lama:
$ go run main.go -host example.com -verbose -timeout 2000
Pemindaian memiliki konkurensi yang lebih tinggi untuk hasil yang lebih cepat:
$ go run main.go -host example.com -concurrency 200
Contoh output teks:
Scanning example.com from port 1 to 1024
Scan completed in 12.6s
Found 3 open ports:
PORT SERVICE VERSION
---- ------- -------
22 SSH OpenSSH_7.4p1
Vulnerabilities:
[Medium] CVE-2017-15906 - The process_open function in sftp-server.c in OpenSSH before 7.6 does not properly prevent write operations in read-only mode
Reference:
80 HTTP Apache/2.4.41
Vulnerabilities:
[High] CVE-2020-9490 - A specially crafted value for the 'Cache-Digest' header can cause a heap overflow in Apache HTTP Server 2.4.0-2.4.41
Reference:
443 HTTPS nginx/1.18.0
Contoh Output JSON:
"scan_time": "2025-03-18T14:30:00Z",
"elapsed_time": "12.6s",
"total_ports": 1024,
"open_ports": 3,
"results": [
"Port": 22,
"State": true,
"Service": "SSH",
"Banner": "SSH-2.0-OpenSSH_7.4p1",
"Version": "OpenSSH_7.4p1",
"Vulnerabilities": [
"ID": "CVE-2017-15906",
"Description": "The process_open function in sftp-server.c in OpenSSH before 7.6 does not properly prevent write operations in read-only mode",
"Severity": "Medium",
"Reference": ""
]
,
"Port": 80,
"State": true,
"Service": "HTTP",
"Banner": "HTTP/1.1 200 OK\r\nServer: Apache/2.4.41",
"Version": "Apache/2.4.41",
"Vulnerabilities": [
"ID": "CVE-2020-9490",
"Description": "A specially crafted value for the 'Cache-Digest' header can cause a heap overflow in Apache HTTP Server 2.4.0-2.4.41",
"Severity": "High",
"Reference": ""
]
,
"Port": 443,
"State": true,
"Service": "HTTPS",
"Banner": "HTTP/1.1 200 OK\r\nServer: nginx/1.18.0",
"Version": "nginx/1.18.0",
"Vulnerabilities": []
]
Kami telah membangun pemindai kerentanan jaringan yang kuat di Go yang menunjukkan penerapan bahasa terhadap alat keamanan. Pemindai kami dengan cepat membuka port, menentukan layanan yang berjalan di atasnya, dan menentukan apakah ada kerentanan yang diketahui.
Ini memberikan informasi yang berguna tentang layanan yang berjalan di jaringan, termasuk multithreading, sidik jari layanan, dan berbagai format output.
Ingatlah bahwa alat -alat seperti pemindai hanya dapat digunakan dalam parameter etika dan hukum dan memindai sistem target dengan otorisasi yang sesuai. Pemindaian kerentanan reguler adalah aspek kunci dari postur keselamatan yang baik ketika dilakukan secara bertanggung jawab dan dapat membantu melindungi sistem Anda dari ancaman.
Anda dapat menemukan kode sumber lengkap untuk proyek ini di GitHub
rencana pengembangan website
metode pengembangan website
jelaskan beberapa rencana untuk pengembangan website, proses pengembangan website, kekuatan dan kelemahan bisnis pengembangan website
, jasa pengembangan website, tahap pengembangan website, biaya pengembangan website
#Bangun #Pemindai #Kerentanan #Jaringan #Menggunakan #Poin #Situs