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()定义在\ext\standard\url.c中第337行

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

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

跟入php_url_parse_ex()

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

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

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

第一个trick:

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

此时的指针结构入如下:

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行:

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

181行的循环之后:

185行中if条件满足

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

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

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

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

217行把ue赋值给e:

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

219行把p赋值给e:

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

继续向下:

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

找到zend_memrchr()的定义:

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

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

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

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

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

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

<?php

$url = $_GET['url'];

var_dump(parse_url($url));

第二个trick:

实测一下:

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

继续分析一波:

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

在185行时各指针如下:

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

305行把ue赋值给e:

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

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

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

331行返回结构体ret

后记:

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

原文发布于微信公众号 - ChaMd5安全团队(chamd5sec)

原文发表时间:2018-06-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏专注数据中心高性能网络技术研发

[Effective Modern C++(11&14)]Chapter 4: Smart Pointers

2622
来自专栏Golang语言社区

Golang语言 - 以任意类型的slices作为输入参数

最近参与的一个业余项目,go-linq,让我了解到Go语言的类型系统并不是为任何类面向 对象编程而设计的。没有泛型,没有类型继承,也没有提供任何对这些特性有用的...

3768
来自专栏灯塔大数据

技术 | Python从零开始系列连载(十二)

导读 为了解答大家初学Python时遇到各种常见问题,小灯塔特地整理了一系列从零开始的入门到熟练的系列连载,每周五准时推出,欢迎大家学积极学习转载~ 上一期学习...

39415
来自专栏Ryan Miao

Java8-如何构建一个Stream

Stream的创建方式有很多种,除了最常见的集合创建,还有其他几种方式。 List转Stream List继承自Collection接口,而Collection...

3714
来自专栏机器学习算法与Python学习

python基础-字符串与编码

转载于:廖雪峰的官方网站-python教程 字符编码 我们已经讲过了,字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题。 因为计算机只能处理数字...

46711
来自专栏小樱的经验随笔

【Java学习笔记之三十三】详解Java中try,catch,finally的用法及分析

这一篇我们将会介绍java中try,catch,finally的用法 以下先给出try,catch用法: try {   //需要被检测的异常代码 } ca...

3679
来自专栏10km的专栏

jface databinding: 创建readonly(只读)可观察对象(observable)

java与C++有一点不同:C++有const关键字,使用const关键字,用于指定一个参数、成员变量或函数是只读不可修改的,通过const参数让对象成为rea...

2005
来自专栏大闲人柴毛毛

剑指offer代码解析——面试题14调整数组顺序使奇数在偶数之前

本题详细解析都已在代码中注释了: /** * 题目:输入一个数组,要求将奇数放在数组的前半段,偶数放在数组的后半段 * @author 大闲人柴毛毛 *...

3055
来自专栏小白的技术客栈

Python基础语法-内置数据结构概览

本文内容非常简单,主要介绍接下来要讲的内容。那就是Python的内置数据结构。今天只是简单介绍一下Python都有哪些内置数据结构,这样就可以循序渐进地进行学习...

3477
来自专栏日常学python

史上最全关于sorted函数的10条总结(文末附送书中奖名单)

sorted 用于对集合进行排序(这里说的集合是对可迭代对象的一个统称,他们可以是列表、字典、set、甚至是字符串),它的功能非常强大,本文将深入浅出地介绍 s...

814

扫码关注云+社区