Penetration Testing Step 3 – SSTI attack với phương châm còn thở còn gỡ

Tiếp theo nội dung Penetration Testing Step 3 – Làm gì khi các đòn cơ bản với Server-Side Template Injection không có tác dụng?, kỳ này tôi sẽ mần tiếp 2 kịch bản cuối trong series Server-Side Template Injection – SSTI. Cụ thể, tôi sẽ lần lượt giới thiệu các kịch bản dễ gây nản lòng cho attacker bao gồm:

  • Mục tiêu thiết lập template engine thực thi template trong sanbox;
  • Mục tiêu gia cố bài bản template engine và chỉ để lại đường tấn công custom exploit thông qua object.

Lưu ý:

#1. Server-Side Template Injection với sandboxed environment

Trong các kỳ trước, công việc của tôi tương đối nhẹ nhàng khi có thể tận dụng các documentation liên quan để hỗ trợ công cuộc tấn công mục tiêu. Tuy nhiên, khi mục tiêu bắt đầu lên level (ví dụ thiết lập template engine thực thi template trong sanbox – đại khái là môi trường cô lập để ngăn cấm hành động tấn công “vật chủ”), tôi sẽ bắt đầu phải đổ mồ hôi, sôi nước mắt để thăm dò và thử nghiệm các phương án tấn công.

Trong tình thế này, việc đầu tiên của tôi sẽ là thử thăm dò để xác định các objetc (đối tượng) và method (chức năng) mà tôi có thể tiếp cập. Dựa vào kết quả của quá trình này và những thông tin liên quan nhặt nhạnh được (ví dụ object sẽ có quyền truy cập method nào, kết quả trả về là gì,…), tôi sẽ sàng lọc và lên danh sách các ứng cử viên tiềm năng để bắt đầu các thử nghiệm chi tiết với các phương án giao lưu phối hợp mà tôi có thể nghĩ ra.

Không nói dông dài nữa, tôi triển phần demo đây. Đầu tiên, tôi cũng login với credential được cung cấp.

Sau đó tôi chọn đại một sản phẩm để xem chi tiết và chọn Edit template.

Edit template
Edit template

Lần này, tôi quan sát thấy cái product object trong chỗ edit template. Quăng thử một cái vớ vẩn kiểu product.test vào tôi thấy cái thông báo lỗi cho biết FreeMarker template đang được sử dụng.

 FreeMarker template
FreeMarker template

Tôi thử vận may với từ khóa “SSTI + Freemarker” thì tìm thấy một thứ có vẻ hay ho ở PayloadsAllTheThings/Server Side Template Injection at master · swisskyrepo/PayloadsAllTheThings · GitHub.

SSTI + Freemarker
SSTI + Freemarker

Như vậy, đại khái tôi sẽ có thể đọc file my_password.txt của Carlos với cái đống như sau.

${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve(‘/home/carlos/my_password.txt’).toURL().openStream().readAllBytes()?join(” “)}

Chỗ này tôi cần làm rõ là hiếm khi có chuyện đập phát ăn ngay như ở trên lắm. Trường hợp không ăn may được, tôi sẽ cần bới thông tin liên quan đến cái Class Object trong Java rồi mò mẫm dần dần để xác định các thông tin cần thiết từ đó ghép nối lại thành đòn tấn công cụ thể. Ví dụ, tôi có thể xác định được cái getClass() của các Object:

getClass()
getClass()

Rồi tuần tự xác định cái đám kế tiếp như getProtectionDomain(), getCodeSource(),…(Nói chung là vã cả mồ hôi chứ cũng không dễ dàng gì.)

getCodeSource()
getCodeSource()

Thôi quay lại vấn đề chính, quất thử cái đống lằng nhằng tìm được ở trên vào cái template, tôi nhận được mớ kết quả kiểu decimal (53 103 118 113 55 115 51 122 104 117 54 114 108 102 114 98 114 54 106 109).

Read file
Read file

Như thông tin tìm được ở trên (“Convert the returned bytes to ASCII“), tôi thử chuyển đổi cái kết quả trả về sang ASCII (tôi dùng Convert Decimal to ASCII – Online ASCII Tools trong phần minh họa bên dưới) và húp được nội dung của cái file my_passwd.txt (5gvq7s3zhu6rlfrbr6jm) của Carlos.

decimal to ASCII
decimal to ASCII

Nếu để ý kỹ, bạn sẽ thấy phần thông tin tìm được ở trên còn có phần liên quan đến Code executionSanbox bypass (với version thấp hơn 2.3.30). Ví dụ, phần Sanbox bypass, tôi sẽ có thể đọc file my_password.txt với:

<#assign classloader=product.class.protectionDomain.classLoader>

<#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")>

<#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)>

<#assign ec=classloader.loadClass("freemarker.template.utility.Execute")>

${dwf.newInstance(ec,null)("cat my_password.txt")}

Thực tế, nếu phương án này hoạt động, tôi sẽ không chỉ dừng ở việc đọc file mà còn tận dụng tối đã khả năng thực thi code để hốt trọn ổ mục tiêu (cũng cần lưu ý là thực tế hiếm khi có chuyện mục tiêu tạo file my_passowrd.txt đầy hớ hên như trên lắm).

#2. Server-side template injection với custom exploit

Trong kịch bản này, template engine được gia cố bài bản nên mọi mưu la liếm trước đó của tôi đều thất bại. Tuy nhiên, đôi khi trong tình thế khốn cùng đó, đâu đó vẫn có thể tồn tại ông developer “tốt bụng” để lại cho tôi vài object có thể tiếp cận qua thông qua template để tôi chấm mút sống qua ngày.

Với dạng này, khả năng cao là tôi không tìm được document nào ra hồn để nghiên cứu phương án tấn công. Nhưng ít ra tôi vẫn còn đám object để mò mẫm từng bước để tìm đường phá đảo.

Rồi, chuyển qua phần demo cụ thể. Ở đây, tôi sẽ cho traffic chạy qua Burp Suite. Sau khi thiết lập xong, tôi tiến hành login với credential được cung cấp và post thử một comment vào 1 bài blog.

Tương tự nội dung Penetration Testing Step 3 – Các đòn cơ bản với Server-Side Template Injection, tôi cũng quan sát thấy vị trí cho phép thiết lập preferred name để hiển thị tên lúc đăng comment. Thử thiết lập chuyển sang first namesubmit, tôi ghi nhận được cặp resquest/response kiểu như sau.

preferred name setting
preferred name setting
preferred name setting request
preferred name setting request

Kiểm tra lại tôi thấy phần tên hiển thị trên chỗ comment cũng đã được cập nhật tương ứng. Quay lại chỗ thay đổi preferred name, tôi soi tiếp cái chức năng thay đổi Avatar và thử upload một cái file linh tinh nào đấy (tôi dùng polyglot.php chỉ để minh họa, bạn dùng kiểu khác cũng được, mục tiêu chỉ là để làm phát sinh lỗi vì file upload không phù hợp với thuần phong mỹ tục).

Avatar upload
Avatar upload

Tất nhiên, tôi sẽ bị ăn chửi sml vì hành động sai trái này. Nhưng không sao, tôi đã tia được một thông tin thú vị liên quan đến method setAvatar() đã được sử dụng cũng như cái file path /home/carlos/User.php.

Avatar upload error
Avatar upload error

Quay trở lại chỗ thiết lập Avatar, tôi chọn lại một cái image đàng hoàng để upload. Rồi túm cái request tương ứng đẩy qua Burp Suite Repeater. Tại đây, tôi thử điều chỉnh cái blog-post-author-display thành user.setAvatar(‘/etc/passwd’) và gửi hàng thử.

setAvatar()
setAvatar()

Lúc này, nếu load lại chỗ comment đã thực hiện, tôi sẽ ghi nhận thông báo lỗi cho biết cung cấp thiếu 1 argument.

setAvatar() error
setAvatar() error

Tôi thử cập nhật cái requet với việc thêm vào argument ‘image/jpg’ tương ứng cho image MIME type.

setAvatar() request
setAvatar() request

Lần này sẽ không còn thông báo lỗi nữa nhưung hiển nhiên cái avatar hiển thị chỗ comment cũng sẽ không ra gì.

Load comment
Load comment

Nhưng mà tôi cũng không bận tâm lắm với chuyện này. Thứ tôi quan tâm ở đây là thực tế cái Get request đến avatar sẽ trả về nội dung gì. Để biết được, tôi sẽ chạy cái request GET /avatar?avatar=wiener để truy cập đến avatar của account đang đăng nhập hiện tại. Và như dự kiến, tôi đã húp được nội dung file /ect/passwd trong phần response.

Read file
Read file

Điều này xác nhận tôi đã có phương án truy cập để xem nội dung của file tùy ý trên hệ thống. Thử lặp lại bước trên, nhưng lần này tôi sẽ múc file /home/carlos/User.php ghi nhận trước đó.

Read file (cont)
Read file (cont)

Tiếp tục sử dụng request GET /avatar?avatar=wiener để xem nội dung file, tôi phát hiện function gdprDelete() cho phép tôi xóa user avatar file.

gdprDelete()
gdprDelete()

Tôi có thể tận dụng thông tin nói trên để thử giết thịt file /home/carlos/.ssh/id_rsa (tức là private key để ssh của Carlos) với các bước như sau. Thiết lập lại thông tin chỗ setAvatar với request:

setAvatar() request
setAvatar() request

Sau đó load lại chỗ comment để thực thi template. Và cuối cùng chạy request gọi đến user.gdprDelete() và thực thi template để xử file của của Carlos.

gdprDelete() request
gdprDelete() request

Lưu ý, việc xóa file ở trên chỉ nhằm minh họa ý tưởng tấn công. Thực tế, tôi sẽ có thể hốt nội dung file /home/carlos/.ssh/id_rsa để tạo private key rồi ssh vào hệ thống với vai trò của nạn nhân để tiếp tục công cuộc tấn công.

Đến đây tôi cũng xin kết thúc nội dung giới thiệu SSTI. Tôi sẽ sắp xếp để quay lại minh họa việc sử dụng combo SSTI và các chiêu thức khác để triệt hạ mục tiêu vào một ngày đẹp trời nào đấy.

1 thought on “Penetration Testing Step 3 – SSTI attack với phương châm còn thở còn gỡ”

Leave a Reply

Your email address will not be published. Required fields are marked *