利用php序列化和反序列化的语法差异绕过防护

发布时间 - 2020-01-02 00:00:00    点击率:

介绍

官方文档中介绍php序列化和反序列化如下:

所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。 为了能够unserialize()一个对象,这个对象的类必须已经定义过。如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。

简单说序列化是对象转化字符串的过程,反序列化是字符串还原对象的过程。

环境

文章中所述内容使用环境如下:

PHP7.3.1、SDKVSCodeC++和C

在网上公开参数反序列化执行流程已经非常详细,但是对于一些细节地方有一些不足,其中就包括序列化和反序列化之间的语法差异问题。

差异问题

1、序列化

我们通过编译PHP内核源码分析,发现PHP序列化在默认情况下在对象转换中加入:{和}用来拼接成字符串。

[var.c]
Line:882
static void php_var_serialize_intern()
Line:896
if (ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash) == SUCCESS) {
                        smart_str_appendl(buf, "C:", 2);
                        smart_str_append_unsigned(buf, ZSTR_LEN(Z_OBJCE_P(struc)->name));
                        smart_str_appendl(buf, ":\"", 2);
                        smart_str_append(buf, Z_OBJCE_P(struc)->name);
                        smart_str_appendl(buf, "\":", 2);

                        smart_str_append_unsigned(buf, serialized_length);
                        smart_str_appendl(buf, ":{", 2);
                        smart_str_appendl(buf, (char *) serialized_data, serialized_length);
                        smart_str_appendc(buf, '}');
                    }
Line:952
smart_str_appendl(buf, ":{", 2);
Line:995
smart_str_appendc(buf, '}');

咱们来看上面这段代码,PHP会使用smart_str_appendl为序列化字符串前后拼接:{和},从var.c的第882行开始进入序列化逻辑。在第896行进行序列化字符串拼接,第952行和第995行,对于内嵌方法进行拼接。

2、反序列化

反序列化是将序列化的字符串,按照一定语法规则进行转化还原。

[var_unserialize.c]
Line:655
static int php_var_unserialize_internal()

Line:674{
    YYCTYPE yych;    
    static const unsigned char yybm[] = {          
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
        128, 128, 128, 128, 128, 128, 128, 128, 
        128, 128,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
          0,   0,   0,   0,   0,   0,   0,   0, 
    };
    if ((YYLIMIT - YYCURSOR) < 7) YYFILL(7);
    yych = *YYCURSOR;    
    switch (yych) {    
    case 'C':    
    case 'O':    goto yy4;    
    case 'N':    goto yy5;    
    case 'R':    goto yy6;    
    case 'S':    goto yy7;    
    case 'a':    goto yy8;    
    case 'b':    goto yy9;    
    case 'd':    goto yy10;    
    case 'i':    goto yy11;    
    case 'o':    goto yy12;    
    case 'r':    goto yy13;    
    case 's':    goto yy14;    
    case '}':    goto yy15;    
    default:    goto yy2;
    }

Line:776
yy15:
    ++YYCURSOR;
    {    /* this is the case where we have less data than planned */
    php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data");    
return 0; /* not sure if it should be 0 or 1 here? */
}

通过内核代码能够看到第655行进入反序列化,反序列化是利用词法扫描,判断各项符号转换对应对象。能够看到反序列化中对于}进行了处理,处理中只是对计数器加一并没有其他操作。

实际作用

反序列化语法的差异,对于安全防护设备判断反序列化产生很大的影响。在Snort中,有段规则如下:

alert tcp any any -> any [80,8080,443] (uricontent:".php"; pcre:"/\{\w:.+?\}/"; sid:1; 
msg:php_serialize;)

在攻击载荷中可以使用大多数字符代替{},从而导致规则失效。

总结

在红队攻击中可以利用PHP序列化和反序列化语法差异,从而达到绕过防护的目的。

在蓝队防御中建议考虑定义中所述不会保存对象的方法,只会保存类的名字。,拦截保存类的名字,以及语法中相同的字符比如冒号进行防御。

相关文章教程分享:网站安全教程


# php  # 字符串  # var  # 对象  # 序列化  # 微软  # 将会  # 只会  # 可以使用  # 所述  # 这段  # 相关文章  # 可以利用  # 中就 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel全局作用域是什么_Laravel Eloquent Global Scopes应用指南  如何快速选择适合个人网站的云服务器配置?  小米17系列还有一款新机?主打6.9英寸大直屏和旗舰级影像  文字头像制作网站推荐软件,醒图能自动配文字吗?  如何用AI帮你把自己的生活经历写成一个有趣的故事?  php8.4header发送头信息失败怎么办_php8.4header函数问题解决【解答】  ,交易猫的商品怎么发布到网站上去?  Android GridView 滑动条设置一直显示状态(推荐)  HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】  高端网站建设与定制开发一站式解决方案 中企动力  Laravel中间件如何使用_Laravel自定义中间件实现权限控制  如何实现建站之星域名转发设置?  Python文本处理实践_日志清洗解析【指导】  动图在线制作网站有哪些,滑动动图图集怎么做?  如何制作公司的网站链接,公司想做一个网站,一般需要花多少钱?  Edge浏览器提示“由你的组织管理”怎么解决_去除浏览器托管提示【修复】  ai格式如何转html_将AI设计稿转换为HTML页面流程【页面】  怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?  如何实现javascript表单验证_正则表达式有哪些实用技巧  如何注册花生壳免费域名并搭建个人网站?  如何在云主机上快速搭建多站点网站?  齐河建站公司:营销型网站建设与SEO优化双核驱动策略  Win11怎么关闭专注助手 Win11关闭免打扰模式设置【操作】  原生JS实现图片轮播切换效果  php后缀怎么变mp4格式错误_修改扩展名提示格式不对怎么办【技巧】  Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】  大同网页,大同瑞慈医院官网?  iOS验证手机号的正则表达式  laravel怎么为API路由添加签名中间件保护_laravel API路由签名中间件保护方法  Laravel怎么实现前端Toast弹窗提示_Laravel Session闪存数据Flash传递给前端【方法】  想要更高端的建设网站,这些原则一定要坚持!  Laravel怎么使用Intervention Image库处理图片上传和缩放  javascript基于原型链的继承及call和apply函数用法分析  郑州企业网站制作公司,郑州招聘网站有哪些?  长沙做网站要多少钱,长沙国安网络怎么样?  如何用景安虚拟主机手机版绑定域名建站?  Laravel如何使用Livewire构建动态组件?(入门代码)  如何确认建站备案号应放置的具体位置?  详解Android图表 MPAndroidChart折线图  Zeus浏览器网页版官网入口 宙斯浏览器官网在线通道  Laravel如何发送系统通知_Laravel Notifications实现多渠道消息通知  如何在浏览器中启用Flash_2025年继续使用Flash Player的方法【过时】  如何选择可靠的免备案建站服务器?  如何快速生成专业多端适配建站电话?  Linux网络带宽限制_tc配置实践解析【教程】  Win11怎么查看显卡温度 Win11任务管理器查看GPU温度【技巧】  网站制作大概要多少钱一个,做一个平台网站大概多少钱?  js实现点击每个li节点,都弹出其文本值及修改  三星网站视频制作教程下载,三星w23网页如何全屏?  Linux后台任务运行方法_nohup与&使用技巧【技巧】