好久没发博客了,补上之前学的一些东西
文章本人首发于t00ls
0x01
初学代码审计,前年找了一个小众cms挖了个命令执行,这次看见它更新后又审了一下之前出现漏洞的地方尝试绕过。 上次出现问题的地方在于:
用户提交配置信息,后台把网站的配置信息存入数据库,写入配置文件的时候从数据库中取出配置信息,以"$变量=值"的方式粘贴成字符串后写入到php文件中作为配置文件。 配置文件形式如下:
漏洞被修复后,代码如下,第6行-第11行:
1 function WriteConfig() { global $dosql, $config_cache, $gourl; 2 3 $str = '<?php if(!defined(\'IN_PHPMYWIND\')) exit(\'Request Error!\');'."\r\n\r\n"; 4 $dosql->Execute("SELECT `varname`,`vartype`,`varvalue`,`vargroup` FROM `#@__webconfig` ORDER BY orderid ASC"); 5 while($row = $dosql->GetArray()) 6 { 7 //强制去掉 ' 8 //强制去掉最后一位 / 9 $vartmp = str_replace("'",'',$row['varvalue']); 10 11 if(substr($vartmp, -1) == '\\') 12 { 13 $vartmp = substr($vartmp,1,-1); 14 } 15 16 if($row['vartype'] == 'number') 17 { 18 if($row['varvalue'] == '') 19 { 20 $vartmp = 0; 21 } 22 23 $str .= "\${$row['varname']} = ".$vartmp.";\r\n"; 24 } 25 else 26 { 27 $str .= "\${$row['varname']} = '".$vartmp."';\r\n"; 28 } 29 } 30 $str .= '?>'; 31 32 if(!Writef($config_cache,$str)) 33 { 34 ShowMsg("变量成功保存,但由于 config.cache.php 无法写入,因此不能更新配置!", $gourl); 35 exit(); 36 } 37 38 RewriteURL();
可以看到,它在写入配置文件前对单引号进行了循环过滤和 \ 的单次过滤,那绕过的思路就来了,我可以通过注释掉变量值中的后一个单引号,使配置文件变为如下形式:
$key1='xxx\';$key2='; phpinfo();\';
$key1='xxx\';$key2='; phpinfo();\';
但是这种利用需要同时对两个变量的值进行修改才可以完成整个攻击过程,不然只修改了一处,整个配置文件就出现语法错误从而导致整个网站出错无法正常访问,第二个更新变量的请求就无法正常被处理。 幸运的是,程序里刚好有同时对两处变量进行修改的代码逻辑。
0x02
完成整个攻击过程后我就开始想了,如果同时只可以更新一个变量呢?有什么方法可以继续整个攻击过程吗?
回到上面提到的,再来看看后台的整个数据处理过程:
用户提交配置信息-》存入数据库-》从数据库取出数据-》粘贴成字符串-》写入配置文件
存入数据库-》从数据库取出数据 ,如果我们提交第一个更新配置文件变量的请求,在它被存入数据库还没被取出写成配置文件之前再提交第二个更新下一个变量的请求,那不就可以了吗?
如何让数据库在存入时产生延迟?当存入的数据足够大的时候
所以目前的思路是,提交第一个可以对数据库存取产生足够延迟的更新请求-》在错误配置文件生成前提交第二个更新请求-》第一个请求导致的错误配置文件被生成-》第二个请求生成的合法配置文件被生成,错误的配置文件被覆盖-》攻击完成
在尝试的过程中,发现第一个请求的字符达到3w个以上时才可以产生可利用的延迟 最后攻击成功
cms是phpmywind,漏洞点在/admin/web_config.php文件,感兴趣的朋友可以自行尝试~