Chắc bởi vì mình thấy dạng này khác hay nên mình đã kiếm một số bài về nó để làm. Có bài mình tự làm cũng có bài xem qua writeup nên đôi khi lời mình khá lũng củng và khó hiểu. Một số bài mình dựng lại trên local nên flag chỉ mang tính tượng trưng thôi ^^.
Về POP chain trong PHP thì mình đã nói sơ qua ở đây. Oke bắt đầu thôi :v .
Link tại đây.
Bài cho soure code và đây là thứ cần quan tâm:
data
qua method POST và thực hiện unserialize nó.GetMessage
và WakyWaky
.flag
sẽ được lấy trong magic method __destruct()
của class GetMessage
:Vậy điều kiện lấy flag
là:
__destruct()
được thực thi: đây là magic method trong PHP sẽ được thực thi khi đối tượng được hủy hoặc chương trình kết thúc (không được thực thi khi chương trình kết thúc bởi hàm die()
.receive
của đối tượng tại bởi class GetMessage
là HelloBooooooy
.$getflag
có giá trị true.Đầu tiên để __destruct()
thực thi là tránh xuất hiện hàm die()
Ta thấy trong class GetMessage
có:
Đây là 1 magic method thực thi khi được khởi tạo đối tượng. Tuy nhiên nếu khởi tạo luôn là $receive
có giá trị là HelloBooooooy
sẽ bị false vì nó thực thi die()
nên nó cần gán sau khi khởi tạo và method __toString()
trong class WakyWaky
phải được thực thi vì nó làm được điều này:
Tiếp tục để biến $getflag
có giá trị true ta thấy trong class WakyWaky
:
__toString()
là 1 magic method được thực thi khi 1 đối tượng tạo bởi class đó được dùng như string. Ví dụ như: echo
, print
, preg_match()
,…
Nhận thấy trong cùng class này có :
Khi $this->msg
là 1 đối tượng của class WakyWaky
thì đối tượng đó sẽ thực thi __toString()
. Vậy để __wakeup()
thực thi là được, đây cũng là 1 magic methed thực thi khi đối tượng được unserialize => Đối tượng cần truyền vào hàm unserialize()
tạo bởi class WakyWaky
.
Tóm lại script:
Được payload:
Két quả:
flag:
uns3r14liz3_p0p_ch41n_r0cks
Link bài lab.
Các dạng bài này thường sẽ cho source hoặc bị leak ra như bài này:
Thêm ~
phía sau và truy cập vào để xem source /cgi-bin/libs/CustomTemplate.php~
:
Tổng quan: đề yêu cầu xóa file morale.txt
trong thư mục home của Carlos nghĩa là phải thực thi được câu lệnh: rm /home/carlos/morale.txt
. Có 4 class trong source. Bây giờ login wiener:peter
và kiểm tra giá trị cookie và decode nó:
Giá trị nhận được là O:4:"User":2:{s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"ic9rwytnufldpgjrox3xmrrhdyuzmguo";}
đây là dạng serialized data, thứ mà ta cần biến đổi nó.
Bắt đầu phân tích và khai thác:
Để ý thấy trong class DefaultMap
có method __get()
thực thi hàm call_user_func
đây là hàm đặc biệt vì nó có thể thực thi 1 hàm theo ý muốn khi truyền vào. Ở đây thứ ta muốn là thực thi system('rm /home/carlos/morale.txt')
thì ta cần thực thi call_user_func(system,'rm /home/carlos/morale.txt')
(ngoài system
còn có các hàm khác như exec
, passthru
,…). Vậy để nó thực thi như vậy thì ta cần:
$this->callback
có giá trị là system
, cái này ta có thể làm được khi khởi tạo đối tượng. Ví dụ: $defaultmap = new DefaultMap('system');
__get()
được thực thi khi truy cập thuộc tính không được public hoặc không tồn tại của đối tượng khi đó thuộc tính đó được truyền vào __get()
. Ở class CustomTemplate
có 2 thuộc tính private khả nghi.Quan sát thấy class Product
có : $this->desc = $desc->$default_desc_type;
. Nếu $desc
là đối tượng class DefaultMap
($defaultmap
) và $default_desc_type
có giá trị là rm /home/carlos/morale.txt
thì __get()
như đã nói trên sẽ thực thi. (2 thuộc tính này là của class CustomTemplate
nên có thể kiểm soát được )
Để __construct()
của class Product
thực thi thì phải khởi tạo đối tượng của class Product
và điều đó xảy ra nếu hàm build_product()
. Và hàm này được gọi trong __wakeup
của class CustomTemplate
. Magic method này được thực thi khi deserialize đối tượng. Vậy bây giờ ta tạo một serialized data của đối tượng class CustomTemplate
bằng script sau:
Output:
O:14:"CustomTemplate":2:{s:17:"default_desc_type";s:26:"rm /home/carlos/morale.txt";s:4:"desc";O:10:"DefaultMap":1:{s:8:"callback";s:6:"system";}}
Bây giờ encode base64 và mã hóa URL được:TzoxNDoiQ3VzdG9tVGVtcGxhdGUiOjI6e3M6MTc6ImRlZmF1bHRfZGVzY190eXBlIjtzOjI2OiJybSAvaG9tZS9jYXJsb3MvbW9yYWxlLnR4dCI7czo0OiJkZXNjIjtPOjEwOiJEZWZhdWx0TWFwIjoxOntzOjg6ImNhbGxiYWNrIjtzOjY6InN5c3RlbSI7fX0%3D
Đưa nó vào cookie và kết quả:
Bài này mình dựng lại ở local để làm.
Source:
Tổng quan: bài nhận vào tham số pop
từ URL và unserialize nó. Có 3 class là Modifier
, Show
, Test
. Flag nằm trong file flag.php
. Vậy trong 3 class thì chỗ nào có thể đọc được file flag? Đó là hàm include
trong class Modifier
Nó có thể đọc file khi dùng wrapper:
php://filter/convert.base64-encode/resource=flag.php
và hiển thị dạng base64.
Vậy chỉ cần append()
thực thi và nó nằm trong magic method __invoke()
Magic method
__invoke()
sẽ thực thi khi một đối tượng được dùng như gọi hàm. Ví dụ$obj();
Nhìn tiếp trong class Test
có dòng code return $function();
trong method __get()
và giá trị $function
(cụ thể là thuộc tính p
của class đó) là đối tượng của class Modifier
thì __invoke()
được thực thi.
Vậy chỉ cần thực thi được __get()
Magic method
__get()
thực thi khi đối tượng gọi đến thuộc tính không phải public hoặc không tồn tại.
Vậy để ý tiếp trong class Show
có:
Khi $this->str
là đối tượng của class Test
($test
) thì nó sẽ thực thi __get()
vì đối tượng này không có thuộc tính source
. Bây giờ chỉ cần tạo giá trị str
là $test
và __toString()
được thực thi.
Magic method
__toString()
thực thi khi đối tượng được dùng như string. Ví dụ:echo $obj;
,…
Và ở đây hàm preg_match()
cũng có thể làm được điều đó vì tham số truyền vào (source
) là string.
Vậy $this->source
là đối tượng của chính class đó là sẽ thực thi được toString()
Cuối cùng là việc thực thi __wakeup()
.
Magic method
__wakeup()
thực thi khi deserialize đối tượng.
Ta có script:
Lấy giá trị đó đưa vào pop
là oke, 1 đoạn base64 hiện ra vào decode chúng là file flag.