一道ISCC题引申的PHP正则复习

iscc中的一道web题“试试看”,描述为随意开火


image.png

起初看url,以为是一道常规的文件包含题,后面试了很多方法都出不来
最后受到其他师傅的启发才得到payload
这里有两种payload都可以

http://118.190.152.202:8006/show.php?img=php://filter/resource=1.jpg/resource=show.php
http://118.190.152.202:8006/show.php?img=php://filter/resource=show.php|jpg
image.png

image.png

对这道题目的匹配规则很感兴趣,在本地搭建进行仔细分析,也是对正则以及php函数的复习
在审计代码之前,先复习一下php的preg_match、strpos和file_get_contents等函数

1、preg_match函数用于正则匹配,第一个参数是要匹配的正则规则,第二个参数是被匹配的字符串。后面的可选参数中,$matches是一个数组,用于返回匹配的字符串结果

# preg_match
(PHP 4, PHP 5, PHP 7)
preg_match — 执行匹配正则表达式
### 说明
int **preg_match** ( string `$pattern` , string `$subject` [, array `&$matches` [, int `$flags` = 0 [, int`$offset` = 0 ]]] )
搜索`subject`与`pattern`给定的正则表达式的一个匹配.

2、strpos函数用于字符串查找,如果找到则返回位置,位置从0开始计算。如果没有找到则返回false

# strpos
(PHP 4, PHP 5, PHP 7)
strpos — 查找字符串首次出现的位置
### 说明
int **strpos** ( string `$haystack` , [mixed]`$needle` [, int `$offset` = 0 ] )
返回 `needle` 在 `haystack` 中首次出现的数字位置。
如果提供了参数matches,它将被填充为搜索结果。 $matches[0]将包含完整模式匹配到的文本, $matches[1] 将包含第一个捕获子组匹配到的文本,以此类推。

3、file_get_contents函数用于文本读取,可以获得文件内容,它更强大的地方在于可以通过http协议抓取内容

# file_get_contents
(PHP 4 >= 4.3.0, PHP 5, PHP 7)
file_get_contents — 将整个文件读入一个字符串
### 说明
string **file_get_contents** ( string `$filename` [, bool `$use_include_path` = false [, resource`$context` [, int `$offset` = -1 [, int `$maxlen` ]]]] )

和 file()一样,只除了 **file_get_contents()** 把文件读入一个字符串。将在参数 `offset` 所指定的位置开始读取长度为`maxlen` 的内容。如果失败,**file_get_contents()** 将返回 **`FALSE`**。

**file_get_contents()** 函数是用来将文件的内容读入到一个字符串中的首选方法。如果操作系统支持还会使用内存映射技术来增强性能。
> **Note**:
> 
> 如果要打开有特殊字符的 URL (比如说有空格),就需要使用 [urlencode()]进行 URL 编码。

本题中,经过注释和改造后的主要代码如下

show.php
<?php
error_reporting(0);
ini_set('display_errors','Off');

include('config.php');

$img = $_GET['img'];
if(isset($img) && !empty($img))
{
    if(strpos($img,'jpg') !== false)
    {        
        // strpos拿'resource='到$img中查找,如果匹配到了则前者为真;注意这里是全等
        // 如果没有匹配到'/resource=.*jpg/i'正则模式则后者为真;
        if(strpos($img,'resource=') !== false && preg_match('/resource=.*jpg/i',$img) === 0)
        {
            //满足上述两种情况,返回找不到文件
            die('File not found.');
        }
        // 再次进行正则匹配,如果以php://filter开头,并且字符串中存在resource=加上任意不包含|的字符串
        // 对$img进行左右两边空白或者预定符号的删除,最后匹配结果存到$matches数组
        preg_match('/^php:\/\/filter.*resource=([^|]*)/i',trim($img),$matches);
        // $matches[0]将包含完整模式匹配到的文本, $matches[1] 将包含第一个捕获子组匹配到的文本,以此类推。
        var_dump($matches);
        if(isset($matches[1]))
        {
            $img = $matches[1];
        }
        echo "<br>";
        echo $img;
        header('Content-Type: image/jpeg');
        // 关键函数get_contents,去获得文件内容
        $data = get_contents($img);
        echo $data;
    }
    else
    {
        die('File not found.');
    }

}
else
{
    ?>
    <img src="1.jpg">
    <?php
}
?>    
config.php
<?php  
// 关键函数get_contents,去获得文件内容
function get_contents($img)
{
    // 如果$img中存在'jpg',返回$img文件内容
    if(strpos($img,'jpg') !== false)
    {
        return file_get_contents($img);
    }
    // 否则返回$img的同时,设置返回头为hmtl
    else
    {
        header('Content-Type: text/html');
        return file_get_contents($img);
    }
}
?>  

这里通过实际payload在执行中的流程,对关键地方进行输出,方便分析和查看结果

0x01

首先分析show.php?img=php://filter/resource=config.php|jpg

逻辑中的第一个涉及preg_match的if语句中,只有在传入的$img中匹配到"resource="的同时,preg_match中$img匹配规则"/resource=.*jpg/i"匹配不到的情况下成立
在这里不会对payload形成影响
关键点在接下来的正则匹配

// 再次进行正则匹配,如果以php://filter开头,并且字符串中存在resource=加上任意不包含|的字符串
        // 对$img进行左右两边空白或者预定符号的删除,最后匹配结果存到$matches数组
        preg_match('/^php:\/\/filter.*resource=([^|]*)/i',trim($img),$matches);
        // $matches[0]将包含完整模式匹配到的文本, $matches[1] 将包含第一个捕获子组匹配到的文本,以此类推。
        var_dump($matches);
        if(isset($matches[1]))
        {
            $img = $matches[1];
        }
        echo "<br>";
        echo $img;
        // header('Content-Type: image/jpeg');
        // 关键函数get_contents,去获得文件内容
        $data = get_contents($img);
        echo $data;

可以看到,匹配规则是要求以php://filter开头,并且字符串中存在resource=加上任意不包含|的字符串
([^|]*)代表的意思就是排除|以外的字符,允许重复零次或多次,圆括号包裹则表示这是一个匹配的文本子组
匹配的结果保存在$matches数组中,并且$img会被覆盖为$matches的第2个元素
这里的关键在于$matches的第二个元素内容,第二个元素内容是圆括号包裹的([^|]*)子组的内容

image.png

经过正则后,$img已经被覆盖,内容为config.php
在config.php中,将通过函数file_get_contents($img)去获取指定文件内容并且返回

    // 如果$img中存在'jpg',返回$img文件内容
    if(strpos($img,'jpg') !== false)
    {
        return file_get_contents($img);
    }
    // 否则返回$img的同时,设置返回头为hmtl
    else
    {
        header('Content-Type: text/html');
        return file_get_contents($img);
    }
0x02

接下来分析show.php?img=php://filter/resource=1.jpg/resource=config.php
其他流程和上面的一样,只要字符串中包含jpg就可以,关键在于

preg_match('/^php:\/\/filter.*resource=([^|]*)/i',trim($img),$matches);

payload进去之后的匹配结果将是后面一个resource=config.php,而不是resource=1.jpg,因此拿到的$matches的第二个元素也是config.php!

image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,825评论 4 377
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,887评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,425评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,801评论 0 224
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,252评论 3 299
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,089评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,216评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 31,005评论 0 215
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,747评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,883评论 2 255
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,354评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,694评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,406评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,222评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,242评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,017评论 2 281

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,112评论 18 139
  • 常用函数 var_dump() 函数返回数组的数据类型和值 unset() 释放 bool define(stri...
    Scallions_阅读 587评论 1 2
  • 一、字符串操作 PHP开发中,我们遇到最多的可能就是字符串。 一个字符串 通过下面的3种方法来定义: 1、单引号 ...
    空谷悠阅读 703评论 1 6
  • 正则表达式是php中一个非常重要的知识点,通常用来查找和替换字符串,验证用户输入的信息格式是否符合规范,如邮件格式...
    雷雪松的简书阅读 683评论 0 7
  • 一,什么是正则: 正则表达式是一种描述字符串结果的语法规则,是一个特定的格式化模式,可以匹配、替换、截取匹配的字符...
    君满楼001阅读 735评论 0 1