The Art of Deserialization Gadget Hunting [part 2]
Như đã hứa hẹn trong bài trước, phần 2 này sẽ tiếp tục nói về một số gadgetchain thông dụng trong bộ tool ysoserial.
Việc phân tích gadgetchain như này nó cũng giống như việc review source code, không thú vị như các writeup về bounty hunting, nhưng nó là bước khởi đầu cơ bản để tìm được các lỗ hổng trong phần mềm.
“Những thứ anh làm thường đơn giản, nên không hay được đánh giá cao …”
(Credit: https://www.youtube.com/watch?v=KKc_RMln5UY)
#2. CommonsCollection5
Trong bộ ysoserial có đến 7 gadgetchain liên quan tới library Apache CommonsCollections (https://commons.apache.org/proper/commons-collections/).
Chỉ cần đọc hiểu kỹ 7 cái gadgetchain này là đã có thể thu về rất nhiều kinh nghiệm về Java Deserialization nói riêng, và về cách hoạt động của Java nói chung.
Version hiện tại của CommonsCollections là 3.2.2, 4.4 đã có các phuơng pháp để chống bị lợi dụng thành gadgetchain, mọi chain còn lại đều hoạt động trên version 3.2.1, 4.3 ngoại trừ CC1 và CC3 do version của java đã chặn!
Các gadgetchain này trông thì hơi khác nhau, nhưng đều có đặc điểm chung là lợi dụng class InvokerTransformer và InstantiateTransformer để invoke method.
Sau khi random 1 trong 7 gadgetchain, mình chọn ra CC5 để làm mẫu phân tích cho bài này.
Gadgetchain có dạng như sau:
BadAttributeValueExpException.readObject() TiedMapEntry.toString() TiedMapEntry.getValue() LazyMap.get() ChainedTransformer.transform() ConstantTransformer.transform() InvokerTransformer.transform() Method.invoke() Class.getMethod() InvokerTransformer.transform() Method.invoke() Runtime.getRuntime() InvokerTransformer.transform() Method.invoke()
Mình thực hiện debug trực tiếp gadget này trên ysoserial,
Gadgetchain được bắt đầu tại BadAttributeValueExpException.readObject() và gọi tới TiedMapEntry.toString(),
Content của method BadAttributeValueExpException.readObject() có dạng như sau:

Breakpoint tại điểm gọi tới Object.toString() và tiến hành debug:


Ta có thể thấy, ngay khi breakpoint dừng tại line 86, chưa cả đi hết gadgetchain nhưng calculator đã bị pop up. Vậy điều gì đã xảy ra??
Đây là một tính năng của IntellIJ Debugger!
Như mình đã nói trong bài trước, về cái nhược điểm khó chịu của Eclipse: đó là khi debug với class không có source code, nó không có show ra local variable của method.
IntellIJ debugger thì lại làm được điều này, cho ra các local variable của method đang debug.
Cùng nhìn rõ hơn vào bảng chứa thông tin Variables của IntellIJ khi debug:

Mình ko tìm hiểu sâu về internal của IntellIJ, nhưng theo kinh nghiệm của mình đến thời điểm hiện tại thì vấn đề có thể được giải thích như thế này,
Khi dừng tại breakpoint, muốn show được ra các variable thì debugger phải bằng cách nào đó lấy được các variable được khai báo trước breakpoint. Theo như suy đoán của mình, sau khi lấy được các variable dưới dạng object, và để show lại cho người dùng dưới dạng tường minh, nghĩa là dạng Human-readable. Dạng Human-readable là gì? Là String chứ còn gì nữa ¯\_(ツ)_/¯.
Ở đây để có thể lấy về Object dưới dạng String, debugger đã “ngầm” invoke method toString() của object variable muốn show ra cho người dùng, như trong trường hợp hiện tại thì debugger đã lén invoke method toString() của valObject và khiến cho các chain về sau được thực thi luôn -> calc pop up!
Khi dừng breakpoint, IntellIJ cũng đã cảnh báo về có gì sai sót ở đây:

Tính năng này như con dao 2 lưỡi của cái IntellIJ Debugger này,
- Tuyệt đối không bao giờ debug malware trên IntellIJ debugger
- Phải luôn tỉnh táo khi debug bằng IntellIJ, predict được trước các variable, các flow của chương trình và đặt breakpoint cho chính xác. Đôi khi đặt 1 breakpoint nhầm cũng có thể gây ra sai sót cho việc debug toàn bộ chương trình!
Ngoài việc lén invoke toString() ra, debugger còn lén invoke các setter-getter method nữa, nhưng mình nói rõ hơn khi gặp!