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

CTFshow系列——PHP特性Web89-92

好了,今天开始给大家带来php特性系列的文章,毕竟这部分内容我也没接触过,所以也是想着边学习边了解。

文章目录

    • Web89
      • 代码解释
      • 漏洞利用
      • payload
    • Web90(新方法)
      • 其他WP方法
    • Web91
      • 代码分析
      • payload解释
    • Web92(类似Web90)
      • 漏洞利用方法
    • 总结


Web89

老样子,开篇先看代码:

<?phpinclude("flag.php");
highlight_file(__FILE__);if(isset($_GET['num'])){$num = $_GET['num'];if(preg_match("/[0-9]/", $num)){die("no no no!");}if(intval($num)){echo $flag;}
}

代码解释

  • if(preg_match("/[0-9]/", $num)): 这是关键的过滤器。它使用正则表达式 /[0-9]/ 来检查 $num 变量中是否包含任何数字。如果包含,die("no no no!"); 会被执行,程序终止,你无法获取 flag
  • if(intval($num)): 这是触发漏洞的关键点。intval() 函数的作用是将变量转换为整数。
    • 如果 $num 变量是一个可以被转换为非零整数的值,那么 intval($num) 就会返回一个非零值,在布尔上下文中被认为是 true
    • 当这个条件成立时,echo $flag; 就会被执行,flag 的值就会被打印到页面上。

漏洞利用

要成功获取 flag,你需要找到一个既不包含数字,又能在经过 intval() 转换后得到非零整数的值。

因此,payload 必须是一个字符串,且不包含 0-9 任何一个数字,但被 intval()转换时能得到一个非零的值。

payload

  • 一个常见的绕过方法是利用 科学计数法。例如,intval("0x1") 会得到 1,但是 0 是数字。
  • 最简单的方法是利用布尔值。在 PHP 中,true 转换为整数是 1false 转换为整数是 0

但很遗憾,这两个并不行;

于是经过我测试,又找到了一种方法:

  • 数组参数绕过(最通用、无版本依赖)
    • 原理:preg_match的数组处理特性:preg_match(“/[0-9]/”, $num)仅能处理字符串
    • 若num是数组,函数会直接返回false(不匹配任何内容),因此不会触发die(“no no no!”);
    • intval数组处理规则:PHP 官方规定「数组转换为整数时固定返回 1」,intval中输入数组,返回的值只看数组是否为空,为空返回0,否则返回1 ,恰好满足intval($num)的条件,最终输出flag。
# 常见可用 Payload:?num[]=(空数组值)
?num[]=a(任意非数字字符)
?num[]=xyz(任意字符串)

在这里插入图片描述
根据上述特性,即可得到flag。

Web90(新方法)

<?phpinclude("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){$num = $_GET['num'];if($num==="4476"){die("no no no!");}if(intval($num,0)===4476){echo $flag;}else{echo intval($num,0);}
}

代码解释:

  • if($num==="4476"): 这是第一个关键点。=== 是一个严格比较运算符。它不仅会比较两个变量的值,还会比较它们的类型。
    • 因此,你不能直接输入字符串4476
  • if(intval($num, 0)===4476): 这是第二个关键点,也是漏洞所在
    • intval($num, 0) 函数会尝试将 $num 转换为一个整数
    • 0x 开头会被识别为十六进制
    • 0b 开头会被识别为二进制
    • 0 开头会被识别为八进制

否则,会被识别为十进制。


思路:用其他进制来表示4776:

因此,你的 payload 可以是:

在这里插入图片描述

# 八进制
?num=010574 # 十六进制
?num=0x117c 

也是成功得到flag

其他WP方法

  • 科学计数法:

    • 小数点:intval(‘4476.0’)===4476
    • 正负号:intval(‘+4476.0’)===4476
    • 科学计数法:intval(‘4476e1’)===4476
  • 有关这个函数intval(str,int)的讲解:

    • PHP 的 intval 函数会从字符串的开始部分提取有效数值,直到遇到非数字字符就停止了
    • 所以,只要在其后面加入特殊符号即可绕过
# payload
?num=4476.0
?num=+4476
?num=4476e1# 此处以’为例,也可尝试其他特殊字符
?num=4476'

Web91

<?phpshow_source(__FILE__);
include('flag.php');
$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){if(preg_match('/^php$/i', $a)){echo 'hacker';}else{echo $flag;}
}
else{echo 'nonononono';
}

代码分析

我们发现代码与之前又有一点不一样,多了preg_match('/^php$/im', $a)部分代码分析:

  • /^php$/im):关键的正则匹配

    • ^:匹配字符串的开头。
    • $:匹配字符串的结尾。
    • php:匹配字面量 “php”。
    • i:忽略大小写。
    • m:多行模式。
  • 作用:在多行模式下,^ 和 $ 不仅匹配整个字符串的开头和结尾,还匹配每一行的开头和结尾。


  • 区别:这两个正则表达式的区别在于多行模式(m)
    • 要获取 flag,你需要找到一个输入 a,它能满足第一个 if 语句(/^php/im),但不能满足第二个 if 语句(/^php$/i
  • 多行模式允许 ^ 和 $ 匹配字符串内部的换行符。
  • 非多行模式下,^ 和 $ 只匹配整个字符串的开头和结尾。

payload解释

因此,我们可以利用换行符(%0a,URL 编码)来构造 Payload:

# payload
?cmd=php%0aphp

为什么这个 Payload 能成功?

  1. 第一个 if:preg_match('/^php$/im', 'php\nphp')
  • 在多行模式下,^php$ 会匹配每一行,所以它会匹配第一行的 php 和第二行的 php。这个条件为真。
  1. 第二个 if:preg_match('/^php$/i', 'php\nphp')
  • 在非多行模式下,^ 和 $ 只匹配整个字符串的开头和结尾。整个字符串是 “php\nphp”,它不以 “php” 结尾,也不以 “php” 开头 。这个条件为假。

当然,php%0a后面跟着的字符串不固定,可以是任意字符串:

?cmd=php%0aflag
?cmd=php%0afdaf

Web92(类似Web90)

<?phpinclude("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){$num = $_GET['num'];if($num==4476){die("no no no!");}if(intval($num,0)==4476){echo $flag;}else{echo intval($num,0);}
}

这里我们乍一看代码,咦?怎么和Web90的有点眼熟:


其实还是不一样的:

  • 第一个关键点== 是一个弱类型比较运算符。在进行比较之前,PHP 会尝试将两个值转换为相同的类型。
    • 这个比较的漏洞在于,PHP 会将以数字开头的字符串(如 “4476abc”)也转换为数字 4476
  • 第二个关键点if(intval($num, 0)===4476):也是漏洞所在
    • intval($num, 0) 函数会尝试将 $num 转换为一个整数
    • 0x 开头会被识别为十六进制
    • 0b 开头会被识别为二进制
    • 0 开头会被识别为八进制

(第二个解析与Web90一模一样)


漏洞利用方法

你的目标是找到一个值,它经过弱类型比较后不等于 4476(以绕过第一个 if),但经过 intval() 转换后等于 4476。

你可以利用 intval() 的类型转换特性来构造 Payload:

  1. 利用 intval() 的解析规则:
    • intval("4476abc") 结果为 4476
  • 尝试"4476abc" == 4476 在弱类型比较中会转换为 4476 == 4476,因此第一个 if 语句仍然会执行。所以这种方法行不通。
  1. 利用科学计数法或特殊字符串:

    • intval(“4476e1”) 结果为 44760。
    • -intval(“4476.1”) 结果为 4476。
  • 尝试:"4476.1" == 4476 会转换为 4476.1 == 4476,结果为 false。因此,?num=4476.1 可以绕过第一个 if,并满足第二个 if。
  1. 利用十六进制或八进制:
    • intval("0x117c", 0) 结果为 4476(十六进制 117c 转换为十进制是 4476)。
    • "0x117c" == 4476 会转换为 0 == 4476,结果为 false,成功绕过第一个 if。

所以,payload为:

?num=4476.1
?num=4476e1
?num=010574  # 八进制
?num=0x117c  # 十六进制

在这里插入图片描述

总结

好了,从今天开始PHP特性也是开始进行了解。可能有的人会问,昨天不是说做SQL注入的专题嘛,你个骗子。好吧,其实是PHP特性我没了解过,所以想拓展知识面,所以才临时做的决定。骗子就骗子吧~

http://www.dtcms.com/a/362934.html

相关文章:

  • 假设检验(超级详细易懂)
  • 大模型常用的数据类型FP32,BF16,FP16
  • Android --- 搭建JNI框架
  • Nature | 克隆拷贝数多样性影响肺癌生存
  • Ubuntu系统镜像源配置
  • 什么是Z-score标准化
  • 传统企业数字化转型投入巨大却收效甚微,其根源究竟在哪?
  • QSlider 和 QProgressBar 的区别与实践
  • 【高等数学】第十一章 曲线积分与曲面积分——第一节 对弧长的曲线积分
  • 【2025终极对决】Python三大后端框架Django vs FastAPI vs Robyn,你的选择将决定项目生死?
  • 基于SQLite索引的智能图片压缩存储系统设计与实现
  • Postman接口测试工具:高效管理测试用例与环境变量,支持断言验证及团队协作同步
  • Unity学习----【数据持久化】二进制数据(五)--由Excel自动生成数据结构类与二进制文件
  • 向成电子惊艳亮相2025物联网展,携工控主板等系列产品引领智造新风向
  • 深度集成Dify API:企业级RAG知识库管理平台解决方案
  • 一款高效、强大的子域名爬取工具,帮助安全研究者和渗透测试人员快速收集目标域名的子域名信息
  • 【设计模式】三大原则 单一职责原则、开放-封闭原则、依赖倒转原则
  • 【linux】firewall防火墙
  • 社区医疗健康管理系统的设计与实现-(源码+LW+可部署)
  • css3元素倒影效果属性:box-reflect
  • Web2 vs Web3--差异一看就懂
  • 开发中使用——鸿蒙本地存储之收藏功能
  • webpack性能优化指南
  • 汽车制造工厂如何应用力控SCADA实现全方位智能监控与诊断
  • Spring Boot + Spring MVC 项目结构
  • Jenkins 拉取 Git 仓库时报错:there are still refs under ‘refs/remotes/origin/release‘
  • 在 Elasticsearch 中使用用户行为分析:使用 UBI 和 search-ui 创建一个应用程序
  • 【序列晋升】25 Spring Cloud Open Service Broker 如何为云原生「服务市集」架桥铺路?
  • 【JavaScript】前端两种路由模式,Hash路由,History 路由
  • UBUNTU之Onvif开源服务器onvif_srvd:2、测试