使用Python實現(xiàn)Fuzz測試的四種方法實現(xiàn)與對比
下面我將用Python實現(xiàn)一個類似的、存在漏洞的程序,并展示如何使用Python進行Fuzz測試。需要注意的是,由于Python是內存安全的語言,我們無法完全復制C語言中的緩沖區(qū)溢出漏洞,但可以模擬類似的安全問題。
存在漏洞的Python程序
# vulnerable_parser.py
import sys
import json
def parse_data(input_data):
"""
一個存在安全問題的解析函數(shù)
1. 可能引發(fā)異常的處理邏輯
2. 可能存在代碼注入漏洞
3. 可能存在正則表達式拒絕服務(ReDoS)
"""
try:
# 模擬不安全的數(shù)據(jù)處理
if input_data.startswith("{"):
# 嘗試解析為JSON - 可能引發(fā)異常
data = json.loads(input_data)
return f"Parsed JSON: {data}"
elif "system" in input_data:
# 模擬命令注入漏洞
import os
# 危險操作:實際應用中絕不應該這樣做!
result = os.popen(f"echo {input_data}").read()
return f"Command result: {result}"
elif "calc" in input_data:
# 模擬不安全的eval使用
return f"Calculation: {eval(input_data)}"
else:
# 模擬正則表達式ReDoS漏洞
import re
# 危險的正則模式,可能造成ReDoS
pattern = r"^(a+)+$"
if re.match(pattern, input_data):
return "Pattern matched"
return f"Processed: {input_data}"
except Exception as e:
return f"Error: {str(e)}"
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python vulnerable_parser.py <input_file>")
sys.exit(1)
with open(sys.argv[1], 'r', encoding='utf-8', errors='ignore') as f:
input_data = f.read().strip()
result = parse_data(input_data)
print(result)
使用Python進行Fuzz測試
有多種方法可以對Python程序進行Fuzz測試。以下是幾種常見方法:
方法一:使用AFL++與Python包裝
雖然AFL++主要針對本地代碼,但可以通過Python擴展支持:
# 安裝python-afl pip install python-afl # 使用AFL++運行Python Fuzz測試 PYTHON_AFL_PERSISTENT=1 python -m afl.vulnerable_parser
方法二:使用專門針對Python的Fuzzer - Atheris
Atheris是由Google開發(fā)的針對Python的覆蓋率引導Fuzzer:
# fuzz_parser.py
import atheris
import sys
with atheris.instrument_imports():
import vulnerable_parser
def TestOneInput(data):
try:
# 將輸入數(shù)據(jù)轉換為字符串
input_str = data.decode("utf-8")
vulnerable_parser.parse_data(input_str)
except (UnicodeDecodeError, ValueError):
# 忽略編碼錯誤,這是正常的Fuzz行為
pass
except Exception as e:
# 這里可以記錄異常,但通常讓Fuzzer自動處理
pass
if __name__ == "__main__":
atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()
運行上面的Fuzzer:
pip install atheris python fuzz_parser.py
方法三:使用基于生成的Fuzzer - Hypothesis
Hypothesis是一個基于屬性的測試庫,也可以用于Fuzz測試:
# test_with_hypothesis.py
from hypothesis import given, strategies as st
import vulnerable_parser
@given(st.text())
def test_parse_data_with_random_input(text):
"""使用隨機生成的文本測試解析器"""
try:
result = vulnerable_parser.parse_data(text)
# 這里可以添加一些斷言
assert result is not None
except Exception:
# 對于Fuzz測試,異常是可以接受的
pass
if __name__ == "__main__":
test_parse_data_with_random_input()
運行測試:
pip install hypothesis python test_with_hypothesis.py
方法四:簡單的自定義Fuzzer
# simple_fuzzer.py
import random
import string
import subprocess
import os
def generate_random_input(length=100):
"""生成隨機輸入"""
# 生成基本隨機字符串
chars = string.ascii_letters + string.digits + string.punctuation + " "
result = ''.join(random.choice(chars) for _ in range(length))
# 有時添加一些特殊模式
if random.random() < 0.3:
result = "{" + result + "}" # 模擬JSON
if random.random() < 0.1:
result = "a" * length # 可能觸發(fā)ReDoS
if random.random() < 0.05:
result = "system(" + result + ")" # 可能觸發(fā)命令注入
return result
def run_fuzzer():
"""運行Fuzzer"""
crash_count = 0
hang_count = 0
total_tests = 10000
for i in range(total_tests):
# 生成測試輸入
test_input = generate_random_input(random.randint(1, 1000))
# 寫入臨時文件
with open("temp_input.txt", "w") as f:
f.write(test_input)
try:
# 運行目標程序,設置超時
result = subprocess.run(
["python", "vulnerable_parser.py", "temp_input.txt"],
capture_output=True,
text=True,
timeout=5 # 5秒超時
)
# 檢查結果
if result.returncode != 0:
crash_count += 1
print(f"Crash found with input: {test_input[:100]}...")
print(f"Error: {result.stderr}")
# 保存崩潰輸入以供分析
with open(f"crash_{crash_count}.txt", "w") as f:
f.write(test_input)
except subprocess.TimeoutExpired:
hang_count += 1
print(f"Timeout with input: {test_input[:100]}...")
# 保存導致超時的輸入
with open(f"hang_{hang_count}.txt", "w") as f:
f.write(test_input)
# 清理
if os.path.exists("temp_input.txt"):
os.remove("temp_input.txt")
print(f"Fuzzing completed. Total tests: {total_tests}")
print(f"Crashes: {crash_count}, Hangs: {hang_count}")
if __name__ == "__main__":
run_fuzzer()
分析與改進
通過上述Fuzz測試,我們可以發(fā)現(xiàn)Python程序中可能存在的多種問題:
- 異常處理 - 程序是否能夠優(yōu)雅地處理各種異常輸入
- 代碼/命令注入 - 程序是否存在eval或os.popen的不安全使用
- 正則表達式拒絕服務(ReDoS) - 是否存在效率低下的正則表達式
- 資源消耗 - 程序是否會因特定輸入消耗過多資源
發(fā)現(xiàn)漏洞后,我們應該修復程序:
# fixed_parser.py
import sys
import json
import re
def safe_parse_data(input_data):
"""
修復后的安全解析函數(shù)
"""
# 限制輸入大小
if len(input_data) > 1000:
return "Error: Input too long"
try:
if input_data.startswith("{"):
# 安全地解析JSON
data = json.loads(input_data)
return f"Parsed JSON: {data}"
else:
# 使用更安全的正則表達式
pattern = r"^a+$" # 簡化模式,避免ReDoS
if re.match(pattern, input_data):
return "Pattern matched"
return f"Processed: {input_data}"
except json.JSONDecodeError:
return "Error: Invalid JSON"
except Exception as e:
return f"Error: {str(e)}"
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python fixed_parser.py <input_file>")
sys.exit(1)
try:
with open(sys.argv[1], 'r', encoding='utf-8', errors='ignore') as f:
input_data = f.read().strip()
# 移除危險功能(命令執(zhí)行、eval等)
if any(cmd in input_data for cmd in ["system", "eval", "exec", "os.", "subprocess"]):
print("Error: Suspicious input detected")
sys.exit(1)
result = safe_parse_data(input_data)
print(result)
except Exception as e:
print(f"Error: {str(e)}")
總結
Python中的Fuzz測試與C/C++有所不同,主要關注:
- 異常處理 - 確保程序不會因異常輸入而崩潰
- 代碼注入 - 避免使用eval、exec等危險函數(shù)
- 正則表達式ReDoS - 使用效率更高的正則模式
- 資源限制 - 防止消耗過多內存或CPU時間
- 安全實踐 - 遵循安全編碼準則
通過結合使用專門的Python Fuzzer(如Atheris)和自定義Fuzz測試,可以有效發(fā)現(xiàn)Python應用程序中的各種安全問題。
到此這篇關于使用Python實現(xiàn)Fuzz測試的四種方法實現(xiàn)與對比的文章就介紹到這了,更多相關Python實現(xiàn)Fuzz測試內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python Django框架url反向解析實現(xiàn)動態(tài)生成對應的url鏈接示例
這篇文章主要介紹了Python Django框架url反向解析實現(xiàn)動態(tài)生成對應的url鏈接,結合實例形式分析了Django框架URL反向解析具體原理與應用操作技巧,需要的朋友可以參考下2019-10-10
Python scrapy爬取蘇州二手房交易數(shù)據(jù)
scrapy的第二個實例對比上一個,在數(shù)據(jù)處理上增加了新的需求,運用了管道文件pipelines.py,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下2021-06-06
Python中字節(jié)數(shù)組和16進制字符串轉換方式
這篇文章主要介紹了Python中字節(jié)數(shù)組和16進制字符串轉換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06

