php 网站渗透,PHP网站渗透中的奇技淫巧:检查相等时的漏洞

本文探讨了PHP中的弱类型比较问题,特别是`==`运算符可能导致的安全漏洞。当字符串被转换为数值时,特定的字符串组合可能会产生意外的等值比较结果。例如,`'12a'==12`会返回`true`,这在某些条件下可能导致代码注入。文章通过一个CTF题目为例,展示了如何利用这种特性绕过安全检查。同时,还介绍了`md5()`函数的输出格式,指出在进行哈希值比较时应使用`===`以避免此类问题。
摘要由CSDN通过智能技术生成

PHP是现在网站中最为常用的后端语言之一,是一种类型系统 动态、弱类型的面向对象式编程语言。可以嵌入HTML文本中,是目前最流行的web后端语言之一,并且可以和Web Server 如apache和nginx方便的融合。目前,已经占据了服务端市场的极大占有量。

但是,弱类型,一些方便的特性由于新手程序员的不当使用,造成了一些漏洞,这篇文章就来介绍一下一些渗透中可以用的特性。

上面都是废话,下面我们进入正题

1.弱类型的比较==导致的漏洞

注:这些漏洞适用于所有版本的php

先来复习一下基本的语法:php中有如下两种比较符号:两个等号和三个等号(这一点和Javascript)有些类似

$a==$b

$a===$b

我们来一下php官方手册的说法

$a == $b 等于 TRUE,如果类型转换后 $a 等于 $b。$a === $b 全等 TRUE,如果 $a 等于 $b,并且它们的类型也相同。

明确的看到,两个等于号的等于会在比较的时候进行类型转换的比较。

如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换为数值并且比较按照数值来进行。此规则也适用于 switch 语句。当用 === 或 !== 进行比较时则不进行类型转换,因为此时类型和数值都要比对.

明确的写出了 如果一个数值和一个字符串比较,那么会将字符串转换为数值(而不是相反,将数值转化为字符串)

然而,php是如何将一个字符串转化为数值的呢,我们继续查看php手册

当一个字符串被当作一个数值来取值,其结果和类型如下:如果该字符串没有包含 ‘.’,’e’ 或 ‘E’ 并且其数字值在整型的范围之内(由 PHP_INT_MAX 所定义),该字符串将被当成 integer 来取值。其它所有情况下都被作为 float 来取值。该字符串的开始部分决定了它的值。如果该字符串以合法的数值开始,则使用该数值。否则其值为 0(零)。合法数值由可选的正负号,后面跟着一个或多个数字(可能有小数点),再跟着可选的指数部分。指数部分由 ‘e’ 或 ‘E’ 后面跟着一个或多个数字构成。

这是官方手册上面的几个例子

1 + "10.5";                // $foo is float (11.5)

$foo = 1 + "-1.3e3";              // $foo is float (-1299)

$foo = 1 + "bob-1.3e3";           // $foo is integer (1)

$foo = 1 + "bob3";                // $foo is integer (1)

$foo = 1 + "10 Small Pigs";       // $foo is integer (11)

$foo = 4 + "10.2 Little Piggies"; // $foo is float (14.2)

$foo = "10.0 pigs " + 1;          // $foo is float (11)

$foo = "10.0 pigs " + 1.0;        // $foo is float (11)

?>

我们大概可以总结出如下的规则:当一个字符串被转换为数值时

如果一个字符串为 “合法数字+e+合法数字”类型,将会解释为科学计数法的浮点数

如果一个字符串为 “合法数字+ 不可解释为合法数字的字符串”类型,将会被转换为该合法数字的值,后面的字符串将会被丢弃

如果一个字符串为“不可解释为合法数字的字符串+任意”类型,则被转换为0! 为0…为0

'a'==0 // true

'12a'==12 //true

'1'==1 //true

'1aaaa55sss66'==1 //true

当然,上面的那些等式对于===都是false的,原本一些应该用===的地方误用了==,导致了可以注入的地方。

示例代码 1:利用转为数字后相等的漏洞

if (isset($_GET['v1']) && isset($_GET['v2'])) {

$logined = true;

$v1 = $_GET['v1'];

$v2 = $_GET['v2'];

if (!ctype_alpha($v1)) {$logined = false;}

if (!is_numeric($v2) ) {$logined = false;}

if (md5($v1) != md5($v2)) {$logined = false;}

if ($logined){

// continuue to do other things

} else {

echo "login failed"

}

}

?

这是一个ctf的题目,非常有趣,可以看到,要求给出两字符串,一个是纯数字型,一个只能出现字符,使两个的md5哈希值相等,然而这种强碰撞在密码学上都是无法做到的。

但是我们看到,最终比较两者的哈希的时候,使用的是等于 而不是 全等于 ,因此可以利用一下这个漏洞

再回头看一 md5() 函数

string md5 ( string $str [, bool $raw_output = false ] )

str原始字符串。raw_output如果可选的 raw_output 被设置为 TRUE,那么 MD5 报文摘要将以16字节长度的原始二进制格式返回。

可以知道,第二个参数为true的时候,显示16位的结果,而为false和没有第二个参数时,为32位的16进制码(16位的结果是把32位的作为ASCII码进行解析)

16进制的数据中是含有e的,可以构建使得两个数字比较的,这里有一个现成的例子:

md5('240610708')

//0e462097431906509019562988736854.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值