Security risks caused by inconsistent PHP string serialization and deserialization Syntax Parsing

Source: Internet
Author: User

Not long ago, IPB reported an unserialize () vulnerability [1]. The vulnerability itself is nothing special, but the patch officially released by IPB is very interesting [2], soon Stefan Esser gave the bypass Method on twitter [3]. Subsequently, IPB officially released a new patch for this bypass, but Stefan Esser said that the new patch eventually resolved the vulnerability by changing the processing method, but its filtering function safeUnserialize () there are still security issues. Although Stefan Esser does not reveal the specific problem, I found that PHP had a Syntax Parsing inconsistency during string serialization and deserialization by checking the relevant PHP source code, this may cause serious security issues, and also easily Filter bypass safeUnserialize () functions. I. PHP string serialize ()-related source code analysis ---------------------------------- {% highlight c %} static inline void php_var_serialize_string (smart_str * buf, char * str, int len) /* {*/{smart_str_appendl (buf, "s:", 2); smart_str_append_long (buf, len); smart_str_appendl (buf, ": \" ", 2 ); smart_str_appendl (buf, str, len); smart_str_appendl (buf, "\"; ", 2) ;}{% endhighlight %} The above code snippet shows serialize () the following describes how to serialize a string:: {% Highlight php %} $ str = 'ryatsyne'; var_dump (serialize ($ str); // $ str serialized string output/s: 8: "ryatsyne "; {% endhighlight %} ii. PHP string unserialize ()-related source code analysis ------------------------------------- unserialize () function deserialization of string is divided into two types, one is to process the serialized string in the 's:' format: {% highlight c %} switch (yych ){... case's ': goto yy9 ;... yy9: yych = * (YYMARKER = ++ YYCURSOR); if (yych = ':') goto yy46; goto yy3;... Yy46: yych = * ++ YYCURSOR; if (yych = '+') goto yy47; if (yych <= '/') goto yy18; if (yych <= '9') goto yy48; goto yy18; yy47: yych = * ++ YYCURSOR; if (yych <= '/') goto yy18; if (yych> = ':') goto yy18; yy48: ++ YYCURSOR; if (YYLIMIT-YYCURSOR) <2) YYFILL (2); yych = * YYCURSOR; if (yych <= '/') goto yy18; if (yych <= '9') goto yy48; if (yych> = ';') goto yy18; yych = * ++ YYCURSOR; if (yych! = '"') Goto yy18; ++ YYCURSOR; {size_t len, maxlen; char * str; len = parse_uiv (start + 2); maxlen = max-YYCURSOR; if (maxlen <len) {* p = start + 2; return 0;} str = (char *) YYCURSOR; YYCURSOR + = len; if (* (YYCURSOR )! = '"') {* P = YYCURSOR; return 0;} // make sure the format is s: x:" x "YYCURSOR + = 2; * p = YYCURSOR; // note here, * the p pointer directly moves two digits behind, that is to say, it does not judge whether "is followed by; INIT_PZVAL (* rval); ZVAL_STRINGL (* rval, str, len, 1 ); return 1; {% endhighlight %} another method is to process the S: Format sequence string (this format is not defined in serialize () function serialization ): {% highlight c %} static char * unserialize_str (const unsigned char ** p, size_t * len, size_t maxlen) {size_t I, j; char * str = safe_emalloc (* len, 1, 1); u Nsigned char * end = * (unsigned char **) p + maxlen; if (end <* p) {efree (str); return NULL ;}for (I = 0; I <* len; I ++) {if (* p> = end) {efree (str); return NULL;} if (** p! = '\') {Str [I] = (char) ** p;} else {unsigned char ch = 0; for (j = 0; j <2; j ++) {(* p) ++; if (** p> = '0' & ** p <= '9 ') {ch = (ch <4) + (** p-'0 ');} else if (** p> = 'A' & ** p <= 'F') {ch = (ch <4) + (** p-'A' + 10);} else if (** p> = 'A' & ** p <= 'F ') {ch = (ch <4) + (** p-'A' + 10);} else {efree (str); return NULL ;}} str [I] = (char) ch;} (* p) ++;} str [I] = 0; * len = I; return str ;} // The above function is for www.2cto.com Convert hexadecimal strings like \ 72 \ 79 \ 61 \ 74 \ 73 \ 79 \ 6e \ 65... switch (yych ){... case's ': goto yy10; // The processing process is the same as that of S: if (str = unserialize_str (& YYCURSOR, & len, maxlen) = NULL) {return 0;} // The processing process is the same as that of s: {% endhighlight %}. From the code snippet above, we can see that unserialize () processes the serialized string deserialization as follows: {% highlight php %} $ str1 ='s: 8: "ryatsyne"; '; $ str2 ='s: 8: "ryatsyne" t'; $ str3 ='s: 8: "\ 72 \ 79 \ 61 \ 74 \ 73 \ 79 \ 6e \ 65" '; var_dump (unserialize ($ str); // $ str1, $ Str2 and $ str3 unserialized string output // ryatsyne; {% endhighlight %} iii. security risks caused by inconsistent Syntax Parsing processing ----------------------------- from the above analysis process, we can see that PHP does not strictly follow the serialization format s: x: "x"; When deserializing strings, no judgment on whether or not the following string exists. At the same time, the processing of the hexadecimal string is added, which makes the inconsistency between the pre-processing and post-processing confusing, at the same time, due to the absence of detailed descriptions in the PHP manual, most programmers do not know about the processing process, which may lead to omissions in the coding process, and even cause serious security problems. Back to the IPB vulnerability mentioned at the beginning of the article, using this funny feature of PHP can easily bypass safeUnserialize () filter Function: {% highlight php %} * mixed safe_unserialize (string $ serialized) * Safely unserialize, that is only unserialize string, numbers and arrays, not objects ** @ license Public Domain * @ author dcz (at) phpbb-seo (dot) com */static public function safeUnserialize ($ serialized) {// unserialize will return false for obje Ct declared with small cap o // as well as if there is any ws between O and: if (is_string ($ serialized) & strpos ($ serialized, "\ 0 ") === false) {if (strpos ($ serialized, 'O: ') === false) {// the easy case, nothing to worry about // let unserialize do the job return @ unserialize ($ serialized);} else if (! Preg_match ('/(^ |; | {|}) O: [+ \-0-9] +: "/', $ serialized )) {// in case we did have a string with O: in it, // but it was not a true serialized object return @ unserialize ($ serialized) ;}} return false ;} // a: 1: {s: 8: "ryatsyne" tO: 8: "ryatsyne": 0: {}}// as long as similar serialized strings are constructed, the {% endhighlight %} iiii can be easily filtered out here. refer to ---------- * [1] [ http://seclists.org/bugtraq/2012/Nov/17 ] ( http://seclists.org/bugtraq/2012/Nov/17 ) * [2] [ http://adminextra.com/threads/ip-board-3-1-x-3-2-x-and-3-3-x-hacked.6125/ ] ( http://adminextra.com/threads/ip-board-3-1-x-3-2-x-and-3-3-x-hacked.6125/ ) * [3] [ http://twitter.com/i0n1c ] ( http://twitter.com/i0n1c )

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.