通過前面幾篇關于有效ip發現的文章介紹後,接下來就是對于這些活着的主機進行端口掃描的介紹了。
端口對應了網絡服務及應用端程序,服務的程序的漏洞通過端口攻入;通過開放的端口,可以進行更具體、更高效的攻擊。
UDP端口掃描一般都會假設ICMP Port Unreachable響應代表端口關閉,不過當目标系統設置了不響應ICMP Port Unreachable時,就會存在誤判的情況。
當然還可以通過完整的UDP應用層請求來進行端口掃描,雖然能提升準确性,但是會消耗大量時間。
UDP端口掃描:scapy最好去了解每一種基于UDP的應用層包結構,對于使用udp來進行端口掃描的工作會很有幫助。
直接上代碼吧:
#!/usr/bin/python3
import logging
logging.getLogger('scapy.runtime').setLevel(logging.ERROR)
import time
import sys
from scapy.all import *
if len(sys.argv) != 4:
print('Usage ./udp_port_scan.py [Target-IP] [First Port] [Last Port]')
print('Example ./udp_port_scan.py 172.18.14.1 1 100')
print('Example will UDP port scan ports 1 through 100 on 172.18.14.1')
sys.exit()
ip = str(sys.argv[1])
start = int(sys.argv[2])
end = int(sys.argv[3])
for port in range(start, end):
a = sr1(IP(dst=ip)/UDP(dport=port), timeout=5, verbose=0)
time.sleep(1)
if a == None:
print(port)
else:
pass
執行結果就是這樣:
執行結果
可以看到結果顯示沒有一個端口是開放的,這個結果可能有問題,将端口範圍加大一些再試試:
./udp_port_scan.py 192.168.31.168 1 150
掃出一個開放的端口,可以參考一下,但不要完全相信。
UDP端口掃描:nmap使用nmap進行udp的端口掃描,需要傳的參數是-sU,不指定端口的話以前默認是掃描1000個常用的端口,如果通過-p指定端口的話,就隻會對指定端口進行掃描:
nmap -sU 192.168.31.168
當然通過-p也是可以傳遞端口範圍的,比如這樣:
nmap -sU 192.168.31.168 -p1-100
也能通過-iL傳遞指定文檔裡的ip進行端口掃描:
nmap -iL ip.txt -sU -p1-100
tcp端口掃描使用tcp端口掃描,主要是基于連接協議,基于三次握手的。可以實現隐蔽掃描、僵屍掃描、全連接掃描,所有的tcp掃描方式,都是基于三次握手的變化來判斷目标端口狀态。
隐蔽掃描是隻發syn包,不建立完整連接,應用日志不記錄掃描行為,所以相對比較隐蔽,在網絡層還是會留下記錄。
僵屍掃描比前一個隐蔽掃描更加隐蔽,實施條件比較苛刻(現在僞造來源地址比較困難),可僞造來源地址,選擇僵屍機(閑置系統、系統使用遞增的IPID,IPID不可以是0或者随機産生的)
僵屍掃描目标端口打開
1.掃描者向僵屍機發送一個SYN/ACK,僵屍機回複一個RST,并取得僵屍機的IPID,假設為x;
2.掃描者僞造來源為僵屍機,向目标主機發送一個SYN,然後目标主機給僵屍機返回一個SYN/ACK的RST,僵屍機收到後給目标主機返回一個RST,并且IPID加1;
3.然後掃描者再次向僵屍機發送一個SYN/ACK,如果收到僵屍機返回的RST中IPID比第1步中收到IPID大2,就是目标機器端口處于打開狀态,如果大1則處于關閉狀态。
僵屍掃描目标端口關閉
隐蔽的端口掃描:scapy隐蔽端口掃描的定義已經在前面說過了,這裡直接用scapy來演示具體操作:
a = sr1(IP(dst='36.152.44.96')/TCP(flags='S',dport=80), timeout=1, verbose=0)
從結果來看,目标機器的80端口是開放的。
然後通過抓包工具看一下:
wireshark抓包
可以看到我的機器又回來一個rst包給目标主機,這個不是scapy發的,是當前機器的系統内核自動發送的,後面會講到如何處理這種rst包,避免對後續安全工作的幹擾。
如果遇到端口沒有開放會有兩種可能,第一種就是啥都不回複,另一種就是回複一個flags為RA的數據包。
用前面的内容寫一個python腳本:
#!/usr/bin/python3
import logging
logging.getLogger('scapy.runtime').setLevel(logging.ERROR)
import sys
from scapy.all import *
if len(sys.argv) != 4:
print('Usage ./syn_port_scan.py [Target-IP] [First Port] [Last Port]')
print('Example ./syn_port_scan.py 172.18.14.1 1 100')
print('Example will TCP syn port scan ports 1 through 100 on 172.18.14.1')
sys.exit()
ip = str(sys.argv[1])
start = int(sys.argv[2])
end = int(sys.argv[3])
for port in range(start, end):
a = sr1(IP(dst=ip)/TCP(dport=port, flags='S'), timeout=1, verbose=0)
if a == None:
pass
else:
if int(a[TCP].flags) == 18:
print(port)
else:
pass
腳本中最後用18作為判斷依據的原因可以看抓包中的數據:
SYN,ACK的抓包數據
可以看出來SYN,ACK轉換成10進制後就是18。
執行方式還是一樣,先賦予權限,然後傳入正确的參數:
./syn_port_scan.py 36.152.44.96 50 200
隐蔽的端口掃描:nmapscapy畢竟還要寫好幾行代碼,實際工作中都是怎麼簡單高效怎麼來。所以我們可以選擇nmap來做隐蔽的端口掃描。
nmap使用syn做端口掃描隻需要使用參數-sS:
nmap -sS 36.152.44.96 -p 1-100
有時候nmap的掃描結果裡會有一些fail、close、filtered,如果不想要這些結果,隻想知道open的端口的話,可以加個參數--open。
nmap也可以通過傳遞指定端口集合來掃描指定的端口:
nmap 36.152.44.238 -sS -p 50,80,88,90
隐蔽的端口掃描:hping3hping3可以通過參數-S來使用syn進行掃描:
hping3 36.152.44.238 --scan 1-100 -S
hping3有一個僞裝來源地址的參數--spoof:
hping3 -c 100 -S --spoof 192.168.10.13 -p 1 36.152.44.238
其中-c表示發多少數量的包,-p 1表示端口号每次加一,但是由于僞裝了源地址,目标機器就算端口開放,發出來的syn\ack數據包,也不會是我的主機,肯定是僵屍機。
全連接的端口掃描:scapy全連接掃描隻有在特殊情況下使用,很容易被防火牆發現。
scapy做全連接的端口掃描其實是有點麻煩的。因為syn掃描不需要raw packets,系統内核認為目标機器返回的syn/ack是非法包,直接發送rst終斷連接。
在不解決系統内核自動發送RST時,用下面的腳本嘗試一下全連接的端口掃描:
#!/usr/bin/python3
import logging
logging.getLogger('scapy.runtime').setLevel(logging.ERROR)
import sys
from scapy.all import *
SYN = IP(dst='36.152.44.238')/TCP(dport=80, flags='S')
print('--- SENT ---')
SYN.display()
print('\n\n ---RECEIVED---')
response = sr1(SYN, timeout=1, verbose=0)
response.display()
if int(response[TCP].flags) == 18:
print('\n\n --- SENT')
A = IP(dst='36.152.44.238')/TCP(dport=80, flags='A', ack=(response[TCP].seq 1))
A.display()
print('\n\n ---RECEIVED---')
response2 = sr1(A, timeout=1, verbose=0)
response2.display()
else:
print('SYN-ACK not returned')
抓包的結果:
未關閉系統内核發送RST時的執行結果
從抓包結果裡看出這台目标服務器雖然沒有回複RST,但是也沒有真正建立連接。不過有些服務器會将收到RST包後過來的ACK包拒絕掉,直接返回一個RST過來。
可以通過iptables的命令将去往指定目标ip的數據包過濾掉:
iptables -A OUTPUT -p tcp --tcp-flags RST RST -d 36.152.44.238 -j DROP
執行上面這個命令後,在執行腳本,就是這樣的結果:
内核沒有在發送RST數據包
雖然系統内核的确是沒有發送RST數據包了,但是從執行結果看也是有問題的。可能是目标機器的防火牆功能比較強大,也可能是腳本的邏輯存在問題,如果有同學對這個感興趣,可以私信我一起研究一下,這裡就先這樣吧。
全連接的端口掃描:nmap通過傳遞參數-sT來使用nmap的全連接端口掃描:
nmap 36.152.44.238 -sT -p 70-90
在抓包工具中可以看到:
80端口建立起了連接
全連接的端口掃描:ncnc也是可以做掃描工具的,隻需要使用參數-z:
nc -nv -w 1 -z 36.152.44.238 70-90
僵屍掃描僵屍掃描的定義已經在前面說過了,這裡直接來介紹具體實現,分别用scapy和nmap。
需要先假設有了一台可以使用的僵屍機。
僵屍掃描:scapy直接上腳本吧,應該都能看懂,如果有疑問,可以私信咨詢我。腳本裡主要是提供了兩個方法,一個是校驗不清楚僵屍機是否符合使用條件時調用,也就是最開始輸入1的時候,另一個就是直接指定僵屍機和目标機器,直接進行掃描。
#!/usr/bin/python3
import logging
logging.getLogger('scapy.runtime').setLevel(logging.ERROR)
from scapy.all import *
def ipid(zombie):
reply1 = sr1(IP(dst=zombie)/TCP(flags='SA'), timeout=2, verbose=0)
send(IP(dst=zombie)/TCP(flags='SA'), verbose=0)
reply2 = sr1(IP(dst=zombie)/TCP(flags='SA'), timeout=2, verbose=0)
if reply2[IP].id == (reply1[IP].id 2):
print('IPID sequence is incremental and target appears to be idle. ZOMBIE LOCATED')
response = input('Do you want to use this zombie to perform a scan?(Y or N): ')
if response == 'Y':
target = input('Enter the IP address of the target system: ')
zombie_scan(target, zombie)
else:
print('Either the IPID sequence is not incremental or the target is not idle. NOT A GOOD ZOMBIE')
def zombie_scan(target, zombie):
print('\n Scanning target ' target ' with zombie ' zombie)
print('\n ------ Open Ports on Target ------ \n ')
for port in range(1, 10000):
try:
start_val = sr1(IP(dst=zombie)/TCP(flags='SA', dport=port), timeout=2, verbose=0)
send(IP(src=zombie, dst=target)/TCP(flags='S', dport=port), verbose=0)
end_val = sr1(IP(dst=zombie)/TCP(flags='SA'), timeout=2, verbose=0)
if end_val[IP].id == (start_val[IP].id 2):
print(port)
except:
pass
print('------Zombie Scan Suite------\n')
print('1 - Identify Zombie Host \n')
print('2 - Perform Zombie Scan \n')
ans = input('Select an Option(1 or 2): ')
if ans == '1':
zombie = input('Enter IP address to test IPID sequence: ')
ipid(zombie)
else:
if ans == '2':
zombie = input('Enter IP address for zombie system: ')
target = input('Enter IP address for scan target: ')
zombie_scan(target, zombie)
我在網上找了一些機器,一時半會沒找到合适的僵屍機,這裡就不演示效果了。
僵屍掃描:nmapnmap提供了專門用來檢測指定機器是否是否作為僵屍機:
nmap -p端口 僵屍主機IP地址 --script=ipidseq.nse
如果能正常使用的話,在執行結果裡會返回ipdi是否是遞增的。
然後在有了合适的僵屍機以後,可以通過-sI參數來指定使用的僵屍機:
nmap 目标主機IP -sI 僵屍主機IP -Pn -p 端口号