PHP源码分析之parse_url()的2个小trick

Posted ChaMd5安全团队

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP源码分析之parse_url()的2个小trick相关的知识,希望对你有一定的参考价值。

前言:

之前从phithon师傅的代码审计小密圈看到pupiles师傅发过一篇文章,讲了parse_url()的很多小tricks,可惜只是给出了tricks的利用方法,并没有从底层原理上进行分析,正好我最近也在研究php源码,于是就给分析了一波。

本文测试使用的PHP版本为7.0.30

pupiles师傅的原文链接:

http://pupiles.com/%E8%B0%88%E8%B0%88parse_url.html

 

函数分析:

parse_url()定义在extstandardurl.c中第337

334行调用zend_parse_parameters()对参数进行解析,第一参数就是传入的URL字符串,第二个参数是可选的我们暂时不做研究。

348行,调用php_url_parse_ex()URL字符串进行解析,返回值保存在resource中,resource定义在341行,是一个php_url类型的结构体:

PHP源码分析之parse_url()的2个小trick

跟入php_url_parse_ex()

PHP源码分析之parse_url()的2个小trick

这个函数接收两个参数,分别是URL字符串和其长度

第100行声明了一个ret指针并为其分配了一个php_url结构,用于保存返回值

之后初始化s指向字符串开头,ue指向字符串结尾

 

第一个trick:

PHP源码分析之parse_url()的2个小trick

此时我们传入的字符串为 /pupiles.com:80
第107行把e指向了字符“:”所在的位置
第109行把s赋值给p

此时的指针结构入如下:

PHP源码分析之parse_url()的2个小trick

112行的if中有四个条件:

1.*p非字符

2.*p非数字

3.*p != ‘+’

4.*p != ‘-’

很明显,p指向的第一个字符是’/’,满足上述条件

113行再次进行判断,其中两个条件:

1.   e + 1 < ue,由上图知e + 2 == ue,故条件满足

2.   e < s + strcspn(s,"?#"), 由于字符串s中没有出现字符?和#,因此strcspn()返回s的长度15,e < s + 15,满足条件

 

114行 goto parse_port;

parse_port在第177行:

PHP源码分析之parse_url()的2个小trick

执行到第179行时指针结构如下:

PHP源码分析之parse_url()的2个小trick

181行的循环之后:

PHP源码分析之parse_url()的2个小trick

185行中if条件满足

187行中,因为pp - p == 2,所以把从指针p开始的两个字符复制到port_buf中,port_buf定义在99行:

PHP源码分析之parse_url()的2个小trick

188行追加一个空字符终止字符串,此时port_buf的值为: 80

189行从port_buf解析出port并在191行赋值给ret结构体的port成员

至此port解析完成,进入到215行的parse_host:

PHP源码分析之parse_url()的2个小trick

217行把ue赋值给e:

PHP源码分析之parse_url()的2个小trick

218行把p指向了字符’/’的位置:

PHP源码分析之parse_url()的2个小trick

219行把p赋值给e:

PHP源码分析之parse_url()的2个小trick

此时 e == s,故不会进入229行的if

继续向下:

PHP源码分析之parse_url()的2个小trick

246行的if不满足,进入到251行的else中

找到zend_memrchr()的定义:

PHP源码分析之parse_url()的2个小trick

传入的参数n即(e-s),由于e == s,即e - s == 0,可知n == 0

在zend_memrchr()的第189行,可知n <= 0时返回NULL

因此p == NULL,不会进入255行的if,而是进入到281行的else中:

PHP源码分析之parse_url()的2个小trick

281行把e赋值给p,还是和之前一样:

PHP源码分析之parse_url()的2个小trick

286行由于p == s,因此(p-s) < 1成立,291行return NULL,函数返回

自己写一个PHP文件测试一下:

<?php

$url = $_GET['url'];

var_dump(parse_url($url));

PHP源码分析之parse_url()的2个小trick



第二个trick:

PHP源码分析之parse_url()的2个小trick

实测一下:

PHP源码分析之parse_url()的2个小trick

在端口号之后加一个字符就会被当做path解析了,神奇!

继续分析一波:

这个字符串的解析过程和上述基本一致,不同发生在了parse_port中:

在185行时各指针如下:

PHP源码分析之parse_url()的2个小trick

PHP源码分析之parse_url()的2个小trick

由于此时185行的if不满足因此会进入到207行,跳转到just_path中:

PHP源码分析之parse_url()的2个小trick

305行把ue赋值给e:

由于字符串中不存在字符’#’和’?’

因此306和316行的if都不满足

326行s < e为真,之后设置了ret结构的path成员

331行返回结构体ret

 

 

后记:

本人不才,看C看的好心累,只分析了前两个trick,剩下的trick有兴趣的师傅欢迎投稿分享~!


ChaMd5安全招聘~

美团点评集团

移动安全专家(协议分析、安全审计方向)

http://www.chamd5.org/jobdetail.aspx?id=487

移动安全专家(产品研发方向)

http://www.chamd5.org/jobdetail.aspx?id=488


百度安全实验室

AI安全产品研发工程师

http://www.chamd5.org/jobdetail.aspx?id=482

AI安全研究员

http://www.chamd5.org/jobdetail.aspx?id=483


北京天际友盟信息技术有限公司

安全开发工程师

http://www.chamd5.org/jobdetail.aspx?id=474

情报/数据分析师

http://www.chamd5.org/jobdetail.aspx?id=475

Python爬虫工程师

http://www.chamd5.org/jobdetail.aspx?id=476

用户体验设计师

http://www.chamd5.org/jobdetail.aspx?id=477

JAVA工程师

http://www.chamd5.org/jobdetail.aspx?id=478

Web前端工程师

http://www.chamd5.org/jobdetail.aspx?id=479

售前工程师

http://www.chamd5.org/jobdetail.aspx?id=480

华东区销售总监

http://www.chamd5.org/jobdetail.aspx?id=481


西安讯蜂科技有限公司

前端开发工程师

http://www.chamd5.org/jobdetail.aspx?id=493

安全工程师

http://www.chamd5.org/jobdetail.aspx?id=492

安全研究员

http://www.chamd5.org/jobdetail.aspx?id=491

人工智能研究员

http://www.chamd5.org/jobdetail.aspx?id=490

数据分析研究员

http://www.chamd5.org/jobdetail.aspx?id=489

销售经理

http://www.chamd5.org/jobdetail.aspx?id=488


以上是关于PHP源码分析之parse_url()的2个小trick的主要内容,如果未能解决你的问题,请参考以下文章

[源码分析] OpenTracing之跟踪Redis

php parse_url linux 解析问题

PHP parse_url函数示例

php函数---parse_url函数

[单选题]parse_url()函数的功能是:

OSSIM之security.php源码分析