乐趣区

关于go:Go渗透测试编程二TCP扫描器和代理

留神

因为系列文章仅是我在浏览 BHG 时进行的一些记录,并不是一个很谨严的教程,且本章题目会追随书的章节目录。


TCP 协定

传输控制协议(Transmission Control Protocel,TCP)是面向连贯的牢靠通信的次要规范,以及古代网络的根底。BHG 要求咱们可能从 TCP 的工作原理动手,开发能够辨认关上 / 敞开的端口,通过端口转发绕过进口限度。

TCP 的握手机制

分为以下三种状况

  1. 端口凋谢
    如果端口是凋谢的,就会进行经典的三次握手:syn->syn-ack->ack;
  2. 端口敞开
    如果端口敞开,服务器会以 rst 数据包而非 syn-ack 数据包进行响应;
  3. 防火墙过滤
    如果流量被防火墙过滤,客户端通常不会从服务器收到任何响应;

编写 TCP 扫描器

通过编写一个端口扫描器去了解 TCP 握手过程以及 3 种端口状态,以确定 TCP 端口是否可用,或者已敞开和应用过滤状态进行响应

Go 的 net 包

通过 net.Dial(network, address string),启动客户端到服务端的连贯
network 参数:字符串类型,用于标识要启动的连贯的类型。Dial 不仅实用于 TCP,还能够用于创立 UNIX 套接字、UDP 和第 4 层协定的连贯
address 参数:字符串类型,标识要连贯的主机。对于 IPv4/TCP 连贯,应用 host:port 的模式
返回值:Conn,err;若连贯胜利,err 为 nil

示例:根本的单端口扫描器

package main

import (
    "fmt"
    "net"
)

func main() {_, err := net.Dial("tcp", "scanme.namp.org:80")
    if err == nil {fmt.Println("Connection successful")
    }
}

示例:非并发多端口扫描器

package main

import (
    "fmt"
    "net"
)

func main() {
    for i := 1; i <= 1024; i++ {address := fmt.Sprintf("scanme.nmap.org:%d", i)
        connm err := net.Dial("tcp", address)
        if err != nil {continue}
        conn.Close()
        fmt.Println("%d open\n", i)
    }
}

示例:并发扫描器

package main

import (
    "fmt"
    "net"
    "sync"
)

func main() {
    // 同步计数器
    var wg sync.WaitGroup
    // 扫描前 1024 个端口
    for i := 1; i < 1024; i++ {wg.Add(1)
        // 启动 goroutine
        go func(j int) {
            // 延后至外层函数返回时执行
            defer wg.Done()
            address := fmt.Sprintf("scanme.nmap.org:%d", j)
            conn, err := net.Dial("tcp", address)
            if err != nil {return}
            conn.Close()
            fmt.Printf("%d open\n", j)
        }(i)
    }
    // 函数阻塞,期待同步计数器为 0
    wg.Wait()}
毛病:扫描过多的主机或端口,可能会导致网络或零碎限度,造成后果不正确

应用 goroutine 池治理正在进行的并发工作,通过 for 循环创立肯定数量的 worker goroutine 作为资源池

示例:worker
import (
    "fmt"
    "net"
    "sort"
)
//parameter:
//ports: int 类型的通道,用于接管工作
//results: int 类型的通道,用于接管后果
func worker(ports, results chan int){
    for p := range ports {address := fmt.Sprintf("scanme.nmap.org:%d", p)
        conn, err = net.Dial("tcp", address)
        if err != nil {
            // 端口敞开,接管 0
            results <- 0
            continue
        }
        conn.Close()
        // 端口关上,接管端口号
        results <- p
    }
}
func main() {
    // 应用 make 函数创立通道
    ports := make(chan int, 100)
    results := make(chan int)
    var openports []int
    // cap 函数计算通道的容量
    // for 循环启动所需数量的 worker goroutine
    for i := 0; i < cap(ports); i++ {go worker(ports, results)
    }
    // 匿名函数
    go func() {
        for i := 1; i <= 1024; i++ {ports <- i}
    }()
    for i := 0; i < 1024; i++ {
        port := <-results
        if port != 0 {openports = append(openports, port)
        }
    }
    close(ports)
    close(results)
    // 切片排序
    sort.Ints(openports)
    for _, port := range openports {fmt.Printf("%d open\n", port)
    }
}

结构 TCP 代理

构建回显服务器(仅回显给定响应到服务器)

io.Reader

type Reader interface {Read(p []byte) (n int, err error)
}

io.Writer

type Writer interface {Write(p []byte) (n int, err error)
}

net.Conn:Go 面向流的网络连接
Conn 实现了针对接口 Reader 和 Writer 定义的函数 Read([]byte) 和 Write([]byte), 即 Conn 即是 Reader 也是 Writer—->TCP 是双向连贯,能够发送或接收数据

回显服务器构建流程

1. 应用 net.Listen(network, address string)在特定端口上关上 TCP 监听器
2.listener.Accpet()期待客户端连贯胜利后,创立并返回一个 Conn 对象,应用该对象接管和发送数据
退出移动版