Một trường hợp thực tế về lỗ hổng Race Condition để RCE

Một ngày không được đẹp trời tôi nhận được thông tin hỗ trợ xử lý sự cố tấn công mạng từ 1 Đơn vị. Quá trình thu thập thông tin về sự cố cho thấy các máy chủ ứng dụng web đã bị tấn công xâm nhập, trong đó một ứng dụng web được viết bằng ngôn ngữ PHP. Cũng đã khá lâu không động đến PHP, nên tôi cũng thử challenge xem có bug nào thú vị không. Kết quả cho thấy có một số cách có thể dẫn tới RCE, trong đó bug liên quan đến Race condition có lẽ cũng có chút hay ho để chia sẻ.

Bỏ qua quy trình, cách thức tìm bug thì tôi note lại đặc điểm của chuỗi các vấn đề dẫn tới RCE như sau:

  • Ứng dụng tồn tại đoạn code cho phép File inclusion, example code như sau ($obj có thể control):

Chú ý: Có vẻ việc sử dụng nullbyte trong trường hợp này không còn khả thi sau phiên bản PHP 5.3.4 (cve-2006-7243).

  • Ứng dụng có một chức năng xử lý upload file, đoạn code xử lý khá dài, tóm gọn example code như sau:

Nội dung phần code này sẽ xử lý:

  1. Lấy thông tin pathinfo ($tempPath là thư mục định nghĩa sẵn nằm ngoài thư mục webroot, ex: D:\\UploadedFiles\Temp\
  2. Gán $_FILES[‘fileToUpload’][‘name’] bằng mã hash md5($_FILES[‘fileToUpload’][‘name’])
  3. Tạo $filepath và thực hiện upload (ex: Nếu upload file với filename là test.php thì sẽ được lưu tại đường dẫn D:\\UploadedFiles\Temp\93bc3c03503d8768cf7cc1e39ce16fcb.php
  4. Nếu upload vào tempPath thành công, sẽ thực hiện renametới newFilePath. newFilePath này không control được extension (ex: file_id là 1 sẽ được lưu D:\\UploadedFiles\1). Sau khi thực thi rename() function, file lưu tại $filepath sẽ bị xóa.

Với code xử lý upload như trên thì việc upload và thực thi webshell là không thể, vì thư mục lưu trữ file nằm ngoài thư mục webroot – không thể execute cho dù có upload được php file. Và việc upload được file với extension .php vào thư mục temp sẽ bị xóa ngay sau khi rename() được thực thi.

Tuy nhiên vấn đề mấu chốt ở phần code này là việc cho phép chúng ta tạo 1 file .php trên server – cho dù ngay sau đó nó sẽ bị xóa. Kết hợp với phần code cho phép File Inclusion ở trên, ta có 2 ý tưởng:

– Tìm cách để file được upload thành công vào thư mục temp nhưng sau đó (bằng cách nào đó) code xử lý sẽ bị exception trước khi run qua rename(). Dẫn tới file sẽ không bị xóa. Cuối cùng sử dụng path traversal để include file vừa được upload vào temp.

– Kết hợp path traversal, tìm cách include file được upload thành công trước khi thực thi rename().

Ý tưởng thứ 2 khả thi mà không cần phải tạo ra exception, chỉ cần chúng ta include file được upload vào thư mục temp trước khi file được xóa. Ta có thể sử dụng tính năng Intruder tạo nhiều threads liên tục thực hiện gửi http request nhằm include file, sau đó thực hiện upload bình thường với filename với extension là .php – ví dụ test.php

Chú ý nâng số threads trong option Intruder lên khoảng 25-30.

Như vậy với case này chúng ta đã kết hợp giữa path traversal, file inclusion, file upload và race condition để thực hiện RCE thành công.

@RedteamDiXuLySuCo