实现原理
tcp扫描
创建tcp客户端然后与目标地址的每个端口建立连接,如果能连接成功说明目标地址此端口已经被打开。
判断是什么协议
- 连接成功后读取字节,如ssh协议的端口会读取到如这种的数据
SSH-2.0-OpenSSH_7.4
; - 创建http/s客户端与已经扫描出来的端口进行请求,返回数据如
&{403 Forbidden 403 HTTP/1.1 1 1 map[Content-Length:[548] Content-Type:[text/html] Date:[Thu, 09 Jun 2022 08:16:50 GMT] Server:[nginx]] 0xc0015ba2e0 548 [] true false map[] 0xc0015d0400 <nil>}
代码实现
package main
import (
"fmt"
"log"
"net"
"runtime"
"strconv"
"strings"
"sync"
"time"
gt "github.com/mangenotwork/gathertool"
)
// 队列
type Queue struct {
mux *sync.Mutex
list []int
}
// Add 向队列中添加元素
func (q *Queue) Add(i int) error {
q.mux.Lock()
defer q.mux.Unlock()
q.list = append(q.list,i)
return nil
}
// Poll 移除队列中最前面的额元素
func (q *Queue) Poll() int {
q.mux.Lock()
defer q.mux.Unlock()
if q.IsEmpty() {
return 0
}
first := q.list[0]
q.list = q.list[1:]
return first
}
func (q *Queue) IsEmpty() bool {
if len(q.list) == 0 {
return true
}
return false
}
func main(){
gt.CloseLog()
runtime.GOMAXPROCS(runtime.NumCPU())
ip := "192.168.0.197"
q := &Queue{
mux : &sync.Mutex{},
list : make([]int,0),
}
for i:=1; i<65000;i++ {
_=q.Add(i)
}
var wg sync.WaitGroup
for job:=0;job<888;job++{
wg.Add(1)
go func(i int){
defer wg.Done()
for {
port := q.Poll()
if port == 0 {
break
}
ok, conn := ScanPort(ip, port)
if ok{
addr := fmt.Sprintf("%s:%d", ip, port)
log.Println(fmt.Sprintf("%s:%d is open", ip, port))
// 判断是什么
// 1. 判断 读取 net.Conn 返回
readTimeout := 3*time.Second
buffer := make([]byte, 1024)
err := conn.SetReadDeadline(time.Now().Add(readTimeout)) // timeout
if err != nil {
log.Println("setReadDeadline failed:", err)
}
_, _ = conn.Read(buffer)
bufStr := string(buffer)
if strings.Index(bufStr, "SSH") != -1 {
log.Println("扫描出 --> ", addr, " [ssh端口], msg: ", bufStr)
break
}
if strings.Index(bufStr, "mysql") != -1 {
log.Println("扫描出 --> ", addr, " [mysql端口], msg: ", bufStr)
break
}
_= conn.Close()
if port == 80 {
ctx, err := gt.Get("http://"+addr)
if err != nil {
log.Println("扫描出 --> ", addr, " [http端口] 网络不可到", err)
}else {
log.Println("扫描出 --> ", addr, " [http端口] ",ctx.Resp)
}
break
}
if port == 443 {
ctx, err := gt.Get("https://"+addr)
if err != nil {
log.Println("扫描出 --> ", addr, " [https端口] 网络不可到", err)
}else {
log.Println("扫描出 --> ", addr, " [https端口] ",ctx.Resp)
}
break
}
// 2. 判断是否 http/s 协议
ctxHttp, err := gt.Get("http://"+addr)
if err == nil {
log.Println("扫描出 --> ", addr, " [http端口] ",ctxHttp.Resp)
break
}
ctxHttps, err := gt.Get("https://"+addr)
if err == nil {
log.Println("扫描出 --> ", addr, " [http端口] ",ctxHttps.Resp)
break
}
}
}
}(job)
}
wg.Wait()
}
func ScanPort(hostname string, port int) (bool, net.Conn) {
//fmt.Printf("scanning port %d \n", port)
p := strconv.Itoa(port)
addr := net.JoinHostPort(hostname, p)
conn, err := net.DialTimeout("tcp", addr, 5*time.Second)
if err != nil {
return false, nil
}
return true, conn
}
// 需求,扫描端口 并查看是什么协议
// 暴力 ssh, mysql, redis
//