用python實現域名資產監控的詳細步驟
應用場景
域名資產監控,通過輸入一個主域名,找到該域名對應的ip地址所在的服務器的端口開閉情況。通過定期做這樣的監控,有助於讓自己知道自己的資產的整體暴露面情況。
所需要具備的前綴技能
python的簡單使用
linux操作系統的簡單使用
DNS的原理
工具
pycharm 專業版
xshell 用於部署腳本
步驟
通過域名得到對應的ip地址
首先,我們知道對於一個域名來說,可以設置很多類型的記錄值,比如A記錄、AAAA記錄、SOA記錄、TXT記錄等等。安全領域常見的記錄值和其含義對應關系如下:
代碼 | 描述 |
---|---|
A | IPv4地址記錄 |
AAAA | IPv6地址記錄 |
CNAME | 規范名稱記錄,一個主機名字的別名: 域名系統將會繼續嘗試查找新的名字 |
MX | 電郵交互記錄 |
NS | 名稱服務器記錄 |
PTR | 最常用來運行反向DNS查找 |
SOA | 權威記錄的起始 |
TXT | 文本記錄 |
而我們要用到的就是A記錄(目前IPv6用得不廣泛)。
通過A記錄,獲取到一個域名對應的IP地址,用python實現的方法如下:
def dns_a(domain: str): dns_servers = '114.114.114.114,114.114.115.115,223.5.5.5,223.6.6.6,180.76.76.76,119.29.29.29,119.29.29.29,1.2.4.8,210.2.4.8,117.50.11.11,52.80.66.66,101.226.4.6,218.30.118.6,123.125.81.6,140.207.198.6,8.8.8.8,8.8.4.4,9.9.9.9,208.67.222.222,208.67.220.220'.split( ',') loop = asyncio.new_event_loop() resolver = aiodns.DNSResolver(loop=loop) resolver.nameservers = dns_servers try: record_a = loop.run_until_complete(resolver.query(domain, 'A')) return record_a except: pass return []
在代碼中,為每一次查詢隨機指定瞭一個dns_server,也就是dns查詢服務器,由於收斂的關系,不同的查詢服務器結果可能不相同。所以可以考慮做得完善一些,這裡隻查詢瞭一次,也可以換多個dns服務器查詢多次,取並集(並集是不放過所有可能情況,交集是精確但可能漏)。最終該方法就可以實現獲取域名對應的ip地址。
這個方法中使用到瞭asyncio和aiodns兩個包,安裝方法如下:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ –trusted-host pypi.tuna.tsinghua.edu.cn asyncio,aiodns
下面我們以www.mengwa.store為例,看看結果如何:
可以發現ip地址有瞭,不過,還需要從結果中進行提取。方法如下:
record_a = dns_a(domain) ips = [] if type(record_a) == list: ips = sorted([answer.host for answer in record_a])
這個ips中存儲的就是排序後的解析記錄ip列表。
對ip地址進行端口掃描
通過上面的步驟找到瞭ip地址,下一步就是對ip地址進行端口掃描。可在掃描之前,我們還有一個步驟需要做,需要判斷當前ip所在的機器是否存活。
可能你立馬就想到瞭ping方法,可是在安全領域,有很多公司都要求服務器將ICMP協議給阻止掉,也就是說,ping方法可能返回超時,但是機器並不一定沒有開啟,隻是主動給你把請求攔截掉瞭。
這裡我們使用nmap的-sPn參數進行掃描,以www.mengwa.store對應的ip地址47.119.137.0為例:
然後我們通過代碼來實現這一邏輯,我們使用python-nmap包,安裝步驟如下:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ –trusted-host pypi.tuna.tsinghua.edu.cn python-nmap
代碼如下:
def check_ip_reachable(ip: str): nm = nmap.PortScanner() xx = nm.scan(hosts=ip, arguments='-sP') # -sPn也可以 if 'scan' in xx: i = xx.__getitem__('scan') if ip in i: j = i.__getitem__(ip) if 'status' in j: status = j['status'] if 'state' in status: state = status['state'] print(ip, state) return state print(ip, 'down') return 'down'
做這一步的前提是,你本機安裝瞭nmap。
通過這裡做判斷,如果ip所在機器是開啟狀態,那麼我們就可以對其進行端口掃描瞭。
代碼如下:
# 實現對端口進行掃描,並且返回結果。使用nmap實現 def port_scan(ip: str): second = check_ip_reachable(ip) if second is not None and second == 'up': nm = nmap.PortScanner() xx = nm.scan(ip) print(nm.command_line()) ans = [] if 'scan' in xx: i = xx.__getitem__('scan') if ip in i: j = i.__getitem__(ip) if 'tcp' in j: tcp = j['tcp'] for port in tcp: ans.append(port) ans = sorted(ans) return ans else: write_to_file('output/' + time_now + '/ips.txt', ip + ' 不可達\n') return []
nm.command_line()方法可以打印出當前執行的命令行。(本質上這個包就是一個命令行調用包,然後做解析)
以47.119.137.0為例,結果如下:
這裡的方法,使用的是nmap默認掃描的常見端口,如果有需要,也可以通過給Scan方法,加入Ports參數,自定義要掃描的端口,甚至於全端口。
串聯起來,實現通過域名到端口監控
def handle_ip(ip: str): if not task_ip_set.__contains__(ip): try: print('ip:' + ip, '開始端口掃描') port_result = port_scan(ip) val = '' print('ip:', ip, '發現端口', port_result) for i in port_result: val = val + '\n' + ip + "----" + i.__str__() write_to_file('output/' + time_now + '/ip_ports.txt', val) task_ip_set.add(ip) except Exception as e: print(e) def handle_domain(domain: str): if not task_domain_set.__contains__(domain): print('domain:' + domain) record_a = dns_a(domain) ips = [] if type(record_a) == list: ips = sorted([answer.host for answer in record_a]) val = '' for i in ips: val = val + '\n' + domain + "----" + i.__str__() write_to_file('output/' + time_now + '/domain_ips.txt', val) print(ips) for i in ips: handle_ip(i)
這裡使用瞭task_domain_set和task_ip_set用於對作用目標進行去重。
那麼,到這裡我們的任務完成瞭嗎?
沒有
子域名發現
如果我的主域名資產有很多二級域名,而我自己又對自己有哪些子域名不清楚,那麼這個時候就需要做子域名發現。然後對每一個子域名調用前面的方法,找到其對應的ip開放的端口。
子域名發現一般來說有三種方法:
第一種通過對主域名所在網站進行爬取,從內容中解析出子域名;
第二種通過外部的查詢網站獲取結果,比如crt、virustotal、fofa等;
第三種通過字典爆破獲取結果,通過不斷的輪詢dns服務器,查詢其是否有A記錄的值,如果有,則表明該子域名存在,如果沒有則暫時認為該子域名不存在。
第一種方法,需要實現一個爬蟲,拿到網站的內容後利用正則表達式提取裡面的子域名,提取的方法如下:
def get_subdomains(value: str, domain: str): x = f'(?P<subdomain>[a-zA-Z0-9.]+{domain})' pattern = re.compile(x) y = pattern.findall(value) ans = set() for i in y: ans.add(i) print(ans) return ans
第二種方法,利用接口調用,參見相關的API接口即可。
第三種方法,子域名爆破。核心代碼如下
answers = await self.resolvers[j].query(cur_domain, 'A') # 查找A記錄 # 如果A記錄有值且沒有報錯,則說明該子域名存在
當你完成上面的步驟,並且去重之後,就可以將這些子域名作為前面步驟的輸入。這樣,對於用戶需要監控的某個主域名而言,監控到的范圍就提升瞭很多。
請勿用於非已有域名的監控,造成的損失與本人無關。以上測試數據均為本人已有域名和ip。
到此這篇關於用python實現域名資產監控的文章就介紹到這瞭,更多相關python域名資產監控內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- PyHacker編寫指南引用Nmap模塊實現端口掃描器
- 利用Python腳本寫端口掃描器socket,python-nmap
- Python編寫nmap掃描工具
- python中pip安裝庫時出現Read timed out解決辦法
- Python基礎教程之pip的安裝和卸載