Cũng lâu rồi mình không viết blog về write up ctf, phần lớn là do mình solve khá muộn màng và hay phải đi học wu của người khác, và đây là cũng không phải là một ngoại lệ. Giải này được người anh refer là có bài java khá là hay nên mình cũng lọ mọ làm và xem sol của người khác trong kênh discord để phân tích. Đây là bài java ctf đầu tiên mà mình làm được ra flag nên mình muốn viết lại quá trình làm và tìm hiểu để sau này đọc lại cho nhớ hehe=)). Bắt đầu thoi
Ukay, nhìn thấy sample request là có thể đoán được bài cho mình POST xml rùi :">
Đi vào từ phần đọc source đã, đề bài cho mình file war mà không cho file pom (set up lại code gen xml khá cay), mình sử dụng Inteliji để đọc file war.
Để có thể đọc được thì mình sẽ sử dụng 7-zip để extract file war ra một thư mục, và đọc thư mục đó bằng Inteliji là được:
Bắt đầu tiến hành đọc source thui
Challenge có 3 class thông tin và 1 file xử lý servlet request GET và POST. Trong đó class Calculator là class mang thông tin mà mình muốn khai thác, class Node là class có các element tương ứng trong xml POST request của mình, còn class Result sẽ chứa những element tương ứng trong xml response.
Đi vào từng class, mình đọc class Calculator đầu tiên:
HttpURLConnection.openConnection().connect()
, cuối cùng là trả về status code khi truy cập đến URL đóClass Node:
Tiếp đến mình muốn chú ý đến cách thức server xử lý request POST:
Server gọi đến class JAXBContext và 2 interface Marshaller và Unmashaller để thực hiện việc xử lý convert object sang xml và ngược lại.
Trong đoạn code trên, unmarshaller thực hiện phương thức unmarshall lên xml mình gửi, ép kiểu về kiểu Node và ta có object node chứa thông tin về location
mình POST.
Sau đó mình có object calculator nhận giá trị locationA là giá trị location của node. LocationB được hard code là /tmp/location.txt
, ngoài ra giá trị truyền vào phương thức setServerValidationCheck cũng được gán luôn là http://localhost:8080/NodeCalculator/nodeCalc
. Nếu như phương thức trả về kết quả là 200 (server status) thì ta sẽ trả về kết quả là của một phương thức khác là calculateDistance. Marshaller gọi đến phương thức marshal để dùng kết quả đó chuyển object result về dạng xml trả về cho mình trong response.
Quan sát Dockerfile mình biết được flag được đưa vào /tmp/flag.txt
Tổng hợp lại thông tin thì mình thấy được là mình có một class Node hiện tại thiếu phần constructor, đặc biệt là việc constructor nhận một Object, object node chỉ nhằm việc cấp giá trị của locationA cho class calculator, việc xử lý sẽ nằm hoàn toàn ở class calculator.
Ở class calculator, mình thấy nếu control được giá trị locationB thì có thể thực hiện Arbitary File Read. Việc server gửi request đến URL truyền vào phương thức setServerValidationCheck
với giá trị leaderLocation là nội dung file cũng làm mình nghĩ đến việc nếu như control được giá trị truyền vào hoàn toàn có thể lấy nội dung file bằng các web request catcher
Tuy nhiên mình chỉ control được object Node, còn đâu object Calculator đã được hard code sẵn rồi. Mình đã rất bí khi đến bước này, và sau khi xem solution thì mình không hiểu thanh niên kia móc đâu ra được con thẻ constructor =)). Và mình chợt nhận ra là constructor của Node mình có thể can thiệp và nhét thêm một object calculator trước khi tiến hành convert sang xml.
Câu hỏi đặt ra giờ là tại sao thẻ constructor này bypass được việc gán tĩnh 2 giá trị của object calculator, thì người solve cũng đã giải đáp như sau: Class Node được khai báo @XmlAccessorType(XmlAccessType.PROPERTY)
sẽ khiến cho tất cả các setter được gọi ra trong quá trình deserialization. Nếu như có sự xuất hiện của tag constructor trong xml của calculator, khi trigger đến object calculator nó sẽ gọi đến các setter, từ đó lưu các giá trị của mình vào được object
Mọi thứ cũng đã rõ ràng, vậy thì mình sẽ cần phải sửa chút code để gen ra một cái xml có chứa các tag như kia:
Sửa lại class Node với việc thêm một giá trị kiểu object và sửa lại 2 phương thức get/setConstructor
Khi xử lý request, mình gán object calculator vào phương thức setConstructor trước khi đưa object Node về dạng xml:
Có thể thấy việc setup XML đã thành công, và mình cũng đọc được file flag local
Mình có mẫu xml để solve bài này như sau:
Gửi đi request POST:
Lụm flag