Python 實現Tracert追蹤TTL值

2022-10-04 18:01:04

Tracert 命令跟蹤路由原理是IP路由每經過一個路由節點TTL值會減一,假設TTL值=0時封包還沒有到達目標主機,那麼該路由則會回覆給目標主機一個封包不可達,由此我們就可以獲取到目標主機的IP地址,如下我們通過scapy構造一個路由追蹤工具並實現一次追蹤。

首先Scapy是如何發包與收包的,看以下案例的演示。

>>> from random import randint
>>>
>>> RandomID=randint(1,65534)
>>> packet = IP(dst="61.135.169.125", ttl=1, id=RandomID) / ICMP(id=RandomID, seq=RandomID) / "hello lyshark"
>>> respon = sr1(packet,timeout=3,verbose=0)
>>>
>>> respon
<IP  version=4 ihl=5 tos=0xc0 len=61 id=14866 flags= frag=0 ttl=64 proto=icmp chksum=0xbc9a src=192.168.1.1 dst=192.168.1.2 |<ICMP  type=time-exceeded code=ttl-zero-during-transit chksum=0xf4ff reserved=0 length=0 unused=None |<IPerror  version=4 ihl=5 tos=0x0 len=33 id=49588 flags= frag=0 ttl=1 proto=icmp chksum=0x4f79 src=192.168.1.2 dst=61.135.169.125 |<ICMPerror  type=echo-request code=0 chksum=0x30c4 id=0xc1b4 seq=0xc1b4 |<Raw  load='hello' |>>>>>

路由追蹤原理(參考於網際網路):一開始傳送一個TTL為1的包,這樣到達第一個路由器的時候就已經超時了,第一個路由器就發ICMP通知說包超時,這樣就能夠記錄下所經過的第一個路由器的IP。然後將TTL加1,安全通過第一個路由器,而第二個路由器的的處理與第一個同樣,丟包,發通知說包超時了,這樣記錄下第二個路 由器IP,由此能夠一直進行下去,直到這個封包到達目標主機,由此列印出全部經過的路由器。

將這個過程自動化,就可以完成封包的跟蹤,Python 程式碼如下所示

from scapy.all import *
from random import randint
import time,ipaddress,threading
from optparse import OptionParser

def ICMP_Ping(addr):
    RandomID=randint(1,65534)
    packet = IP(dst=addr, ttl=64, id=RandomID) / ICMP(id=RandomID, seq=RandomID) / "lyshark"
    respon = sr1(packet,timeout=3,verbose=0)
    if respon:
        print("[+] --> {}".format(str(respon[IP].src)))

# By: LyShark.com
def TraceRouteTTL(addr):
    for item in range(1,128):
        RandomID=randint(1,65534)
        packet = IP(dst=addr, ttl=item, id=RandomID) / ICMP(id=RandomID, seq=RandomID)
        respon = sr1(packet,timeout=3,verbose=0)
        if respon != None:
            ip_src = str(respon[IP].src)
            if ip_src != addr:
                print("[+] --> {}".format(str(respon[IP].src)))
            else:
                print("[+] --> {}".format(str(respon[IP].src)))
                return 1
        else:
            print("[-] --> TimeOut")
        time.sleep(1)

if __name__== "__main__":
    parser = OptionParser()
    parser.add_option("--mode",dest="mode",help="選擇使用的工具模式<ping/trace>")
    parser.add_option("-a","--addr",dest="addr",help="指定一個IP地址或範圍")
    (options,args) = parser.parse_args()
    print("By: LyShark.com")
    # 使用方式: lyshark.py --mode=ping -a 192.168.1.0/24
    if options.mode == "ping":
        net = ipaddress.ip_network(str(options.addr))
        for item in net:
            t = threading.Thread(target=ICMP_Ping,args=(str(item),))
            t.start()
    # 使用方式: lyshark.py --mode=trace -a 8.141.58.64
    elif options.mode == "trace":
        TraceRouteTTL(str(options.addr))
    else:
        parser.print_help()

追蹤探測效果如下: