前言
上一篇文章中, 对命令注入进行了简单的分析, 有兴趣的可以去看一看, 文章地址 https://www.cnblogs.com/lxfweb/p/12828754.html, 今天这篇文章以 DVWA 的 Command Injection(命令注入) 模块为例进行演示与分析, 本地搭建 DVWA 程序可以看这篇文章 https://www.cnblogs.com/lxfweb/p/12678463.html, 通过对 DVWA 不同等级的代码分析, 看看它是如何做的防御.
漏洞利用与分析
low 级别 (低级别)
首先查看 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
- echo "<pre>{$cmd}</pre>";
- }
- ?>
可以发现上面的代码, 用了 stristr(),php_uname(), 函数, 这是用来判断当前的系统是否是 Windows, 因为 Windows 和 Linux 下的 ping 命令执行参数是不同的. 接下来是用 shell_exec 函数来执行 ping 命令, 并将结果输出. 我们发现 low 级别的代码, 对用户的输入没有做任何的过滤. 存在很大的安全隐患. 例如使用管道符 "|" 查看当前端口, 输入下列内容
127.0.0.1|netstat -ano
结果如下图
这里不止可以使用 "|", 在 DOS 下允许同时执行多条命令的符号主要有以下几个
& 连接符 执行完第一个命令, 执行第二个命令
&& 只有上一个执行成功, 才执行下一个命令
| 管道符 让前一命令的输出当做后一命令的输入, 就是说前面命令的结果当做一个参数传递给后面命令处理
|| 只有上一个执行失败, 才执行下一个命令
可以用连接符直接接 net user zhangsan 123/add 创建用户 接着连接提权命令 net localgroup administrators zhangsan /add 拿下整个服务器
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>";
- }
- ?>
我们发现, 中级的代码, 对参数做了一点过滤, 把 && 和; 删除, 相当于黑名单的形式, 在 Linux 中; 也可以起连接作用, 依次执行多个命令. 我们可以尝试 | || & &;& , 这里以 || 举例,|| 前面报错, 后面执行咱们构造的命令, 结果如下图
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>";
- }
- ?>
高级别的代码对黑名单进行了进一步完善, 好像过滤了所有危险字符, 仔细观察黑名单里 "|" 管道符, 后面有一个空格 "|" 这样可以尝试 "|" 发现成功绕过, 结果如下图
Impossible(无漏洞)
查看核心代码
- if( isset( $_POST[ 'Submit' ] ) ) {
- // Check Anti-CSRF token
- checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
- // Get input
- $target = $_REQUEST[ 'ip' ];
- $target = stripslashes( $target );
- // Split the IP into 4 octects
- $octet = explode( ".", $target );
- // Check IF each octet is an integer
- if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
- // If all 4 octets are int's put the IP back together.
- $target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];
- // 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>";
- }
- else {
- // Ops. Let the user name theres a mistake
- echo '<pre>ERROR: You have entered an invalid IP.</pre>';
- }
- }
- // Generate Anti-CSRF token
- generateSessionToken();
- ?>
通过查看 Impossible 级别的代码加入了 Anti-CSRF token, 并且采用白名单的方式, 对参数 ip 进行了严格的限制, 只接受 X.X.X.X(X 只能为数字), 因此不存在命令执行漏洞.
来源: https://www.cnblogs.com/lxfweb/p/12831417.html