參考連結
如需轉載,請註明出處。
作者:w7ay@知道創宇404實驗室
日期:2019年10月12日
Zmap和Masscan都是號稱能夠快速掃描網際網路的掃描器,十一因為無聊,看了下它們的程式碼實現,發現它們能夠快速掃描,原理其實很簡單,就是實現兩種程式,一個傳送程式,一個抓包程式,讓傳送和接收分隔開從而實現了速度的提升。但是它們識別的準確率還是比較低的,所以就想了解下為什麼準確率這麼低以及應該如何改善。
首先是看的
的原始碼,在readme上有它的一些設計思想,它指引我們看
main.c
中的入口函式
main()
,以及傳送函式和接收函式
transmit_thread()
和
receive_thread()
,還有一些簡單的原理解讀。
在後面自己寫掃描器的過程中,對Masscan的掃描速度產生懷疑,目前Masscan是號稱6分鐘掃描全網,以每秒1000萬的發包速度。
但是255^4/10000000/60 ≈ 7.047 ???
之後瞭解到,預設模式下Masscan使用
pcap
傳送和接收資料包,它在Windows和Mac上只有30萬/秒的發包速度,而Linux可以達到150萬/秒,如果安裝了PF_RING DNA裝置,它會提升到1000萬/秒的發包速度(這些前提是硬體裝置以及頻寬跟得上)。
注意,這只是按照掃描 一個埠的計算。
PF_RING DNA裝置瞭解地址:
在Zmap的 上說明了
用PF_RING驅動,可以在5分鐘掃描全網,而預設模式才是45分鐘,Masscan的預設模式計算一下也是45分鐘左右才掃描完,這就是宣傳的差距嗎 (-
觀察了readme的歷史記錄
之前構建時會提醒安裝
libpcap-dev
,但是後面沒有了,從releases上看,是將靜態編譯的
libpcap
改為了動態載入。
c10k也叫做client 10k,就是一個客戶端在硬體效能足夠條件下如何處理超過1w的連線請求。Masscan把它叫做C10M問題。
Masscan的解決方法是不透過系統核心呼叫函式,而是直接呼叫相關驅動。
主要透過下面三種方式:
rings
來進行一些需要同步的操作。與之對比一下Zmap,很多地方都用到了鎖。
src/output.c
中,
在讀取地址後,如果進行順序掃描,虛擬碼如下
for (i = 0; i < range; i++) { scan(i);}
但是考慮到有的網段可能對掃描進行檢測從而封掉整個網段,順序掃描效率是較低的,所以需要將地址進行隨機的打亂,用演算法描述就是設計一個
打亂陣列的演算法
,Masscan是設計了一個加密演算法,虛擬碼如下
range = ip_count * port_count;for (i = 0; i < range; i++) { x = encrypt(i); ip = pick(addresses, x / port_count); port = pick(ports, x % port_count); scan(ip, port);}
隨機種子就是
i
的值,這種加密演算法能夠建立一種一一對應的對映關係,即在[1...range]的區間內透過
i
來生成[1...range]內不重複的隨機數。同時如果中斷了掃描,只需要記住
i
的值就能重新啟動,在分散式上也可以根據
i
來進行。
回顧一下tcp協議中三次握手的前兩次
在收到syn和ack後,我們返回一個rst來結束這個連線,如下圖所示
Masscan和Zmap的掃描原理,就是利用了這一步,因為seq是我們可以自定義的,所以在傳送資料包時填充一個特定的數字,而在返回包中可以獲得相應的響應狀態,即是無狀態掃描的思路了。 接下來簡單看下Masscan中發包以及接收的程式碼。
在
main.c
中,前面說的隨機化地址掃描
接著生成cookie併傳送
uint64_tsyn_cookie( unsigned ip_them, unsigned port_them, unsigned ip_me, unsigned port_me, uint64_t entropy){ unsigned data[4]; uint64_t x[2]; x[0] = entropy; x[1] = entropy; data[0] = ip_them; data[1] = port_them; data[2] = ip_me; data[3] = port_me; return siphash24(data, sizeof(data), x);}
看名字我們知道,生成cookie的因子有源ip,源埠,目的ip,目的埠,和entropy(隨機種子,Masscan初始時自動生成),siphash24是一種高效快速的雜湊函式,常用於網路流量身份驗證和針對雜湊dos攻擊的防禦。
組裝tcp協議
template_set_target()
,部分程式碼
case Proto_TCP: px[offset_tcp+ 0] = (unsigned char)(port_me >> 8); px[offset_tcp+ 1] = (unsigned char)(port_me & 0xFF); px[offset_tcp+ 2] = (unsigned char)(port_them >> 8); px[offset_tcp+ 3] = (unsigned char)(port_them & 0xFF); px[offset_tcp+ 4] = (unsigned char)(seqno >> 24); px[offset_tcp+ 5] = (unsigned char)(seqno >> 16); px[offset_tcp+ 6] = (unsigned char)(seqno >> 8); px[offset_tcp+ 7] = (unsigned char)(seqno >> 0); xsum += (uint64_t)tmpl->checksum_tcp + (uint64_t)ip_me + (uint64_t)ip_them + (uint64_t)port_me + (uint64_t)port_them + (uint64_t)seqno; xsum = (xsum >> 16) + (xsum & 0xFFFF); xsum = (xsum >> 16) + (xsum & 0xFFFF); xsum = (xsum >> 16) + (xsum & 0xFFFF); xsum = ~xsum; px[offset_tcp+16] = (unsigned char)(xsum >> 8); px[offset_tcp+17] = (unsigned char)(xsum >> 0); break;
發包函式
/*************************************************************************** * wrapper for libpcap's sendpacket * * PORTABILITY: WINDOWS and PF_RING * For performance, Windows and PF_RING can queue up multiple packets, then * transmit them all in a chunk. If we stop and wait for a bit, we need * to flush the queue to force packets to be transmitted immediately. ***************************************************************************/intrawsock_send_packet( struct Adapter *adapter, const unsigned char *packet, unsigned length, unsigned flush){ if (adapter == 0) return 0; /* Print --packet-trace if debugging */ if (adapter->is_packet_trace) { packet_trace(stdout, adapter->pt_start, packet, length, 1); } /* PF_RING */ if (adapter->ring) { int err = PF_RING_ERROR_NO_TX_SLOT_AVAILABLE; while (err == PF_RING_ERROR_NO_TX_SLOT_AVAILABLE) { err = PFRING.send(adapter->ring, packet, length, (unsigned char)flush); } if (err < 0) LOG(1, "pfring:xmit: ERROR %d\n", err); return err; } /* WINDOWS PCAP */ if (adapter->sendq) { int err; struct pcap_pkthdr hdr; hdr.len = length; hdr.caplen = length; err = PCAP.sendqueue_queue(adapter->sendq, &hdr, packet); if (err) { rawsock_flush(adapter); PCAP.sendqueue_queue(adapter->sendq, &hdr, packet); } if (flush) { rawsock_flush(adapter); } return 0; } /* LIBPCAP */ if (adapter->pcap) return PCAP.sendpacket(adapter->pcap, packet, length); return 0;}
可以看到它是分三種模式發包的,
PF_RING
,
WinPcap
,
LibPcap
,如果沒有裝相關驅動的話,預設就是pcap發包。如果想使用PF_RING模式,只需要加入啟動引數
--pfring
在接收執行緒看到一個關於cpu的程式碼
大意是鎖住這個執行緒執行的cpu,讓傳送執行緒執行在雙數cpu上,接收執行緒執行在單數cpu上。但程式碼沒怎麼看懂
接收原始資料包
int rawsock_recv_packet( struct Adapter *adapter, unsigned *length, unsigned *secs, unsigned *usecs, const unsigned char **packet){ if (adapter->ring) { /* This is for doing libpfring instead of libpcap */ struct pfring_pkthdr hdr; int err; again: err = PFRING.recv(adapter->ring, (unsigned char**)packet, 0, /* zero-copy */ &hdr, 0 /* return immediately */ ); if (err == PF_RING_ERROR_NO_PKT_AVAILABLE || hdr.caplen == 0) { PFRING.poll(adapter->ring, 1); if (is_tx_done) return 1; goto again; } if (err) return 1; *length = hdr.caplen; *secs = (unsigned)hdr.ts.tv_sec; *usecs = (unsigned)hdr.ts.tv_usec; } else if (adapter->pcap) { struct pcap_pkthdr hdr; *packet = PCAP.next(adapter->pcap, &hdr); if (*packet == NULL) { if (is_pcap_file) { //pixie_time_set_offset(10*100000); is_tx_done = 1; is_rx_done = 1; } return 1; } *length = hdr.caplen; *secs = (unsigned)hdr.ts.tv_sec; *usecs = (unsigned)hdr.ts.tv_usec; } return 0;}
主要是使用了PFRING和PCAP的api來接收。後面便是一系列的接收後的處理了。在
mian.c
757行
後面還會判斷是否為源ip,判斷方式不是相等,是判斷某個範圍。
int is_my_port(const struct Source *src, unsigned port){ return src->port.first <= port && port <= src->port.last;}
接著後面的處理
if (TCP_IS_SYNACK(px, parsed.transport_offset) || TCP_IS_RST(px, parsed.transport_offset)) { // 判斷是否是syn+ack或rst標誌位 /* 獲取狀態 */ status = PortStatus_Unknown; if (TCP_IS_SYNACK(px, parsed.transport_offset)) status = PortStatus_Open; // syn+ack 說明埠開放 if (TCP_IS_RST(px, parsed.transport_offset)) { status = PortStatus_Closed; // rst 說明埠關閉 } /* verify: syn-cookies 校驗cookie是否正確 */ if (cookie != seqno_me - 1) { LOG(5, "%u.%u.%u.%u - bad cookie: ackno=0x%08x expected=0x%08x\n", (ip_them>>24)&0xff, (ip_them>>16)&0xff, (ip_them>>8)&0xff, (ip_them>>0)&0xff, seqno_me-1, cookie); continue; } /* verify: ignore duplicates 校驗是否重複*/ if (dedup_is_duplicate(dedup, ip_them, port_them, ip_me, port_me)) continue; /* keep statistics on number received 統計接收的數字*/ if (TCP_IS_SYNACK(px, parsed.transport_offset)) (*status_synack_count)++; /* * This is where we do the output * 這是輸出狀態了 */ output_report_status( out, global_now, status, ip_them, 6, /* ip proto = tcp */ port_them, px[parsed.transport_offset + 13], /* tcp flags */ parsed.ip_ttl, parsed.mac_src ); /* * Send RST so other side isn't left hanging (only doing this in * complete stateless mode where we aren't tracking banners) */ // 傳送rst給服務端,防止服務端一直等待。 if (tcpcon == NULL && !Masscan->is_noreset) tcp_send_RST( &parms->tmplset->pkts[Proto_TCP], parms->packet_buffers, parms->transmit_queue, ip_them, ip_me, port_them, port_me, 0, seqno_me);}
Zmap官方有一篇 ,講述了Zmap的原理以及一些實踐。上文說到Zmap使用的發包技術和Masscan大同小異,高速模式下都是呼叫pf_ring的驅動進行,所以對這些就不再敘述了,主要說下其他與Masscan不同的地方,paper中對丟包問題以及掃描時間段有一些研究,簡單整理下
還有一點是Zmap只能掃描單個埠,看了一下程式碼,這個儲存埠變數的作用也只是在最後接收資料包用來判斷srcport用,不明白為什麼還沒有加上多埠的支援。
相比於Masscan用
rate=10000
作為限制引數,Zmap用
-B 10M
的方式來限制
我覺得這點很好,因為不是每個使用者都能明白每個引數代表的原理。實現細節
Zmap不支援Windows,因為Zmap的發包預設用的是socket,在window下可能不支援tcp的組包(猜測)。相比之下Masscan使用的是pcap發包,在win/linux都有支援的程式。Zmap接收預設使用的是pcap。
在構造tcp包時,附帶的狀態資訊會填入到seq和srcport中
在解包時,先判斷返回dstport的資料
再判斷返回的ack中的資料
在瞭解完以上後,我就準備用go寫一款類似的掃描器了,希望能解決丟包的問題,順便學習go。
在上面分析中知道了,Masscan和Zmap都使用了pcap,pfring這些元件來原生髮包,值得高興的是go官方也有原生支援這些的包 ,而且完美符合我們的要求。
介面沒問題,在實現了基礎的無狀態掃描功能後,接下來就是如何處理丟包的問題。
按照tcp協議的原理,我們傳送一個資料包給目標機器,埠開放時返回
ack
標記,關閉會返回
rst
標記。
但是透過掃描一臺外網的靶機,發現掃描幾個埠是沒問題的,但是掃描大批次的埠(1-65535),就可能造成丟包問題。而且不存在的埠不會返回任何資料。
剛開始以為是速度太快了,所以先控制下每秒傳送的頻率。因為傳送和接收都是啟動了一個goroutine,目標的傳入是透過一個channel傳入的(go的知識點)。
所以控制速率的虛擬碼類似這樣
rate := 300 // 每秒速度var data = []int{1, 2, 3, 4, 5, 6,...,65535} // 埠陣列ports := make(chan int, rate)go func() { // 每秒將data資料分配到ports index := 0 for { OldTimestap := time.Now().UnixNano() / 1e6 // 取毫秒 for i := index; i < index+rate; i++ { if len(datas) <= index { break } index++ distribution <- data[i] } if len(datas) <= index { break } Timestap := time.Now().UnixNano() / 1e6 TimeTick := Timestap - OldTimestap if TimeTick < 1000 { time.Sleep(time.Duration(1000-TimeTick) * time.Millisecond) } } fmt.Println("傳送完畢..") }()
即使將速度控制到了最小,也存在丟包的問題,後經過一番測試,發現是防火牆的原因。例如常用的
iptables
,其中拒絕的埠不會返回資訊。將埠放行後再次掃描,就能正常返回資料包了。
此時遇到的問題是有防火牆策略的主機如何進行準確掃描,一種方法是掃描幾個埠後就延時一段時間,但這不符合快速掃描的設想,所以我的想法是維護一個本地的狀態表,狀態表中能夠動態修改每個掃描結果的狀態,將那些沒有返回包的目標進行重試。
Ps:這是針對一個主機,多埠(1-65535)的掃描策略,如果是多個IP,Masscan的
隨機化地址掃描
策略就能發揮作用了。
設想的結構如下
// 本地狀態表的資料結構type ScanData struct { ip string port int time int64 // 傳送時間 retry int // 重試次數 status int // 0 未傳送 1 已傳送 2 已回覆 3 已放棄}
初始資料時
status
為0,當傳送資料時,將
status
變更為1,同時記錄傳送時間
time
,接收資料時透過返回的標記,
dstport
,
seq
等查詢到本地狀態表相應的資料結構,變更
status
為2,同時啟動一個監控程式,監控程式每隔一段時間對所有的狀態進行檢查,如果發現
stauts
為1並且當前時間-傳送時間大於一定值的時候,可以判斷這個ip+埠的探測包丟失了,準備重發,將
retry
+1,重新設定傳送時間
time
後,將資料傳入傳送的channel中。
因為只是概念驗證程式,而且是自己組包傳送,需要使用到本地和閘道器的mac地址等,這些還沒有寫自動化程式獲取,需要手動填寫。mac地址可以手動用wireshark抓包獲得。
如果你想使用該程式的話,需要修改全域性變數中的這些值
var ( SrcIP string = "10.x.x.x" // 源IP DstIp string = "188.131.x.x" // 目標IP device string = "en0" // 網路卡名稱 SrcMac net.HardwareAddr = net.HardwareAddr{0xf0, 0x18, 0x98, 0x1a, 0x57, 0xe8} // 源mac地址 DstMac net.HardwareAddr = net.HardwareAddr{0x5c, 0xc9, 0x99, 0x33, 0x37, 0x80} // 閘道器mac地址)
整個go語言源程式如下,單檔案。
package mainimport ( "fmt" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" "log" "net" "sync" "time")var ( SrcIP string = "10.x.x.x" // 源IP DstIp string = "188.131.x.x" // 目標IP device string = "en0" // 網路卡名稱 SrcMac net.HardwareAddr = net.HardwareAddr{0xf0, 0x18, 0x98, 0x1a, 0x57, 0xe8} // 源mac地址 DstMac net.HardwareAddr = net.HardwareAddr{0x5c, 0xc9, 0x99, 0x33, 0x37, 0x80} // 閘道器mac地址)// 本地狀態表的資料結構type ScanData struct { ip string port int time int64 // 傳送時間 retry int // 重試次數 status int // 0 未傳送 1 已傳送 2 已回覆 3 已放棄}func recv(datas *[]ScanData, lock *sync.Mutex) { var ( snapshot_len int32 = 1024 promiscuous bool = false timeout time.Duration = 30 * time.Second handle *pcap.Handle ) handle, _ = pcap.OpenLive(device, snapshot_len, promiscuous, timeout) // Use the handle as a packet source to process all packets packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) scandata := *datas for { packet, err := packetSource.NextPacket() if err != nil { continue } if IpLayer := packet.Layer(layers.LayerTypeIPv4); IpLayer != nil { if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil { tcp, _ := tcpLayer.(*layers.TCP) ip, _ := IpLayer.(*layers.IPv4) if tcp.Ack != 111223 { continue } if tcp.SYN && tcp.ACK { fmt.Println(ip.SrcIP, " port:", int(tcp.SrcPort)) _index := int(tcp.DstPort) lock.Lock() scandata[_index].status = 2 lock.Unlock() } else if tcp.RST { fmt.Println(ip.SrcIP, " port:", int(tcp.SrcPort), " close") _index := int(tcp.DstPort) lock.Lock() scandata[_index].status = 2 lock.Unlock() } } } //fmt.Printf("From src port %d to dst port %d\n", tcp.SrcPort, tcp.DstPort) }}func send(index chan int, datas *[]ScanData, lock *sync.Mutex) { srcip := net.ParseIP(SrcIP).To4() var ( snapshot_len int32 = 1024 promiscuous bool = false err error timeout time.Duration = 30 * time.Second handle *pcap.Handle ) handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout) if err != nil { log.Fatal(err) } defer handle.Close() scandata := *datas for { _index := <-index lock.Lock() data := scandata[_index] port := data.port scandata[_index].status = 1 dstip := net.ParseIP(data.ip).To4() lock.Unlock() eth := &layers.Ethernet{ SrcMAC: SrcMac, DstMAC: DstMac, EthernetType: layers.EthernetTypeIPv4, } // Our IPv4 header ip := &layers.IPv4{ Version: 4, IHL: 5, TOS: 0, Length: 0, // FIX Id: 0, Flags: layers.IPv4DontFragment, FragOffset: 0, //16384, TTL: 64, //64, Protocol: layers.IPProtocolTCP, Checksum: 0, SrcIP: srcip, DstIP: dstip, } // Our TCP header tcp := &layers.TCP{ SrcPort: layers.TCPPort(_index), DstPort: layers.TCPPort(port), Seq: 111222, Ack: 0, SYN: true, Window: 1024, Checksum: 0, Urgent: 0, } //tcp.DataOffset = 5 // uint8(unsafe.Sizeof(tcp)) _ = tcp.SetNetworkLayerForChecksum(ip) buf := gopacket.NewSerializeBuffer() err := gopacket.SerializeLayers( buf, gopacket.SerializeOptions{ ComputeChecksums: true, // automatically compute checksums FixLengths: true, }, eth, ip, tcp, ) if err != nil { log.Fatal(err) } //fmt.Println("\n" + hex.EncodeToString(buf.Bytes())) err = handle.WritePacketData(buf.Bytes()) if err != nil { fmt.Println(err) } }}func main() { version := pcap.Version() fmt.Println(version) retry := 8 var datas []ScanData lock := &sync.Mutex{} for i := 20; i < 1000; i++ { temp := ScanData{ port: i, ip: DstIp, retry: 0, status: 0, time: time.Now().UnixNano() / 1e6, } datas = append(datas, temp) } fmt.Println("target", DstIp, " count:", len(datas)) rate := 300 distribution := make(chan int, rate) go func() { // 每秒將ports資料分配到distribution index := 0 for { OldTimestap := time.Now().UnixNano() / 1e6 for i := index; i < index+rate; i++ { if len(datas) <= index { break } index++ distribution <- i } if len(datas) <= index { break } Timestap := time.Now().UnixNano() / 1e6 TimeTick := Timestap - OldTimestap if TimeTick < 1000 { time.Sleep(time.Duration(1000-TimeTick) * time.Millisecond) } } fmt.Println("傳送完畢..") }() go recv(&datas, lock) go send(distribution, &datas, lock) // 監控 for { time.Sleep(time.Second * 1) count_1 := 0 count_2 := 0 count_3 := 0 var ids []int lock.Lock() for index, data := range datas { if data.status == 1 { count_1++ if data.retry >= retry { datas[index].status = 3 continue } nowtime := time.Now().UnixNano() / 1e6 if nowtime-data.time >= 1000 { datas[index].retry += 1 datas[index].time = nowtime ids = append(ids, index) //fmt.Println("重發id:", index) //distribution <- index } } else if data.status == 2 { count_2++ } else if data.status == 3 { count_3++ } } lock.Unlock() if len(ids) > 0 { time.Sleep(time.Second) increase := 0 interval := 60 for _, v := range ids { distribution <- v increase++ if increase > 1 && increase%interval == 0 { time.Sleep(time.Second) } } } fmt.Println("status=1:", count_1, "status=2:", count_2, "status=3:", count_3) }}
執行結果如下
但這個程式並沒有解決上述說的防火牆阻斷問題,設想很美好,但是在實踐的過程中發現這樣一個問題。比如掃描一臺主機中的1000個埠,第一次掃描後由於有防火牆的策略只檢測到了5個埠,剩下995個埠會進行第一次重試,但是重試中依然會遇到防火牆的問題,所以本質上並沒有解決這個問題。
這是Masscan原始碼中一份內建的Top埠表
staticconstunsignedshorttop_tcp_ports[]={1,3,4,6,7,9,13,17,19,20,21,22,23,24,25,26,30,32,33,37,42,43,49,53,70,79,80,81,82,83,84,85,88,89,90,99,100,106,109,110,111,113,119,125,135,139,143,144,146,161,163,179,199,211,212,222,254,255,256,259,264,280,301,306,311,340,366,389,406,407,416,417,425,427,443,444,445,458,464,465,481,497,500,512,513,514,515,524,541,543,544,545,548,554,555,563,587,593,616,617,625,631,636,646,648,666,667,668,683,687,691,700,705,711,714,720,722,726,749,765,777,783,787,800,801,808,843,873,880,888,898,900,901,902,903,911,912,981,987,990,992,993,995,999,1000,1001,1002,1007,1009,1010,1011,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1102,1104,1105,1106,1107,1108,1110,1111,1112,1113,1114,1117,1119,1121,1122,1123,1124,1126,1130,1131,1132,1137,1138,1141,1145,1147,1148,1149,1151,1152,1154,1163,1164,1165,1166,1169,1174,1175,1183,1185,1186,1187,1192,1198,1199,1201,1213,1216,1217,1218,1233,1234,1236,1244,1247,1248,1259,1271,1272,1277,1287,1296,1300,1301,1309,1310,1311,1322,1328,1334,1352,1417,1433,1434,1443,1455,1461,1494,1500,1501,1503,1521,1524,1533,1556,1580,1583,1594,1600,1641,1658,1666,1687,1688,1700,1717,1718,1719,1720,1721,1723,1755,1761,1782,1783,1801,1805,1812,1839,1840,1862,1863,1864,1875,1900,1914,1935,1947,1971,1972,1974,1984,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2013,2020,2021,2022,2030,2033,2034,2035,2038,2040,2041,2042,2043,2045,2046,2047,2048,2049,2065,2068,2099,2100,2103,2105,2106,2107,2111,2119,2121,2126,2135,2144,2160,2161,2170,2179,2190,2191,2196,2200,2222,2251,2260,2288,2301,2323,2366,2381,2382,2383,2393,2394,2399,2401,2492,2500,2522,2525,2557,2601,2602,2604,2605,2607,2608,2638,2701,2702,2710,2717,2718,2725,2800,2809,2811,2869,2875,2909,2910,2920,2967,2968,2998,3000,3001,3003,3005,3006,3007,3011,3013,3017,3030,3031,3052,3071,3077,3128,3168,3211,3221,3260,3261,3268,3269,3283,3300,3301,3306,3322,3323,3324,3325,3333,3351,3367,3369,3370,3371,3372,3389,3390,3404,3476,3493,3517,3527,3546,3551,3580,3659,3689,3690,3703,3737,3766,3784,3800,3801,3809,3814,3826,3827,3828,3851,3869,3871,3878,3880,3889,3905,3914,3918,3920,3945,3971,3986,3995,3998,4000,4001,4002,4003,4004,4005,4006,4045,4111,4125,4126,4129,4224,4242,4279,4321,4343,4443,4444,4445,4446,4449,4550,4567,4662,4848,4899,4900,4998,5000,5001,5002,5003,5004,5009,5030,5033,5050,5051,5054,5060,5061,5080,5087,5100,5101,5102,5120,5190,5200,5214,5221,5222,5225,5226,5269,5280,5298,5357,5405,5414,5431,5432,5440,5500,5510,5544,5550,5555,5560,5566,5631,5633,5666,5678,5679,5718,5730,5800,5801,5802,5810,5811,5815,5822,5825,5850,5859,5862,5877,5900,5901,5902,5903,5904,5906,5907,5910,5911,5915,5922,5925,5950,5952,5959,5960,5961,5962,5963,5987,5988,5989,5998,5999,6000,6001,6002,6003,6004,6005,6006,6007,6009,6025,6059,6100,6101,6106,6112,6123,6129,6156,6346,6389,6502,6510,6543,6547,6565,6566,6567,6580,6646,6666,6667,6668,6669,6689,6692,6699,6779,6788,6789,6792,6839,6881,6901,6969,7000,7001,7002,7004,7007,7019,7025,7070,7100,7103,7106,7200,7201,7402,7435,7443,7496,7512,7625,7627,7676,7741,7777,7778,7800,7911,7920,7921,7937,7938,7999,8000,8001,8002,8007,8008,8009,8010,8011,8021,8022,8031,8042,8045,8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8093,8099,8100,8180,8181,8192,8193,8194,8200,8222,8254,8290,8291,8292,8300,8333,8383,8400,8402,8443,8500,8600,8649,8651,8652,8654,8701,8800,8873,8888,8899,8994,9000,9001,9002,9003,9009,9010,9011,9040,9050,9071,9080,9081,9090,9091,9099,9100,9101,9102,9103,9110,9111,9200,9207,9220,9290,9415,9418,9485,9500,9502,9503,9535,9575,9593,9594,9595,9618,9666,9876,9877,9878,9898,9900,9917,9929,9943,9944,9968,9998,9999,10000,10001,10002,10003,10004,10009,10010,10012,10024,10025,10082,10180,10215,10243,10566,10616,10617,10621,10626,10628,10629,10778,11110,11111,11967,12000,12174,12265,12345,13456,13722,13782,13783,14000,14238,14441,14442,15000,15002,15003,15004,15660,15742,16000,16001,16012,16016,16018,16080,16113,16992,16993,17877,17988,18040,18101,18988,19101,19283,19315,19350,19780,19801,19842,20000,20005,20031,20221,20222,20828,21571,22939,23502,24444,24800,25734,25735,26214,27000,27352,27353,27355,27356,27715,28201,30000,30718,30951,31038,31337,32768,32769,32770,32771,32772,32773,32774,32775,32776,32777,32778,32779,32780,32781,32782,32783,32784,32785,33354,33899,34571,34572,34573,35500,38292,40193,40911,41511,42510,44176,44442,44443,44501,45100,48080,49152,49153,49154,49155,49156,49157,49158,49159,49160,49161,49163,49165,49167,49175,49176,49400,49999,50000,50001,50002,50003,50006,50300,50389,50500,50636,50800,51103,51493,52673,52822,52848,52869,54045,54328,55055,55056,55555,55600,56737,56738,57294,57797,58080,60020,60443,61532,61900,62078,63331,64623,64680,65000,65129,65389};
可以使用
--top-ports = n
來選擇數量。
這是在寫完go掃描器後又在Masscan中發現的,可能想象到Masscan可能也考慮過這個問題,它的方法是維護一個top常用埠的排行來儘可能減少掃描埠的數量,這樣可以覆蓋到大多數的埠(猜測)。
概念性程式實踐失敗了,所以再用go開發的意義也不大了,後面還有一個坑就是go的pcap不能跨平臺編譯,只能在Windows下編譯windows版本,mac下編譯mac版本。
但是研究了Masscan和Zmap在tcp協議下的syn掃描模式,還是有很多收穫,以及明白了它們為什麼要這麼做,同時對網路協議和一些更低層的細節有了更深的認識。
這裡個人總結了一些tips:
設定發包速率時不僅要考慮自己頻寬,還要考慮目標伺服器的承受情況(掃描多埠時)
如需轉載,請註明出處。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69912109/viewspace-2659926/,如需轉載,請註明出處,否則將追究法律責任。