ocd+i反序列化正则bypass
bypass反序列化正则
当执行反序列化时,使用正则 "/[oc]:\d+:/i" 进行拦截,代码见图 3-1-20,主要拦截了这类反序列化字符:
O:4:"demo":1:{s:5:"demoa";a:0:{}}
图 3-1-20 代码:
function sugar_unserialize($value)
{
preg_match('/[oc]:\d+:/i', $value, $matches);
if (count($matches))
{
return false;
}
return unserialize($value);
}
##这个正则表达式是用来防御 PHP 反序列化漏洞的,它专门用来拦截序列化字符串中的对象(Object)和自定义类(Class)。
我们来逐字拆解这个正则表达式 /[oc]:d+:/i 的含义:
正则表达式拆解:
1. / ... /i
- 这是正则表达式的定界符。
- 末尾的 i 代表不区分大小写。这意味着 o 和 O、c 和 C 都会被匹配。
2. [oc]
- 这是一个字符集合,表示匹配字母 o 或者字母 c。
- 在 PHP 序列化字符串的格式中:
- O 代表 Object(对象)。
- C 代表 Custom Object(自定义对象,通常用于 SplFixedArray 或实现了 Serializable 接口的类)。
3. :
- 匹配一个冒号字符。
4. d+
- d 代表匹配任意数字(0-9)。
- + 代表匹配一次或多次。
- 这表示匹配类名的长度(例如 5 或 12)。
5. :
- 匹配后面的第二个冒号。
匹配的目标格式:
这个正则表达式旨在匹配 PHP 序列化字符串中定义对象的标准格式:
- O:8:"ClassName":1:{...}
- O:表示这是一个对象。
- :8::表示类名 "ClassName" 的长度是 8。
- 正则中的 [oc]:d+: 正好对应 O:8: 这部分结构。
- C:16:"MyClass":100:{...}
- C:表示这是一个自定义对象。
- 正则同样匹配 C:16:。
防御原理:
PHP 反序列化漏洞(如 unserialize() 导致的代码执行)通常利用的是魔术方法(如 wakeup、destruct)。这些魔术方法只有在实例化对象时才会被触发。
- 如果攻击者只能传入数组(a:)或字符串(s:),通常无法触发代码执行。
- 只有传入对象(O: 或 C:),才能利用 POP 链(面向属性编程)触发漏洞。
结论:
这个正则表达式通过禁止输入中包含对象定义(即把 O:... 和 C:... 拦截掉),强制 unserialize() 函数无法生成对象,从而从根本上阻断了大多数 PHP 反序列化攻击链。
这是反序列中最常见的一种形式,那么如何进行绕过呢?通过对 PHP 的 unserialize() 函数进行分析,发现 PHP 内核中最后使用 php_var_unserialize 进行解析,代码见图 3-1-21。
图 3-1-21 代码:
case 'O': goto yy13;
yy13:
yych = *(YYMARKER++YYCURSOR);
if (yych == ':') goto yy17;
goto yy3;
yy17:
yych = *++YYCURSOR;
if (yybm[0+yych] & 128) {
goto yy20;
}
if (yych == '+') goto yy19;
yy19:
yych = *++YYCURSOR;
//判断字符是否为数字
if (yybm[0+yych] & 128) {
goto yy20;
}
goto yy18;
上面的代码主要是解析 "O:" 语句段,跟入 yy17 段中,还会存在 "+" 的判断。所以,如果输入 O:+4:"demo":1:{s:5:"demoa";a:0:{}},可以看到当 "O:" 后面为 "+" 时,就会从yy17 跳转到 yy19 处理,然后继续对 "+" 后面的数字进行判断,意味着这是支持 "+" 来表达数字,从而对上面的正则进行绕过。
本文来自博客园,作者:Doll_Marker,转载请注明原文链接:https://www.cnblogs.com/dollaikun/p/20633842

浙公网安备 33010602011771号