Challenge Solving
Source File
1 |
|
1 |
|
Unserialization Analyzing
Got phpinfo by accessing /?phpinfo:
Because session.serialize_handler was set to php and its default value is php_serialize, we can unserialize any object we want. And session.upload_progress.enabled was set to On and we have value of session.upload_progress.name, only we need to do is adding our payload at upload filename then our object will be unserialized.
POP Chain Building
Here is the POP clain: Happy->__destruct() ==> _New_->__get() ==> _New_->__toString() ==> Year->show()
1 |
|
I create a Happy object called $happy1 as starting object, its __destruct method will be called during unserialization. This method access happy attribute of $happy1->happy, then I create a _New_ object called $new1 and Happy->happy was set to it, $new1->__get magic method will be called because _New_ class does not have happy attribute. $new1->__get will connect $new1->daniu with some string, which will convert $new1->daniu into string if its type is not string. Then I create another _New_ object called new2 and $new1->daniu was set to it, $new2->__toString will be called when calling $new1->__get method converting $new2 into string. $new2->__toString will setup a specific attribute of $new2->daniu with specific value, and convert $new2->daniu, then I create a Year object called year1 and $new2->daniu was set to it, set $new2->robot and $new2->notrobot to zodiac and /etc/passwd so that the $year1->zodiac will be set to /etc/passwd, then $year1->__toString will be called and $year1->show show the file content of /etc/passwd. I didn’t use Year class directly because Year->__wakeup method will reset $year1->zodiac, so I have to use $new2->toString to setup $year1->zodiac dynamically.
Exploit
Now we have the payload to unserialize, so we can read any file. Let’s catch requests in burp and insert our payload.
1 | <form action="http://276c305a-1877-4365-bab1-45cd8da4be3b.challenge.ctf.show/index.php" method="POST" |
Reading /etc/passwd file successfully, but the flag is not at /flag. Here is a hint from ctfshow:
This hint tells us the flag is in other process, follow the hint I start to scan the process through /proc/pid/cmdline. Then I found a python process has pid 114.
1 | from flask import * |
This python script open the flag file without close, then remove the file. I test actions like this through an local script, and I found removed file can still access from script at /proc/pid/fd/3. Then read this file through http://127.0.0.1:5000/download/?filename=/proc/pid/fd/3.
Summarize
This time I used some tricks I learned from hackthebox. This is positive feedback for me to spend more time on hackthebox next. Maybe it’s not a bad idea Hah?
And the ctfshow lottery drew me and gave me a one-month bilibili membership as a prize, thanks.