Server-side template injection(SSTI)
Last updated
Last updated
Template engines (công cụ giúp chúng ta tách mã HTML thành các phần nhỏ hơn mà chúng ta có thể sử dụng lại trên nhiều tập tin HTML) được sử dụng rộng rãi bởi các ứng dụng web nhằm trình bày dữ liệu thông qua các trang web và emails. Việc nhúng các đầu vào từ phía người dùng theo cách không an toàn vào trong templates dẫn đến Server-Side Template Injection - một lỗ hổng nghiêm trọng thường xuyên dễ dàng bị nhầm lẫn với Cross-Site Scripting (XSS).
SSTI
là khi kẻ tấn công có thể sử dụng template syntax gốc để đưa payload độc hại vào template, sau đó payload này được thực thi phía server.
Template engines được thiết kế để tạo các trang web bằng cách kết hợp các template cố định với dữ liệu dễ thay đổi. Các cuộc tấn công SSTI
có thể xảy ra khi đầu vào của người dùng được nối trực tiếp vào một template, thay vì được chuyển vào dưới dạng dữ liệu. Điều này cho phép kẻ tấn công đưa vào các template tùy ý để thao túng template engine, thường cho phép chúng kiểm soát hoàn toàn server. Như tên gợi ý, payload SSTI được thực hiện và đánh giá phía server, có khả năng khiến chúng trở nên nguy hiểm hơn nhiều so với client-side template injection.
Hậu quả nó mang lại vô cùng lớn có thể khiến các trang web phải đối mặt với nhiều cuộc tấn công khác nhau tùy thuộc vào emplate engine được đề cập và ứng dụng sử dụng nó chính xác như thế nào. Trong một số trường hợp hiếm gặp, những lỗ hổng này không gây rủi ro bảo mật thực sự. Tuy nhiên, hầu hết thời gian, tác động của việc SSTI có thể rất thảm khốc.
Ở mức nghiêm trọng nhất của quy mô, kẻ tấn công có khả năng thực thi mã từ xa(RCE), chiếm toàn quyền kiểm soát server và sử dụng nó để thực hiện các cuộc tấn công khác vào cơ sở hạ tầng nội bộ.
Ngay cả trong trường hợp không thể thực thi mã từ xa đầy đủ, kẻ tấn công vẫn có thể thường xuyên sử dụng tính năng chèn template phía server làm cơ sở cho nhiều cuộc tấn công khác, có khả năng giành được quyền truy cập đọc vào dữ liệu nhạy cảm và các tệp tùy ý trên server.
Các lỗ hổng SSTI phát sinh khi đầu vào của người dùng được nối vào các template thay vì được chuyển vào dưới dạng dữ liệu.
Các template tĩnh chỉ cung cấp trình giữ chỗ để hiển thị nội dung động thường không dễ bị SSTI. Ví dụ điển hình là một email chào đón từng người dùng bằng tên của họ, chẳng hạn như đoạn trích sau đây từ template Twig:
Điều này không dễ bị SSTI vì tên của người dùng chỉ được chuyển vào template dưới dạng dữ liệu.
Tuy nhiên, vì các template chỉ đơn giản là các chuỗi, các nhà phát triển web đôi khi trực tiếp nối đầu vào của người dùng vào các template trước khi kết xuất. Hãy lấy một ví dụ tương tự như ví dụ trên, nhưng lần này, người dùng có thể tùy chỉnh các phần của email trước khi gửi. Ví dụ: họ có thể chọn tên được sử dụng:
Trong ví dụ này, thay vì một giá trị tĩnh được chuyển vào template, một phần của template tự động được tạo bằng cách sử dụng $_GET
tham số name
. Vì cú pháp template được xử lý phía server, điều này có khả năng cho phép kẻ tấn công đặt payload SSTI bên trong name
tham số như sau:
Các lỗ hổng bảo mật như thế này đôi khi do vô tình gây ra do thiết kế template kém bởi những dev không có kiến thức bảo mật và update kiến thức. Giống như trong ví dụ trên, bạn có thể thấy các thành phần khác nhau, một số thành phần chứa đầu vào của người dùng, được nối và nhúng vào một template. Theo một số cách, điều này tương tự như các lỗ hổng SQL injection xảy ra trong những dòng code chủ quan, thiếu hiểu biết của những dev web.
Việc xác định các lỗ hổng SSTI và tạo ra một cuộc tấn công thành công thường bao gồm quy trình sau đây.
Các lỗ hổng SSTI thường không được chú ý không phải vì chúng phức tạp mà vì chúng chỉ thực sự rõ ràng đối với những pentest đang tìm kiếm chúng một cách rõ ràng. Nếu bạn có thể phát hiện ra rằng có một lỗ hổng bảo mật, thì việc khai thác nó có thể dễ dàng một cách đáng ngạc nhiên.
Như với bất kỳ lỗ hổng nào, bước đầu tiên để khai thác là có thể tìm thấy nó. Có lẽ cách tiếp cận ban đầu đơn giản nhất là fuzz template bằng cách đưa vào một chuỗi các ký tự đặc biệt thường được sử dụng trong các template expressions, chẳng hạn như ${{<%[%'"}}%\
. Nếu một exception được đưa ra, điều này cho thấy rằng template syntax được đưa vào có khả năng được server xử lý theo một cách nào đó. Đây là một dấu hiệu cho thấy có thể tồn tại lỗ hổng đối với SSTI.
Các lỗ hổng SSTI xảy ra trong hai bối cảnh(context) riêng biệt, mỗi bối cảnh đều yêu cầu phương pháp phát hiện riêng. Bất kể kết quả của các nỗ lực làm mờ của bạn là gì, điều quan trọng là bạn cũng nên thử các cách tiếp cận theo ngữ cảnh cụ thể sau đây.
Hầu hết các template languages cho phép bạn tự do nhập nội dung bằng cách sử dụng trực tiếp các thẻ HTML hoặc bằng cách sử dụng cú pháp gốc của template, cú pháp này sẽ được hiển thị thành HTML ở mặt sau trước khi phản hồi HTTP được gửi.
Ví dụ: trong Freemarker, dòng render('Hello ' + username)
này sẽ hiển thị thành một cái gì đó như Hello Carlos
.
Điều này đôi khi có thể bị khai thác cho XSS và trên thực tế thường bị nhầm với một lỗ hổng XSS đơn giản. Tuy nhiên, bằng cách đặt các phép toán làm giá trị của tham số, chúng tôi có thể kiểm tra xem đây có phải là nơi có thể khai thác để thực hiện một cuộc tấn công SSTI hay không?
Ví dụ: hãy xem xét một template có chứa đoạn code dễ bị tấn công sau:
Trong quá trình kiểm tra, chúng tôi có thể fuzz SSTI bằng cách GET một URL chẳng hạn như:
Nếu kết quả đầu ra chứa Hello 49
, điều này cho thấy phép toán đang được thực hiện và xử lý ở phía server => có thể exploit SSTI.
Lưu ý rằng cú pháp cụ thể cần thiết để đánh giá thành công phép toán sẽ khác nhau tùy thuộc vào template enginer nào đang được sử dụng.
Trong các trường hợp khác, lỗ hổng bị lộ do đầu vào của người dùng được đặt trong một biểu thức template, như chúng ta đã thấy trước đó với ví dụ email của mình. Điều này có thể ở dạng tên biến do người dùng kiểm soát được đặt bên trong một tham số, chẳng hạn như:
Khi đó payload khai thác sau url là:
Ví dụ, điều này sẽ được hiển thị trong đầu ra thành Hello Carlos
.
Ngữ cảnh này dễ bị bỏ qua trong quá trình đánh giá vì nó không dẫn đến XSS rõ ràng và hầu như không thể phân biệt được với một tra cứu hashmap. Một phương pháp kiểm tra việc SSTI trong ngữ cảnh này là trước tiên phải thiết lập rằng tham số không chứa lỗ hổng XSS trực tiếp bằng cách đưa HTML tùy ý vào giá trị:
Trong trường hợp không có XSS, điều này thường sẽ dẫn đến một mục nhập trống trong đầu ra ( Hello
không có tên người dùng), thẻ được mã hóa hoặc thông báo lỗi. Bước tiếp theo là cố gắng thoát ra khỏi câu lệnh bằng cách sử dụng cú pháp tạo khuôn mẫu phổ biến và cố gắng đưa HTML tùy ý vào sau nó:
Nếu điều này lại dẫn đến lỗi hoặc đầu ra trống, thì bạn đã sử dụng cú pháp từ ngôn ngữ tạo khuôn mẫu sai hoặc nếu không có cú pháp kiểu mẫu nào có vẻ hợp lệ, thì không thể tiêm mẫu phía máy chủ. Ngoài ra, nếu đầu ra được hiển thị chính xác, cùng với HTML tùy ý, thì đây là dấu hiệu chính cho thấy có lỗ hổng chèn mẫu phía máy chủ: Hello Carlos<tag>
Note: Tóm lại nếu XSS thì bạn phải cố gắng break out khỏi chuỗi;
Khi bạn đã phát hiện ra trang web có thể dính lỗ hổng SSTI, sau đó xác định template engine.
Mặc dù có rất nhiều template languages, nhiều ngôn ngữ trong số chúng sử dụng cú pháp rất giống nhau được chọn cụ thể để không xung đột với các ký tự HTML. Do đó, việc tạo các payload thăm dò để kiểm tra template engine nào đang được sử dụng có thể tương đối đơn giản.
Chỉ cần submit invalid syntax thường là đủ vì thông báo lỗi kết quả sẽ cho bạn biết chính xác template engine là gì và đôi khi là phiên bản nào. Ví dụ: biểu thức không hợp lệ <%=foobar%>
kích hoạt phản hồi sau từ template engine - ERB dựa trên Ruby:
Nếu không, bạn sẽ cần tự check hay là fuzz để có build payload dành riêng cho ngôn ngữ khác nhau và nghiên cứu cách chúng được run bởi template engines.
Nên lưu ý rằng cùng một payload đôi khi có thể trả về phản hồi thành công bằng nhiều template languages. Ví dụ: tải trọng {{7*'7'}}
trả về 49
trong Twig và 7777777
trong Jinja2. Do đó, điều quan trọng là không đi đến kết luận dựa trên một phản hồi thành công duy nhất.
Sau khi phát hiện ra rằng tồn tại một lỗ hổng tiềm ẩn và xác định thành công template enginers, chúng ta có thể bắt đầu cố gắng tìm cách khai thác lỗ hổng đó.
Học basic syntax rõ ràng là quan trọng, cùng với các chức năng chính và xử lý các biến. Ngay cả những việc đơn giản như học cách embed các native code blocks vào template đôi khi cũng có thể nhanh chóng dẫn đến việc khai thác. Ví dụ: khi bạn biết rằng Python-based Mako template engine
đang được sử dụng, việc thực thi mã từ xa (RCE
) có thể đơn giản như sau:
Ngoài việc cung cấp các nguyên tắc cơ bản về cách tạo và sử dụng template, tài liệu này cũng có thể cung cấp một số loại phần "Bảo mật". Tên của phần này sẽ khác nhau, nhưng nó thường sẽ phác thảo tất cả những điều nguy hiểm tiềm ẩn mà mọi người nên tránh thực hiện với template. Đây có thể là một nguồn tài nguyên vô giá, thậm chí hoạt động như một loại bảng gian lận về những hành vi mà bạn nên tìm kiếm trong quá trình kiểm tra, cũng như cách khai thác chúng.
Ngay cả khi không có phần "Bảo mật" chuyên dụng, nếu một đối tượng hoặc chức năng tích hợp cụ thể có thể gây rủi ro bảo mật, thì hầu như luôn có một cảnh báo nào đó trong tài liệu. Cảnh báo có thể không cung cấp nhiều chi tiết, nhưng ít nhất cảnh báo nên gắn cờ phần tích hợp sẵn cụ thể này là nội dung cần điều tra.
Ví dụ, trong ERB, tài liệu tiết lộ rằng bạn có thể liệt kê tất cả các thư mục và sau đó đọc các tệp tùy ý như sau:
Một khía cạnh quan trọng khác của việc khai thác các lỗ hổng server-side template injection là có ổn trong việc tìm kiếm các tài nguyên bổ sung trực tuyến. Khi bạn có thể xác định template engine đang được sử dụng, bạn nên duyệt web để tìm bất kỳ lỗ hổng nào mà những người khác có thể đã phát hiện ra(Cụ thể là hãy search nó ở trên mạng). Do việc sử dụng rộng rãi một số template engine, đôi khi có thể tìm thấy các khai thác được ghi chép đầy đủ mà bạn có thể điều chỉnh để khai thác trang web mục tiêu của riêng mình.
Tại thời điểm này, bạn có thể đã tình cờ phát hiện ra một cách khai thác khả thi bằng cách sử dụng tài liệu. Nếu không, bước tiếp theo là khám phá môi trường và cố gắng khám phá tất cả các đối tượng mà bạn có quyền truy cập.
Nhiều template engines hiển thị một số loại đối tượng "self" hoặc "enviroment", hoạt động giống như một không gian tên chứa tất cả các đối tượng, phương thức và thuộc tính được công cụ mẫu hỗ trợ. Nếu một đối tượng như vậy tồn tại, bạn có thể sử dụng nó để tạo danh sách các đối tượng nằm trong phạm vi. Ví dụ: Java-based templating languages, đôi khi bạn có thể liệt kê tất cả các biến trong môi trường bằng cách sử dụng phép nội xạ sau:
Điều này có thể tạo thành cơ sở để tạo một danh sách rút gọn các đối tượng và phương pháp có khả năng thú vị để điều tra thêm. Ngoài ra, đối với người dùng Burp Suite Professional, Intruder cung cấp một danh sách từ tích hợp sẵn cho brute force các biến.
Điều quan trọng cần lưu ý là các trang web sẽ chứa cả các đối tượng tích hợp sẵn do template cung cấp và các đối tượng tùy chỉnh, dành riêng cho trang web do nhà phát triển web cung cấp. Bạn nên đặc biệt chú ý đến các đối tượng không chuẩn này vì chúng đặc biệt có khả năng chứa thông tin nhạy cảm hoặc các phương pháp có thể khai thác. Vì các đối tượng này có thể khác nhau giữa các mẫu khác nhau trong cùng một trang web, hãy lưu ý rằng bạn có thể cần nghiên cứu hành vi của một đối tượng trong ngữ cảnh của từng mẫu riêng biệt trước khi tìm cách khai thác nó.
Mặc dù việc tiêm mẫu phía máy chủ có khả năng dẫn đến việc thực thi mã từ xa và chiếm toàn bộ máy chủ, nhưng trên thực tế, điều này không phải lúc nào cũng có thể đạt được. Tuy nhiên, chỉ vì bạn đã loại trừ việc thực thi mã từ xa, điều đó không nhất thiết có nghĩa là không có khả năng xảy ra một kiểu khai thác khác. Bạn vẫn có thể tận dụng các lỗ hổng chèn mẫu phía máy chủ cho các khai thác mức độ nghiêm trọng cao khác, chẳng hạn như truyền tải thư mục , để có quyền truy cập vào dữ liệu nhạy cảm.
Bước đầu tiên là xác định các đối tượng - object và phương thức mà bạn có quyền truy cập. Một số đối tượng có thể ngay lập tức nhảy ra như thú vị. Bằng cách kết hợp kiến thức của riêng bạn và thông tin được cung cấp trong tài liệu, bạn sẽ có thể tập hợp một danh sách rút gọn các đối tượng mà bạn muốn điều tra kỹ lưỡng hơn.
Khi nghiên cứu tài liệu về các đối tượng, hãy đặc biệt chú ý đến các phương thức mà các đối tượng này cấp quyền truy cập cũng như đối tượng nào chúng trả về. Bằng cách đi sâu vào tài liệu, bạn có thể khám phá sự kết hợp của các đối tượng và phương pháp mà bạn có thể xâu chuỗi lại với nhau. Việc kết hợp các đối tượng và phương pháp phù hợp với nhau đôi khi cho phép bạn có quyền truy cập vào chức năng nguy hiểm và dữ liệu nhạy cảm mà ban đầu có vẻ ngoài tầm với.
Ví dụ: Trong template engine Velocity dựa trên Java, bạn có quyền truy cập vào một Object ClassTool
có tên là $class
. Nghiên cứu tài liệu cho thấy rằng bạn có thể xâu chuỗi $class.inspect()
phương thức và thuộc $class.type
tính để có được các tham chiếu đến các đối tượng-Object tùy ý. Trước đây, điều này đã được khai thác để thực thi các lệnh shell trên hệ thống đích như sau:
Theo mặc định, một số template engines chạy trong môi trường an toàn, bị khóa để giảm thiểu các rủi ro liên quan nhiều nhất có thể. Mặc dù điều này gây khó khăn cho việc khai thác các template như vậy để thực thi mã từ xa (RCE), nhưng các Objects do nhà phát triển tạo connect với template có thể mang lại bề mặt tấn công sâu hơn.
Tuy nhiên, trong khi tài liệu quan trọng thường được cung cấp cho template dựng sẵn, các đối tượng dành riêng cho trang web gần như chắc chắn không được ghi lại. Do đó, tìm ra cách khai thác chúng sẽ yêu cầu bạn điều tra hành vi của trang web theo cách thủ công để xác định bề mặt tấn công và xây dựng cách khai thác tùy chỉnh của riêng bạn cho phù hợp.
Cách tốt nhất để ngăn việc server-side template injection là không cho phép bất kỳ người dùng nào sửa đổi hoặc gửi template mới. Tuy nhiên, điều này đôi khi không thể tránh khỏi do yêu cầu kinh doanh.
Một trong những cách đơn giản nhất để tránh tạo ra cácserver-side template injection là luôn sử dụng một công cụ tạo template "ít logic", chẳng hạn như Mustache, trừ khi thực sự cần thiết. Tách logic khỏi bản trình bày càng nhiều càng tốt có thể làm giảm đáng kể khả năng bạn tiếp xúc với các cuộc tấn công dựa trên mẫu nguy hiểm nhất.
Một biện pháp khác là chỉ thực thi mã của người dùng trong môi trường sandbox nơi các mô-đun và chức năng nguy hiểm tiềm ẩn đã bị xóa hoàn toàn. Thật không may, sandbox không đáng tin cậy vốn đã khó và dễ bị bỏ qua.
Cuối cùng, một cách tiếp cận bổ sung khác là chấp nhận rằng việc thực thi mã tùy ý là tất yếu nhưng không thể tránh khỏi và áp dụng sandbox của riêng bạn bằng cách triển khai template environment của bạn trong bộ chứa Docker bị khóa.