Ở bài trước, mình đã viết về điều tra memory shell bằng cách dump memory, upload một file jsp lên website và dựa vào các phương thức để lấy các thông tin liên quan đến Listener, Filter, Servlet, hay cấu hình logging. Tuy nhiên, phương pháp trên chỉ hiệu quả đối với servlet và cũng còn nhiều hạn chế như là việc cấu hình logging cần phải restart dịch vụ.
Và trong lúc trình bày về bài trước, một người anh xã hội đã hỏi mình: "Có cách nào hook thẳng vào memory không em?"
Bắt đầu từ phiên bản JDK 1.5, java đã thêm vào tính năng Instrumentation (Java Agent API) và JVMTI (JVM Tool Interface). Hai tính năng này cho phép chỉnh sửa bytecode của classfile trước khi nó được load, và cũng cho phép liệt kê toàn bộ class được load trong memory. Ở jdk1.5 thì việc chỉnh sửa và liệt kê cần phải diễn ra trước khi chạy chương trình phần nào đó không thực tế.
Rồi như sinh ra để dành cho việc tấn công và phỏng thủ. Từ phiên bản jdk1.6, Java Agent có thể can thiệp trực tiếp vào các tiến trình java đang chạy.(Tính năng ra mắt ở 1.5 là Premain và ở 1.6 là Agentmain ).
Nó là một con dao hai lưỡi khi mà vừa có thể tận dụng để tấn công khi chỉnh sửa, thêm vào class độc hại và cũng vừa có thể dùng để phòng thủ khi hoàn toàn có thể liệt kê các class trong bộ nhớ, dễ dàng kiểm tra nội dung của class mà không cần can thiệp vào chương trình đang chạy hay phải restart lại tiến trình,..
Đầu tiên cùng mình đi tìm hiểu về Premain vì nó là tiền đề cho Agentmain.
Premain
Ở Premain, class premain sẽ được load trước khi hàm main được load. Và để cấu hình cho việc này chúng ta cần phải sửa file MANIFEST.MF như sau:






<build>Hàm main:<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<archive>
<manifestFile>src/main/resources/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
</plugins>
</build>
package org.example;Khi chạy hàm main cũng cần phải thêm tham số:public class Main {
public static void main(String[] args) {
System.out.println("Attacker!");
}
}
-javaagent:PathToAgentFile/JavaAgent-1.0-SNAPSHOT.jar org.example.MainKết quả thu được:

Có thể thấy Premain được load trước khi hàm Main được load. Và dễ dàng có thể chỉnh sửa bytecode của hàm main:

Agentmain
Từ jdk 1.6 trở đi , agentmain ra đời và cho phép chúng ta tương tác trực tiếp với một tiến trình java đang chạy. Thay đổi class main thành như sau:
Build lại agent bằng cách thay tên đổi premain thành agentmain:


Build lại agent, và tiếp theo chúng ta sẽ viết hook. Khởi tạo một project mới. Thường thì lib attach tool đã có sẵn trong jdk1.6 trở đi, nhưng nếu tạo project với intelij mà chưa nhận lib thì add ở JAVA_HOME/libs/tools.jar nhé.



Cảnh sát JVM với khẩu súng mang tên Agent
Dưới góc độ phòng thủ hoàn toàn có thể sử dụng cơ chế này để attach vào tiến trình java đang chạy dịch vụ web kiểm tra xem các class nào đang được load. Ngoài ra còn có thể dump class, kiểm tra content của file được dump.
Ý tưởng về việc detect như sau:- Liệt kê tất cả class đang được load.
- Kiểm tra từng class xem có import những lib, có các superclass, annotations, interfaces có thể dẫn đến RCE không? Đánh dấu các class có nguy cơ
- Lặp qua từng class được đánh dấu để xác định chắc chắn nó là webshell



- Các import package nguy hiểm
- Kiểm tra Super class
- Kiểm tra các Annotations
- Kiểm tra tên class
- Kiểm tra các interface






Với các class của hệ thống sẽ có file .class, còn đối với memshell thì attacker sẽ hạn chế nhất có thể việc tạo ra file, nên việc khi một class được load vào hệ thống nhưng lại không có file .class cũng là một dấu hiệu để nghi ngờ.
Kiểm tra nội dung của các file class
Từ những hình thức kiểm tra trên phần nào giúp chúng ta tìm được memoryshell trong hệ thống một cách dễ hơn. Nó cũng giúp có thể tùy chỉnh những dấu hiệu để nhận diện memoryshell, dễ dàng cập nhật những chain mới. Và cũng đã khắc phục được những điểm yếu của công cụ của phần trước khi nó có thể nhận diện được cả tấn công với Spring, Agent attack và các hình thức inject class khác. Tuy nhiên, vẫn sẽ luôn luôn là cuộc đua giữa blueteam và redteam khi mà sẽ luôn có cách để obfuscate để tránh những kiểm tra ở trên, đòi hỏi người làm phòng thủ cần phải liên tục update "blacklist".
Cảm ơn mọi người đã đọc phần này, hẹn gặp mọi người ở phần sau với những kỹ thuật khác và điều tra memoryshell trên .NET
Nguồn tham khảo: