最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Golang構(gòu)建一個(gè)網(wǎng)絡(luò)漏洞掃描器

 更新時(shí)間:2025年11月19日 09:10:48   作者:俞凡  
Go?語言非常適合網(wǎng)絡(luò)編程,它在設(shè)計(jì)時(shí)就考慮到了并發(fā)性,并且擁有出色的標(biāo)準(zhǔn)庫,本文將詳細(xì)介紹如何使用?Go?語言創(chuàng)建一個(gè)簡單且相當(dāng)可靠的網(wǎng)絡(luò)漏洞掃描器,感興趣的小伙伴可以了解下

本文將用 Go 語言創(chuàng)建一個(gè)簡單且相當(dāng)可靠的網(wǎng)絡(luò)漏洞掃描器。Go 語言非常適合網(wǎng)絡(luò)編程,它在設(shè)計(jì)時(shí)就考慮到了并發(fā)性,并且擁有出色的標(biāo)準(zhǔn)庫。

1. 項(xiàng)目設(shè)置

創(chuàng)建漏洞掃描器

我們想要開發(fā)一個(gè)簡單的命令行工具,該工具能夠掃描主機(jī)網(wǎng)絡(luò)、查找開放端口、識(shí)別運(yùn)行的服務(wù)并發(fā)現(xiàn)潛在漏洞。這個(gè)掃描器一開始會(huì)非常簡單,但隨著逐步添加功能,其能力會(huì)不斷增強(qiáng)。

首先,我們將創(chuàng)建一個(gè)新的 Go 項(xiàng)目:

mkdir goscan
cd goscan
go mod init github.com/yourusername/goscan

這將為項(xiàng)目初始化新的Go模塊,幫助我們管理依賴項(xiàng)。

配置包和環(huán)境

掃描器將利用若干 Go 包:

package main

import (
    "fmt"
    "net"
    "os"
    "strconv"
    "sync"
    "time"
)

func main() {
    fmt.Println("GoScan - Network Vulnerability Scanner")
}

這只是初始設(shè)置,但對(duì)于初始功能來說,已經(jīng)足夠了,我們會(huì)根據(jù)需要添加更多導(dǎo)入內(nèi)容。像 net 這樣的標(biāo)準(zhǔn)庫包將負(fù)責(zé)處理大部分網(wǎng)絡(luò)相關(guān)操作,而 sync 則會(huì)負(fù)責(zé)并發(fā)處理等。

網(wǎng)絡(luò)掃描的倫理考量與風(fēng)險(xiǎn)

在開始實(shí)現(xiàn)之前,首先需要探討一下與網(wǎng)絡(luò)掃描相關(guān)的倫理問題。在許多地區(qū),未經(jīng)授權(quán)的網(wǎng)絡(luò)掃描是違法的,會(huì)被視為發(fā)動(dòng)網(wǎng)絡(luò)攻擊的一種手段。因此,必須始終遵守以下規(guī)則:

  • 許可:僅對(duì)擁有所有權(quán)或已獲得明確許可進(jìn)行掃描的臨時(shí)網(wǎng)絡(luò)和系統(tǒng)進(jìn)行掃描。
  • 范圍:為掃描設(shè)定明確的范圍,并不要超出該范圍。
  • 時(shí)間:不要進(jìn)行可能導(dǎo)致服務(wù)中斷或引發(fā)安全警報(bào)的過度掃描。
  • 披露:如果發(fā)現(xiàn)漏洞,請(qǐng)負(fù)責(zé)任的將其報(bào)告給相應(yīng)的系統(tǒng)所有者。
  • 法律合規(guī):了解并遵守有關(guān)網(wǎng)絡(luò)掃描的當(dāng)?shù)胤伞?/li>

掃描工具的不當(dāng)使用可能會(huì)導(dǎo)致法律訴訟、系統(tǒng)損壞或意外服務(wù)中斷。我們的掃描器將包含諸如速率限制等防護(hù)措施,但最終責(zé)任在于用戶以合乎道德的方式使用。

2. 簡單端口掃描器

漏洞評(píng)估基于端口掃描。每個(gè)開放端口所提供的潛在易受攻擊的服務(wù)信息正是我們所要查找的內(nèi)容?,F(xiàn)在,讓我們用 Go 語言編寫一個(gè)簡單的端口掃描器。

低級(jí)端口掃描實(shí)現(xiàn)

端口掃描:嘗試與目標(biāo)主機(jī)上的每一個(gè)可能的端口建立連接。如果連接成功,則該端口是開放的;如果連接失敗,則該端口是關(guān)閉的或被過濾的。對(duì)于此功能,Go 的 net 包已經(jīng)為我們提供了支持。

那么,這就是我們所設(shè)計(jì)的一種簡單的端口掃描器的示例:

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" // Change this to your target
    timeout := time.Second * 2
    
    fmt.Printf("Scanning host: %s\n", host)
    
    // Scan ports 1-1024 (well-known ports)
    for port := 1; port <= 1024; port++ {
        if scanPort(host, port, timeout) {
            fmt.Printf("Port %d is open\n", port)
        }
    }
    
    fmt.Println("Scan complete")
}

使用net包

上述代碼使用了 Go 語言的 net 包,該包提供了網(wǎng)絡(luò)輸入/輸出接口及相關(guān)函數(shù)。那么,主要的組成部分都有哪些呢?

  • net.DialTimeout:此功能會(huì)嘗試在設(shè)定的超時(shí)時(shí)間內(nèi)連接到 TCP 網(wǎng)絡(luò)地址。如果連接成功,會(huì)返回連接信息以及任何可能出現(xiàn)的錯(cuò)誤。
  • 連接處理:如果連接過程順利,我們便知道該連接已打開,并會(huì)立即關(guān)閉該連接以釋放資源。
  • 超時(shí)參數(shù):設(shè)定超時(shí)時(shí)間,以避免在任何被過濾的開放端口上陷入僵局。兩秒是一個(gè)不錯(cuò)的初始值,但可根據(jù)網(wǎng)絡(luò)狀況進(jìn)行調(diào)整。

對(duì)首次掃描進(jìn)行測試

現(xiàn)在,我們?cè)诒镜刂鳈C(jī)上運(yùn)行簡單掃描器,那里可能有一些服務(wù)正在運(yùn)行。

  • 將代碼保存到名為 main.go 的文件中
  • go run main.go 命令運(yùn)行

這將顯示哪些本地端口是開放的。在普通開發(fā)機(jī)器上,可能會(huì)有 80(HTTP)端口、443(HTTPS)端口,或者根據(jù)運(yùn)行的服務(wù)不同,還有其他任意數(shù)量的數(shù)據(jù)庫端口正在使用。

以下是一些可能得到的示例輸出:

Scanning host: localhost
Port 22 is open
Port 80 is open
Port 443 is open
Scan complete

使用這種基本的掃描器是可以的,但也有不少明顯的缺點(diǎn):

  • 速度:由于是按順序掃描端口,所以速度極其緩慢。
  • 信息:只是告訴我們某個(gè)端口是否開放,沒有服務(wù)信息。
  • 覆蓋范圍有限:只掃描前 1024 個(gè)端口。

這些限制使得難以在實(shí)際應(yīng)用中使用掃描器。

3. 從這里開始改進(jìn):多線程掃描

為何最初的版本運(yùn)行緩慢

第一個(gè)端口掃描器能夠正常工作,但其運(yùn)行速度極其緩慢,幾乎無法實(shí)際使用。問題在于其采用順序掃描方法 —— 一次掃描一個(gè)端口。當(dāng)一臺(tái)主機(jī)有很多關(guān)閉/過濾的端口時(shí),會(huì)在每個(gè)端口上等待連接超時(shí),然后再轉(zhuǎn)移到下一個(gè)端口,這造成了極大的時(shí)間浪費(fèi)。

為了展示這個(gè)問題,我們來看看基本掃描器的運(yùn)行時(shí)間:

  • 對(duì)于掃描前 1024 個(gè)端口的情況,如果設(shè)置 2 秒的超時(shí)時(shí)間,最長時(shí)間將達(dá) 2048 秒(超過 34 分鐘)。
  • 但即便對(duì)那些已關(guān)閉的端口的連接也會(huì)立即失敗,這種方法由于網(wǎng)絡(luò)延遲的原因也是效率低下。

這種逐個(gè)端口進(jìn)行的掃描方式是任何真正的漏洞掃描工具的瓶頸。

添加線程支持

Go 語言在利用協(xié)程和通道實(shí)現(xiàn)并發(fā)方面表現(xiàn)尤為出色。因此,我們利用這些特性嘗試同時(shí)掃描多個(gè)端口,從而顯著提高性能。

現(xiàn)在讓我們來創(chuàng)建多線程端口掃描器:

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 Result{Port: port, State: false}
    }
    
    conn.Close()
    return Result{Port: port, State: true}
}

func scanPorts(host string, start, end int, timeout time.Duration) []Result {
    var results []Result
    var wg sync.WaitGroup
    
    // Create a buffered channel to collect results
    resultChan := make(chan Result, end-start+1)
    
    // Create a semaphore to limit concurrent goroutines
    // This prevents us from opening too many connections at once
    semaphore := make(chan struct{}, 100) // Limit to 100 concurrent scans
    
    // Launch goroutines for each port
    for port := start; port <= end; port++ {
        wg.Add(1)
        go func(p int) {
            defer wg.Done()
            
            // Acquire semaphore
            semaphore <- struct{}{}
            defer func() { <-semaphore }() // Release semaphore
            
            result := scanPort(host, p, timeout)
            resultChan <- result
        }(port)
    }
    
    // Close channel when all goroutines complete
    go func() {
        wg.Wait()
        close(resultChan)
    }()
    
    // Collect results from channel
    for result := range resultChan {
        if result.State {
            results = append(results, result)
        }
    }
    
    return results
}

func main() {
    host := "localhost" // Change this to your target
    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)
    }
}

多線程結(jié)果

現(xiàn)在,我們來看看改進(jìn)后掃描器的性能提升以及并發(fā)機(jī)制:

  • 協(xié)程:為了使掃描過程高效,我們會(huì)為需要掃描的每個(gè)端口啟動(dòng)一個(gè)協(xié)程,這樣當(dāng)我們檢查一個(gè)端口時(shí),就可以同時(shí)檢查其他端口。
  • 等待組:同步的等待組 當(dāng)我們啟動(dòng)協(xié)程時(shí),希望等待它們完成。等待組有助于跟蹤所有正在運(yùn)行的協(xié)程,并等待它們完成。
  • 結(jié)果通道:我們?yōu)樗袇f(xié)程的結(jié)果創(chuàng)建了一個(gè)緩沖通道。
  • 信號(hào)量模式:使用信號(hào)量來限制并行進(jìn)行的掃描數(shù)量,通過通道來實(shí)現(xiàn),防止我們因打開過多連接而使目標(biāo)系統(tǒng)甚至自身機(jī)器不堪重負(fù)。
  • 縮短超時(shí)時(shí)間:由于以并行方式運(yùn)行許多此類掃描,所以使用較短的超時(shí)時(shí)間。

性能差距很大。因此,當(dāng)我們實(shí)現(xiàn)這個(gè)功能時(shí),可以在幾分鐘內(nèi)掃描 1024 個(gè)端口,而且肯定不會(huì)超過半小時(shí)。

示例輸出:

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

這種多線程方法對(duì)于較大的端口范圍和多個(gè)主機(jī)來說具有極好的擴(kuò)展性。信號(hào)量模式確保即便要掃描上千個(gè)端口,也不會(huì)耗盡系統(tǒng)資源。

4. 添加服務(wù)檢測

既然已經(jīng)有了一個(gè)快速、高效的端口掃描器,接下來的步驟就是了解那些開放端口上運(yùn)行的是哪些服務(wù)。這通常被稱為“服務(wù)指紋識(shí)別”或“標(biāo)志抓取”,是一個(gè)連接到開放端口并檢查返回?cái)?shù)據(jù)的過程。

服務(wù)旗標(biāo)抓?。˙anner Grabbing)實(shí)現(xiàn)

服務(wù)旗標(biāo)抓取指的是當(dāng)我們打開服務(wù)并讀取發(fā)送給我們的響應(yīng)(即旗標(biāo)信息)時(shí)的操作。因此,這是一種很好的確認(rèn)服務(wù)是否運(yùn)行的方法,許多服務(wù)都會(huì)在旗標(biāo)中標(biāo)識(shí)自身信息。

我們?cè)趻呙杵髦屑尤胱ト∑鞓?biāo)的功能:

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))
    
    // Some services need a trigger to send data
    // Send a simple HTTP request for web services
    if port == 80 || port == 443 || port == 8080 || port == 8443 {
        fmt.Fprintf(conn, "HEAD / HTTP/1.0\r\n\r\n")
    } else {
        // For other services, just wait for the banner
        // Some services may require specific triggers
    }
    
    // Read the response
    reader := bufio.NewReader(conn)
    banner, err := reader.ReadString('\n')
    if err != nil {
        return "", err
    }
    
    return strings.TrimSpace(banner), nil
}

func identifyService(port int, banner string) (string, string) {
    commonPorts := map[int]string{
        21:    "FTP",
        22:    "SSH",
        23:    "Telnet",
        25:    "SMTP",
        53:    "DNS",
        80:    "HTTP",
        110:   "POP3",
        143:   "IMAP",
        443:   "HTTPS",
        3306:  "MySQL",
        5432:  "PostgreSQL",
        6379:  "Redis",
        8080:  "HTTP-Proxy",
        27017: "MongoDB",
    }
    
    // Try to identify service from common ports
    service := "Unknown"
    if s, exists := commonPorts[port]; exists {
        service = s
    }
    
    version := "Unknown"
    
    lowerBanner := strings.ToLower(banner)
    
    // SSH version detection
    if strings.Contains(lowerBanner, "ssh") {
        service = "SSH"
        parts := strings.Split(banner, " ")
        if len(parts) >= 2 {
            version = parts[1]
        }
    }
    
    // HTTP server detection
    if strings.Contains(lowerBanner, "http") || strings.Contains(lowerBanner, "apache") || 
       strings.Contains(lowerBanner, "nginx") {
        if port == 443 {
            service = "HTTPS"
        } else {
            service = "HTTP"
        }
        
        // Try to find server info in format "Server: Apache/2.4.29"
        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 ScanResult{Port: 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)
    }
}

識(shí)別正在運(yùn)行的服務(wù)

兩種主要的服務(wù)檢測策略:

  • 基于端口識(shí)別:通過映射到公共端口號(hào)(例如,端口 80 是 HTTP),對(duì)服務(wù)有一個(gè)可能的猜測。
  • 旗標(biāo)分析:獲取旗標(biāo)文本并查找服務(wù)標(biāo)識(shí)符和版本信息。

第一個(gè)函數(shù) grabBanner 旨在從服務(wù)中獲取第一個(gè)響應(yīng)。有些服務(wù)(如 HTTP)要求發(fā)送請(qǐng)求并接收回復(fù),為此我們會(huì)添加特定案例來處理這種情況。

基本版本檢測

版本檢測對(duì)于漏洞的識(shí)別至關(guān)重要。在可能的情況下,掃描器會(huì)解析服務(wù)旗標(biāo)以獲取版本信息:

  • SSH:通常會(huì)以 SSH-2.0-OpenSSH_7.4 這樣的形式提供版本信息。
  • HTTP 服務(wù)器:通常會(huì)在響應(yīng)頭中(如 Server: Apache/2.4.29)返回其版本信息。
  • 數(shù)據(jù)庫服務(wù)器:可能會(huì)在其歡迎消息中披露版本信息。

現(xiàn)在,對(duì)于每個(gè)開放端口,輸出都會(huì)返回更多信息:

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...

這種增強(qiáng)后的信息對(duì)于漏洞評(píng)估而言要具有更高的價(jià)值。

5. 漏洞檢測實(shí)現(xiàn)

既然能列出正在運(yùn)行的服務(wù)及其版本,接下來我們將實(shí)現(xiàn)針對(duì)漏洞的檢測。我們對(duì)服務(wù)信息進(jìn)行分析,并與已知漏洞進(jìn)行對(duì)比。

編寫簡單的漏洞測試

我們將根據(jù)常見服務(wù)和版本,基于已知漏洞構(gòu)建數(shù)據(jù)庫。為了簡便起見,我們將創(chuàng)建一個(gè)嵌入代碼的漏洞數(shù)據(jù)庫,但在實(shí)際場景中,掃描器很可能會(huì)查詢外部漏洞數(shù)據(jù)庫(如 CVE 或 NVD)。

現(xiàn)在進(jìn)一步完善代碼,使其能夠檢測出漏洞:

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:   "https://nvd.nist.gov/vuln/detail/CVE-2017-15906",
        },
    },
    {
        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:   "https://nvd.nist.gov/vuln/detail/CVE-2020-9490",
        },
    },
    {
        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",
        },
    },
    // Add more known vulnerabilities here
}

// checkVulnerabilities checks if a service/version combination has known vulnerabilities
func checkVulnerabilities(service, version string) []Vulnerability {
    var vulnerabilities []Vulnerability
    
    for _, vuln := range vulnerabilityDB {
        // Simple matching - in a real scanner, this would be more sophisticated
        if vuln.Service == service && strings.Contains(version, vuln.Version) {
            vulnerabilities = append(vulnerabilities, vuln.Vulnerability)
        }
    }
    
    return vulnerabilities
}

// grabBanner attempts to read the banner from an open port
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 || port == 443 || port == 8080 || port == 8443 {
        fmt.Fprintf(conn, "HEAD / HTTP/1.0\r\nHost: %s\r\n\r\n", host)
    } else {

    }
    
    reader := bufio.NewReader(conn)
    banner, err := reader.ReadString('\n')
    if err != nil {
        return "", err
    }
    
    return strings.TrimSpace(banner), nil
}

func identifyService(port int, banner string) (string, string) {
    commonPorts := map[int]string{
        21:    "FTP",
        22:    "SSH",
        23:    "Telnet",
        25:    "SMTP",
        53:    "DNS",
        80:    "HTTP",
        110:   "POP3",
        143:   "IMAP",
        443:   "HTTPS",
        3306:  "MySQL",
        5432:  "PostgreSQL",
        6379:  "Redis",
        8080:  "HTTP-Proxy",
        27017: "MongoDB",
    }
    
    service := "Unknown"
    if s, exists := commonPorts[port]; exists {
        service = s
    }
    
    version := "Unknown"
    
    lowerBanner := strings.ToLower(banner)
    
    if strings.Contains(lowerBanner, "ssh") {
        service = "SSH"
        parts := strings.Split(banner, " ")
        if len(parts) >= 2 {
            version = parts[1]
        }
    }
    
    if strings.Contains(lowerBanner, "http") || strings.Contains(lowerBanner, "apache") || 
       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 ScanResult{Port: 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:   "https://nvd.nist.gov/vuln/detail/CVE-2017-15906",
        },
    },
    {
        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:   "https://nvd.nist.gov/vuln/detail/CVE-2020-9490",
        },
    },
    {
        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",
        },
    },
    // Add more known vulnerabilities here
}

// checkVulnerabilities checks if a service/version combination has known vulnerabilities
func checkVulnerabilities(service, version string) []Vulnerability {
    var vulnerabilities []Vulnerability
    
    for _, vuln := range vulnerabilityDB {
        // Simple matching - in a real scanner, this would be more sophisticated
        if vuln.Service == service && strings.Contains(version, vuln.Version) {
            vulnerabilities = append(vulnerabilities, vuln.Vulnerability)
        }
    }
    
    return vulnerabilities
}

// grabBanner attempts to read the banner from an open port
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 || port == 443 || port == 8080 || port == 8443 {
        fmt.Fprintf(conn, "HEAD / HTTP/1.0\r\nHost: %s\r\n\r\n", host)
    } else {

    }
    
    reader := bufio.NewReader(conn)
    banner, err := reader.ReadString('\n')
    if err != nil {
        return "", err
    }
    
    return strings.TrimSpace(banner), nil
}

func identifyService(port int, banner string) (string, string) {
    commonPorts := map[int]string{
        21:    "FTP",
        22:    "SSH",
        23:    "Telnet",
        25:    "SMTP",
        53:    "DNS",
        80:    "HTTP",
        110:   "POP3",
        143:   "IMAP",
        443:   "HTTPS",
        3306:  "MySQL",
        5432:  "PostgreSQL",
        6379:  "Redis",
        8080:  "HTTP-Proxy",
        27017: "MongoDB",
    }
    
    service := "Unknown"
    if s, exists := commonPorts[port]; exists {
        service = s
    }
    
    version := "Unknown"
    
    lowerBanner := strings.ToLower(banner)
    
    if strings.Contains(lowerBanner, "ssh") {
        service = "SSH"
        parts := strings.Split(banner, " ")
        if len(parts) >= 2 {
            version = parts[1]
        }
    }
    
    if strings.Contains(lowerBanner, "http") || strings.Contains(lowerBanner, "apache") || 
       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 ScanResult{Port: 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)
            }
        }
    }
}

基于版本的漏洞匹配

針對(duì)漏洞檢測我們用簡單版本匹配方法:

  • 直接匹配:將服務(wù)類型和版本與漏洞數(shù)據(jù)庫進(jìn)行匹配。
  • 部分匹配:對(duì)于漏洞版本的匹配,我們會(huì)對(duì)版本字符串進(jìn)行限制性檢查,這樣即使版本字符串包含額外信息,也能識(shí)別出存在漏洞的系統(tǒng)。

在實(shí)際的掃描器中,匹配會(huì)更為復(fù)雜,會(huì)考慮到以下因素:

  • 版本范圍(即版本 2.4.0 至 2.4.38 受影響)
  • 特定配置的漏洞
  • 操作系統(tǒng)特定的問題
  • 更細(xì)致的版本比較

報(bào)告發(fā)現(xiàn)的情況

報(bào)告結(jié)果是漏洞檢測流程中的最后一步,需要以簡潔且具有可操作性的格式進(jìn)行。掃描器現(xiàn)在:

列出所有開放端口及其服務(wù)及版本信息

對(duì)于每個(gè)存在漏洞的服務(wù),會(huì)顯示:

  • 漏洞標(biāo)識(shí)(例如,CVE 編號(hào))
  • 漏洞描述
  • 嚴(yán)重程度評(píng)級(jí)
  • 更多信息的參考鏈接

示例輸出:

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: https://nvd.nist.gov/vuln/detail/CVE-2017-15906

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: https://nvd.nist.gov/vuln/detail/CVE-2020-9490

443     HTTPS   Unknown

這份詳盡的漏洞數(shù)據(jù)能夠幫助網(wǎng)絡(luò)安全專家迅速找出并排序出需要解決的安全問題。

最后完善與使用方法

現(xiàn)在已經(jīng)有了一個(gè)具備服務(wù)檢測和漏洞匹配功能的基本漏洞掃描器;我們對(duì)其進(jìn)行完善,以便在實(shí)際應(yīng)用中更具實(shí)用性。

命令行參數(shù)

掃描器可以通過命令行標(biāo)志進(jìn)行配置,這些標(biāo)志能夠設(shè)定目標(biāo)、端口范圍以及掃描選項(xiàng)。使用 Go 的 flag 包進(jìn)行配置非常簡單。

添加命令行參數(shù):

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
}{
    // ... (same as before)
}


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 || *startPortPtr > 65535 {
        fmt.Println("Error: starting port must be between 1 and 65535")
        os.Exit(1)
    }
    if *endPortPtr < 1 || *endPortPtr > 65535 {
        fmt.Println("Error: ending port must be between 1 and 65535")
        os.Exit(1)
    }
    if *startPortPtr > *endPortPtr {
        fmt.Println("Error: starting port must be less than or equal to ending port")
        os.Exit(1)
    }
    
    timeout := time.Duration(*timeoutPtr) * time.Millisecond
    
    var outputFile *os.File
    var err error
    
    if *outputFilePtr != "" {
        outputFile, err = os.Create(*outputFilePtr)
        if err != nil {
            fmt.Printf("Error creating output file: %v\n", err)
            os.Exit(1)
        }
        defer outputFile.Close()
    } else {
        outputFile = os.Stdout
    }
    
    fmt.Fprintf(outputFile, "Scanning %s from port %d to %d\n", *hostPtr, *startPortPtr, *endPortPtr)
    startTime := time.Now()
    
    var results []ScanResult
    var wg sync.WaitGroup
    
    resultChan := make(chan ScanResult, *endPortPtr-*startPortPtr+1)
    
    semaphore := make(chan struct{}, *concurrencyPtr)
    
    for port := *startPortPtr; port <= *endPortPtr; port++ {
        wg.Add(1)
        go func(p int) {
            defer wg.Done()
            
            semaphore <- struct{}{}
            defer func() { <-semaphore }()
            
            result := scanPort(*hostPtr, p, timeout)
            resultChan <- result
        }(port)
    }
    
    go func() {
        wg.Wait()
        close(resultChan)
    }()
    
    for result := range resultChan {
        if result.State {
            results = append(results, result)
        }
    }
    
    elapsed := time.Since(startTime)
    
    switch *formatPtr {
    case "json":
        outputJSON(outputFile, results, elapsed)
    case "csv":
        outputCSV(outputFile, results, elapsed, *verbosePtr)
    default:
        outputText(outputFile, results, elapsed, *verbosePtr)
    }
}

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, ",") || strings.Contains(s, "\"") || strings.Contains(s, "\n") {
        return "\"" + strings.ReplaceAll(s, "\"", "\"\"") + "\""
    }
    return s
}

輸出格式

掃描器現(xiàn)在可以輸出三種格式:

  • 文本:易于閱讀,易于編寫,非常適合交互使用。
  • JSON:結(jié)構(gòu)化輸出,適用于機(jī)器處理以及與其他工具的集成。
  • CSV:電子表格兼容的格式,用于分析和報(bào)告。

輸出文本還會(huì)提供更多信息,例如如果設(shè)置了詳細(xì)模式,則會(huì)提供原始旗標(biāo)信息,對(duì)于調(diào)試或深入分析也非常方便。

示例用法及結(jié)果

如果打算將掃描器用于不同場合,以下是一些可能的選擇:

單個(gè)主機(jī)的基本掃描:

$ go run main.go -host example.com

掃描指定端口范圍:

$ go run main.go -host example.com -start 80 -end 443

增加超時(shí)和詳細(xì)信息:

$ go run main.go -host example.com -verbose -timeout 2000

以更高的并發(fā)性掃描以獲得更快的結(jié)果:

$ go run main.go -host example.com -concurrency 200

示例文本輸出:

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: https://nvd.nist.gov/vuln/detail/CVE-2017-15906

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: https://nvd.nist.gov/vuln/detail/CVE-2020-9490

443     HTTPS   nginx/1.18.0:

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": "https://nvd.nist.gov/vuln/detail/CVE-2017-15906"
        }
      ]
    },
    {
      "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": "https://nvd.nist.gov/vuln/detail/CVE-2020-9490"
        }
      ]
    },
    {
      "Port": 443,
      "State": true,
      "Service": "HTTPS",
      "Banner": "HTTP/1.1 200 OK\r\nServer: nginx/1.18.0",
      "Version": "nginx/1.18.0",
      "Vulnerabilities": []
    }
  ]
}

我們用 Go 語言構(gòu)建了一個(gè)強(qiáng)大的網(wǎng)絡(luò)漏洞掃描器,這表明該語言非常適合用于安全工具。掃描器能迅速打開端口,識(shí)別端口上運(yùn)行的服務(wù),并判斷是否存在已知漏洞。

掃描器提供了有關(guān)網(wǎng)絡(luò)上運(yùn)行的服務(wù)的有用信息,包括多線程、服務(wù)指紋識(shí)別以及多種輸出格式。

請(qǐng)記住,像掃描器這樣的工具只能在符合道德和法律規(guī)范的條件下使用,并且需要獲得對(duì)目標(biāo)系統(tǒng)的掃描授權(quán)。如果操作得當(dāng),定期進(jìn)行漏洞掃描是良好安全態(tài)勢的重要組成部分,能夠幫助保護(hù)系統(tǒng)免受威脅。可以在 GitHub 上找到該項(xiàng)目的完整源代碼。

到此這篇關(guān)于基于Golang構(gòu)建一個(gè)網(wǎng)絡(luò)漏洞掃描器的文章就介紹到這了,更多相關(guān)Go網(wǎng)絡(luò)漏洞掃描器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang接收post和get請(qǐng)求參數(shù)處理

    golang接收post和get請(qǐng)求參數(shù)處理

    本文主要介紹了golang接收post和get請(qǐng)求參數(shù)處理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • Go語言基礎(chǔ)之網(wǎng)絡(luò)編程全面教程示例

    Go語言基礎(chǔ)之網(wǎng)絡(luò)編程全面教程示例

    這篇文章主要為大家介紹了Go語言基礎(chǔ)之網(wǎng)絡(luò)編程全面教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • go grpc高級(jí)用法

    go grpc高級(jí)用法

    RPC是遠(yuǎn)程過程調(diào)用,可以像調(diào)用本地服務(wù)一樣取調(diào)用遠(yuǎn)程服務(wù),本文主要介紹了go grpc高級(jí)用法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • golang第三方庫mux的實(shí)現(xiàn)

    golang第三方庫mux的實(shí)現(xiàn)

    Gorilla/mux 是 Go 語言中功能更全面的路由庫,支持參數(shù)匹配、正則、中間件、子路由分組等,本文主要介紹了golang第三方庫mux的實(shí)現(xiàn),感興趣的可以了解一下
    2025-06-06
  • Golang?動(dòng)態(tài)腳本調(diào)研詳解

    Golang?動(dòng)態(tài)腳本調(diào)研詳解

    這篇文章主要為大家介紹了Golang?動(dòng)態(tài)腳本調(diào)研詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • GO語言匿名函數(shù)的幾種使用方式

    GO語言匿名函數(shù)的幾種使用方式

    本文主要介紹了GO語言匿名函數(shù)的幾種使用方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-08-08
  • go語言中使用ent做關(guān)聯(lián)查詢的示例詳解

    go語言中使用ent做關(guān)聯(lián)查詢的示例詳解

    go語言的ent框架是facebook開源的ORM框架,是go語言開發(fā)中的常用框架,而關(guān)聯(lián)查詢又是日常開發(fā)中的常見數(shù)據(jù)庫操作,故文本給出一個(gè)使用ent做關(guān)聯(lián)查詢的使用示例,需要的朋友可以參考下
    2024-02-02
  • go語言標(biāo)準(zhǔn)庫expvar監(jiān)控工具的實(shí)現(xiàn)

    go語言標(biāo)準(zhǔn)庫expvar監(jiān)控工具的實(shí)現(xiàn)

    Go語言的expvar標(biāo)準(zhǔn)庫是專為暴露程序內(nèi)部指標(biāo)設(shè)計(jì)的輕量級(jí)監(jiān)控工具,支持通過HTTP接口以JSON格式實(shí)時(shí)查看運(yùn)行狀態(tài),本文就來詳細(xì)的介紹一下go語言標(biāo)準(zhǔn)庫expvar監(jiān)控工具的實(shí)現(xiàn),感興趣的可以了解一下
    2026-04-04
  • Golang 經(jīng)典校驗(yàn)庫 validator 用法解析

    Golang 經(jīng)典校驗(yàn)庫 validator 用法解析

    這篇文章主要為大家介紹了Golang 經(jīng)典校驗(yàn)庫 validator 用法解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • golang語言map全方位介紹

    golang語言map全方位介紹

    本文主要介紹了golang語言map全方位介紹,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01

最新評(píng)論

祥云县| 莱西市| 汪清县| 无棣县| 临安市| 武夷山市| 郴州市| 罗平县| 兴安县| 卓资县| 仙居县| 汉源县| 乐亭县| 鄂州市| 修文县| 广河县| 长顺县| 郓城县| 如东县| 台中市| 嵩明县| 清丰县| 东乡县| 南澳县| 通江县| 花莲市| 大名县| 贵德县| 武功县| 滕州市| 大理市| 高平市| 多伦县| 渝北区| 海阳市| 高阳县| 龙口市| 富蕴县| 志丹县| 伊川县| 怀柔区|