在資訊安全領域,掌握伺服器資訊收集技術至關重要。本文介紹如何運用 Python 模組 shodanDNSPython 進行伺服器資訊收集,涵蓋 Shodan 搜尋引擎的使用、DNS 資訊查詢、伺服器 Banner 擷取等導向。這些技術有助於安全人員進行滲透測試、漏洞評估和安全稽核。瞭解目標伺服器的作業系統、開放埠、服務版本等資訊,能更有效地找出潛在安全風險。

import shodan import requests import os

SHODAN_API_KEY = os.environ[‘SHODAN_API_KEY’] api = shodan.Shodan(SHODAN_API_KEY) domain = ‘www.python.org

dnsResolve = f"https://api.shodan.io/dns/resolve?hostnames={domain}&key={SHODAN_API_KEY}" try: resolved = requests.get(dnsResolve) hostIP = resolved.json()[domain] host = api.host(hostIP) # 處理host變數中的資訊 except Exception as e: print(f"An error occurred: {e}")

從伺服器收集資訊

本章節將介紹如何使用Python模組來提取伺服器公開的資訊。在進行滲透測試或稽核流程時,收集目標的相關資訊將非常有用。

技術需求

在開始閱讀本章節之前,您應該瞭解Python程式設計的基礎知識,並具備一些關於HTTP協定的基本知識。我們將使用Python 3.7版本。

使用Shodan提取伺服器資訊

Shodan是一個搜尋引擎,負責檢查和監控連線到網際網路的裝置,並從中提取有用的服務資訊。與傳統的搜尋引擎不同,Shodan索引的是伺服器的標頭、橫幅和作業系統版本等資訊。

存取Shodan服務

我們可以透過以下三種方式存取Shodan:

  • 透過Shodan提供的網頁介面
  • 透過RESTful API
  • 使用shodan模組以程式設計方式從Python存取

要以程式設計方式使用Shodan,需要在Shodan註冊開發者帳號並取得SHODAN_API_KEY。這樣,我們就可以透過API自動化搜尋。

Shodan RESTful API

Shodan提供RESTful API來對其服務發出請求。根據請求的不同,RESTful API提供不同的搜尋方法。

使用Shodan搜尋資訊

透過Shodan,我們可以搜尋特定伺服器的資訊,例如作業系統版本、伺服器型別和版本等。

使用Python DNS模組取得DNS伺服器資訊

我們可以使用DNSPython模組來取得DNS伺服器的相關資訊。

對Web應用程式進行模糊測試

模糊測試是一種測試方法,透過向Web應用程式輸入無效或非預期的資料來檢測其安全性。

使用socket模組取得伺服器資訊

我們可以使用socket模組來取得伺服器的相關資訊,例如主機名稱、IP位址等。

從伺服器取得易受攻擊的位址

透過對伺服器進行模糊測試,我們可以發現其中可能存在的漏洞。

程式碼範例:使用Shodan搜尋資訊

import shodan

# 初始化Shodan API
api = shodan.Shodan("YOUR_SHODAN_API_KEY")

# 搜尋特定關鍵字
results = api.search("apache")

# 輸出搜尋結果
for result in results["matches"]:
    print(result["ip_str"])
    print(result["data"])

內容解密:

此程式碼範例展示瞭如何使用Shodan API來搜尋特定關鍵字的相關資訊。首先,我們需要初始化Shodan API並輸入我們的API金鑰。然後,我們可以使用search()方法來搜尋特定的關鍵字。最後,我們可以輸出搜尋結果中的IP位址和相關資料。

Shodan搜尋流程

@startuml
skinparam backgroundColor #FEFEFE
skinparam sequenceArrowThickness 2

title Python 伺服器資訊收集技術

actor "客戶端" as client
participant "API Gateway" as gateway
participant "認證服務" as auth
participant "業務服務" as service
database "資料庫" as db
queue "訊息佇列" as mq

client -> gateway : HTTP 請求
gateway -> auth : 驗證 Token
auth --> gateway : 認證結果

alt 認證成功
    gateway -> service : 轉發請求
    service -> db : 查詢/更新資料
    db --> service : 回傳結果
    service -> mq : 發送事件
    service --> gateway : 回應資料
    gateway --> client : HTTP 200 OK
else 認證失敗
    gateway --> client : HTTP 401 Unauthorized
end

@enduml

此圖示展示了使用Shodan搜尋資訊的流程。首先,我們輸入特定的關鍵字。然後,使用Shodan API來搜尋相關的資訊。接著,輸出搜尋結果。最後,分析搜尋結果以取得有用的資訊。

使用Shodan進行伺服器資訊收集

Shodan是一個強大的搜尋引擎,可以用來收集與網路連線的裝置相關的資訊。在本章節中,我們將探討如何使用Shodan的RESTful API和Python模組來收集伺服器的資訊。

使用Shodan RESTful API收集資訊

Shodan提供了一個RESTful API,使得開發者可以輕鬆地查詢和取得與網路裝置相關的資訊。為了使用這個API,首先需要在Shodan網站上註冊並取得API金鑰。

透過API查詢特定IP位址的資訊

以下的Python指令碼展示瞭如何使用requests模組向Shodan的API傳送請求,取得特定IP位址的資訊,例如DNS伺服器和地理位置等。

#!/usr/bin/env python
import requests
import os

SHODAN_API_KEY = os.environ['SHODAN_API_KEY']
ip = '1.1.1.1'

def ShodanInfo(ip):
    try:
        result = requests.get(f"https://api.shodan.io/shodan/host/{ip}?key={SHODAN_API_KEY}&minify=True").json()
    except Exception as exception:
        result = {"error": "Information not available"}
    return result

print(ShodanInfo(ip))

內容解密:

  1. 首先,我們匯入了必要的模組,包括requests用於傳送HTTP請求,以及os用於存取環境變數。
  2. 我們定義了一個函式ShodanInfo(ip),該函式接受一個IP位址作為引數,並使用Shodan的API查詢該IP的相關資訊。
  3. 在函式內部,我們嘗試傳送GET請求到Shodan的API,並將回應轉換為JSON格式。如果發生任何異常,我們傳回一個錯誤訊息。
  4. 最後,我們呼叫ShodanInfo(ip)函式並列印結果,結果包含了IP位址的地理位置、組織名稱和其他相關資訊。

使用Shodan Python模組進行搜尋

除了使用RESTful API外,Shodan還提供了一個Python模組,使得搜尋和取得網路裝置資訊更加方便。

基本搜尋範例

以下指令碼展示瞭如何使用shodan模組搜尋公開連線的裝置。

#!/usr/bin/python
import shodan
import os

SHODAN_API_KEY = os.environ['SHODAN_API_KEY']
shodan = shodan.Shodan(SHODAN_API_KEY)

try:
    resultados = shodan.search('nginx')
    print("results :", resultados.items())
except Exception as exception:
    print(str(exception))

內容解密:

  1. 我們匯入了shodan模組並初始化了一個Shodan物件,傳入了我們的API金鑰。
  2. 使用shodan.search('nginx')方法搜尋執行nginx服務的裝置。
  3. 列印搜尋結果的專案。

結合命令列引數進行自動化搜尋

我們還可以撰寫指令碼,接受目標IP或網域名稱以及搜尋字串作為命令列引數,以實作自動化搜尋。

指令碼範例

#!/usr/bin/env python
import shodan
import argparse
import socket
import sys
import os

SHODAN_API_KEY = os.environ['SHODAN_API_KEY']
api = shodan.Shodan(SHODAN_API_KEY)

# 定義命令列引數
parser = argparse.ArgumentParser(description='Shodan search')
parser.add_argument("--target", dest="target", help="target IP / domain", required=None)
parser.add_argument("--search", dest="search", help="search", required=None)
parsed_args = parser.parse_args()

# 根據引數執行不同操作
if len(sys.argv) > 1 and sys.argv[1] == '--search':
    try:
        results = api.search(parsed_args.search)
        print('Results: %s' % results['total'])
        for result in results['matches']:
            print('IP: %s' % result['ip_str'])
            print(result['data'])
    except shodan.APIError as exception:
        print('Error: %s' % exception)

if len(sys.argv) > 1 and sys.argv[1] == '--target':
    try:
        hostname = socket.gethostbyname(parsed_args.target)
        results = api.host(hostname)
        print("""
IP: %s
Organization: %s
Operating System: %s
""" % (results['ip_str'], results.get('org', 'n/a'), results.get('os', 'n/a')))
        for item in results['data']:
            print("""Port: %s Banner: %s""" % (item['port'], item['data']))
    except shodan.APIError as exception:
        print('Error: %s' % exception)

內容解密:

  1. 我們使用了argparse模組來定義和解析命令列引數。
  2. 根據不同的引數(--search--target),執行不同的操作:搜尋特定字串或取得特定主機的資訊。
  3. --target模式下,我們使用socket.gethostbyname()將網域名稱解析為IP位址,然後使用Shodan的host()方法取得該主機的詳細資訊。

結合RESTful API和Shodan Python模組

我們還可以結合使用Shodan的RESTful API和Python模組,以取得更多的資訊。例如,使用API解析網域名稱以取得其對應的IP位址。

範例程式碼

import shodan
import requests
import os

SHODAN_API_KEY = os.environ['SHODAN_API_KEY']
api = shodan.Shodan(SHODAN_API_KEY)
domain = 'www.python.org'

dnsResolve = f"https://api.shodan.io/dns/resolve?hostnames={domain}&key={SHODAN_API_KEY}"
try:
    resolved = requests.get(dnsResolve)
    hostIP = resolved.json()[domain]
    host = api.host(hostIP)
    # 處理host變數中的資訊
except Exception as e:
    print(f"An error occurred: {e}")

內容解密:

  1. 首先,我們構建了一個用於解析網域名稱的API請求URL。
  2. 使用requests.get()方法傳送請求,並將回應轉換為JSON格式,以取得網域名稱的IP位址。
  3. 然後,使用Shodan的host()方法取得該IP位址的詳細資訊。

使用Shodan提取伺服器資訊

Shodan是一個強大的搜尋引擎,能夠查詢公開連線至網際網路的裝置資訊。透過Shodan的API,我們可以輕鬆地取得特定主機的Banner資訊、作業系統版本等。

取得特定主機的資訊

以下是一個簡單的Python指令碼,展示如何使用Shodan API取得特定主機的資訊:

import shodan

SHODAN_API_KEY = "YOUR_SHODAN_API_KEY"
shodanApi = shodan.Shodan(SHODAN_API_KEY)

try:
    host = shodanApi.host('TARGET_IP_ADDRESS')
    print("IP: %s" % host['ip_str'])
    print("Organization: %s" % host.get('org', 'n/a'))
    print("Operating System: %s" % host.get('os', 'n/a'))
    for item in host['data']:
        print("Port: %s" % item['port'])
        print("Banner: %s" % item['data'])
except shodan.APIError as e:
    print('Error: %s' % e)

內容解密:

  1. 首先,我們匯入shodan模組並設定API金鑰。
  2. 使用shodan.Shodan類別建立一個Shodan API的例項。
  3. host()方法用於取得特定主機的資訊。
  4. 我們列印出主機的IP、組織名稱和作業系統。
  5. 迴圈遍歷主機的data屬性,列印出開放的連線埠和對應的Banner資訊。
  6. 若發生API錯誤,則捕捉異常並列印錯誤訊息。

搜尋FTP伺服器

除了取得特定主機的資訊外,Shodan還可以用來搜尋特定的服務,例如FTP伺服器。以下是一個範例指令碼,用於搜尋允許匿名登入的FTP伺服器:

import shodan
import os

SHODAN_API_KEY = os.environ['SHODAN_API_KEY']
shodanApi = shodan.Shodan(SHODAN_API_KEY)

results = shodanApi.search("port: 21 Anonymous user logged in")
print("找到的主機數量: " + str(len(results['matches'])))

for result in results['matches']:
    if result['ip_str'] is not None:
        print(result['ip_str'])

內容解密:

  1. 使用Shodan API搜尋條件"port: 21 Anonymous user logged in"來找出開放FTP服務且允許匿名登入的主機。
  2. 列印出搜尋結果中的主機數量。
  3. 迴圈遍歷搜尋結果,列印出主機的IP位址。

使用Shodan篩選器和BinaryEdge搜尋引擎

Shodan篩選器

Shodan提供了多種篩選器,可以幫助我們更精確地搜尋目標。常用的篩選器包括:

  • after/before:根據日期篩選結果
  • country:根據國家篩選結果
  • city:根據城市篩選結果
  • geo:根據經緯度篩選結果
  • hostname:根據主機名稱篩選結果
  • net:根據IP範圍或網路段篩選結果
  • os:根據作業系統篩選結果
  • port:根據連線埠號碼篩選結果
  • org:根據組織名稱篩選結果

BinaryEdge搜尋引擎

BinaryEdge是一個類別似於Shodan的搜尋引擎,提供了豐富的裝置資訊和子網域查詢功能。以下是使用BinaryEdge Python模組pybinaryedge進行搜尋的範例:

from pybinaryedge import BinaryEdge

key = 'BINARY_EDGE_API_KEY'
binaryEdge = BinaryEdge(key)
search_domain = 'www.python.org'
results = binaryEdge.host_search(search_domain)

for ip in results['events']:
    print("%s" % (ip['target']['ip']))

內容解密:

  1. 首先,我們匯入pybinaryedge模組並建立一個BinaryEdge的例項。
  2. 使用host_search()方法對特定網域進行搜尋。
  3. 迴圈遍歷搜尋結果,列印出相關的主機IP位址。

使用socket模組取得伺服器資訊

在本文中,您將學習使用socket模組從伺服器取得banner的基本知識。socket模組提供了一種簡單的方式來傳送請求並取得與我們在滲透測試過程中可以使用的資訊相關的回應。欲瞭解更多關於socket模組的詳細資訊,請存取第3章,Socket程式設計。在此,我們將只著重於使用該模組從伺服器中提取資訊。

使用Python提取伺服器banner

Banner顯示了與Web伺服器名稱和伺服器版本相關的資訊。有些還會展示所使用的後端技術(PHP、Java或Python)及其版本。 生產版本可能存在公開或非公開的漏洞,因此測試我們公開的伺服器傳回的banner,看看它們是否暴露了我們不想公開的某些資訊,總是一個好的做法。這樣,我們可以檢查伺服器是否正在暴露某些我們真的不想暴露的資訊。

使用標準的Python函式庫,我們可以建立一個簡單的指令碼,連線到伺服器並捕捉包含在請求回應中的服務banner。取得伺服器banner的最佳方式是透過socket模組。我們可以向伺服器傳送請求,並使用recvfrom()方法取得回應,該方法將傳回一個包含回應的元組。

您可以在bannerGrabbing資料夾內的get_banner_server.py檔案中找到以下程式碼:

import socket
import argparse
import re

parser = argparse.ArgumentParser(description='取得伺服器banner')
# 主要引數
parser.add_argument("--target", dest="target", help="目標IP", required=True)
parser.add_argument("--port", dest="port", help="埠號", type=int, required=True)
parsed_args = parser.parse_args()

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((parsed_args.target, parsed_args.port))
sock.settimeout(2)

query = "GET / HTTP/1.1\nHost: "+parsed_args.target+"\n\n"
http_get = bytes(query,'utf-8')
data = ''

with open('vulnbanners.txt', 'r') as file:
    vulnbanners = file.read()

try:
    sock.sendall(http_get)
    data = sock.recvfrom(1024)
    data = data[0]
    print(data)
    
    #### 內容解密:
    # 這段程式碼首先建立了一個socket物件,並連線到指定的目標IP和埠號。
    # 然後,它發送了一個HTTP GET請求到伺服器,並接收了伺服器的回應。
    # 回應儲存在data變數中,並被列印出來。

    headers = data.splitlines()
    for header in headers:
        try:
            if re.search('Server:', str(header)):
                print("*****"+header.decode("utf-8")+"*****")
            else:
                print(header.decode("utf-8"))
        except Exception as exception:
            pass
    
    #### 內容解密:
    # 這段程式碼將回應的headers分割成單獨的行,並遍歷每一行。
    # 如果某一行包含'Server:',則它會被特別標記並列印出來。
    # 其他行則直接被列印出來。

    for vulnbanner in vulnbanners.splitlines():
        if vulnbanner.strip() in str(data.strip().decode("utf-8")):
            print('發現易受攻擊的伺服器! ', vulnbanner)
            print('目標: '+str(parsed_args.target))
            print('埠號: '+str(parsed_args.port))
    
    #### 內容解密:
    # 這段程式碼檢查伺服器的回應中是否包含已知的易受攻擊的banner。
    # 如果發現,則會列印出警告訊息,包括目標IP、埠號和易受攻擊的banner。

except socket.error:
    print ("Socket錯誤", socket.errno)
finally:
    sock.close()

#### 內容解密:
# 最後,無論是否發生錯誤,socket都會被關閉,以釋放資源。

使用DNSPython取得DNS伺服器資訊

在本文中,我們將建立一個DNS客戶端在Python中,並檢視此客戶端如何取得有關名稱伺服器、郵件伺服器和IPV4/IPV6地址的資訊。

內容解密:

  • 這部分內容介紹瞭如何使用DNSPython函式庫來查詢DNS記錄,包括名稱伺服器、郵件伺服器和IPV4/IPV6地址。
  • DNSPython是一個用於處理DNS的Python函式庫,可以用來查詢DNS記錄、更新DNS記錄等。