Skip to content

Commit 4035dd7

Browse files
committed
Land rapid7#7796, Improve zip module windows script fallback
2 parents dd9599c + bcbb7b8 commit 4035dd7

File tree

3 files changed

+104
-77
lines changed

3 files changed

+104
-77
lines changed

data/post/zip/zip.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Original technique from http://naterice.com/zip-and-unzip-files-using-the-windows-shell-and-vbscript/
3+
*/
4+
5+
function create_zip(dst)
6+
{
7+
var header = "\x50\x4b\x05\x06" +
8+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
9+
"\x00\x00\x00\x00\x00\x00\x00\x00\x00";
10+
11+
/*
12+
* Trick to write a binary file regardless of the system locale
13+
*/
14+
var outw = new ActiveXObject("ADODB.Stream");
15+
outw.Type = 2;
16+
outw.Open();
17+
outw.WriteText(header);
18+
outw.Position = 0;
19+
20+
var outa = new ActiveXObject("ADODB.Stream");
21+
outa.Type = 2;
22+
outa.Charset = "windows-1252";
23+
outa.Open()
24+
25+
outw.CopyTo(outa);
26+
outa.SaveToFile(dst, 2);
27+
28+
outw.Close();
29+
outa.Close();
30+
}
31+
32+
function basename(path)
33+
{
34+
var a = path.split("\\");
35+
var b = a.slice(-1);
36+
return b[0];
37+
}
38+
39+
function fileeq(a, b)
40+
{
41+
return basename(a).toLowerCase() == basename(b).toLowerCase();
42+
}
43+
44+
function zip(src, dst)
45+
{
46+
var shell = new ActiveXObject('Shell.Application');
47+
var fso = new ActiveXObject('Scripting.FileSystemObject');
48+
49+
/*
50+
* Normalize paths, required by the shell commands
51+
*/
52+
src = fso.GetAbsolutePathName(src);
53+
dst = fso.GetAbsolutePathName(dst);
54+
55+
/*
56+
* Create an empty zip file if necessary
57+
*/
58+
if (!fso.FileExists(dst)) {
59+
create_zip(dst);
60+
}
61+
62+
/*
63+
* Check for duplicates
64+
*/
65+
var zipfile = shell.Namespace(dst);
66+
var files = zipfile.items();
67+
var count = files.Count;
68+
for (var i = 0; i < files.Count; i++) {
69+
if (fileeq(files.Item(i).Name, src)) {
70+
return;
71+
}
72+
}
73+
74+
zipfile.CopyHere(src);
75+
76+
/*
77+
* Wait for completion, but data can be stale on network shares, so we
78+
* abort after 5 seconds.
79+
*/
80+
var max_tries = 50;
81+
while (count == zipfile.items().Count) {
82+
WScript.Sleep(100);
83+
if (max_tries-- == 0) {
84+
return;
85+
}
86+
}
87+
}

data/post/zip/zip.vbs

Lines changed: 0 additions & 62 deletions
This file was deleted.

modules/post/multi/manage/zip.rb

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def initialize(info={})
1616
'Description' => %q{
1717
This module zips a file or a directory. On Linux, it uses the zip command.
1818
On Windows, it will try to use remote target's 7Zip if found. If not, it falls
19-
back to its own VBScript.
19+
back to its Windows Scripting Host.
2020
},
2121
'License' => MSF_LICENSE,
2222
'Author' => [ 'sinn3r' ],
@@ -39,10 +39,12 @@ def has_7zip?
3939
file?("#{get_program_file_path}\\7-Zip\\7z.exe")
4040
end
4141

42-
def vbs(dest, src)
43-
vbs_file = File.read(File.join(Msf::Config.data_directory, "post", "zip", "zip.vbs"))
44-
vbs_file << "WindowsZip \"#{src}\",\"#{dest}\""
45-
vbs_file
42+
def wsh_script(dst, src)
43+
script_file = File.read(File.join(Msf::Config.data_directory, "post", "zip", "zip.js"))
44+
src.gsub!("\\", "\\\\\\")
45+
dst.gsub!("\\", "\\\\\\")
46+
script_file << "zip(\"#{src}\",\"#{dst}\");".force_encoding("UTF-8")
47+
script_file
4648
end
4749

4850
def find_pid_by_user(username)
@@ -62,7 +64,7 @@ def steal_token
6264
pid = find_pid_by_user(current_user)
6365

6466
unless pid
65-
fail_with(Failure::Unknown, "Unable to find a PID for #{current_user} to execute .vbs")
67+
fail_with(Failure::Unknown, "Unable to find a PID for #{current_user} to execute WSH")
6668
end
6769

6870
print_status("Stealing token from PID #{pid} for #{current_user}")
@@ -77,21 +79,21 @@ def steal_token
7779
@token_stolen = true
7880
end
7981

80-
def upload_exec_vbs_zip
82+
def upload_exec_wsh_script_zip
8183
if is_system?
8284
unless session
83-
print_error('Unable to decompress with VBS technique without Meterpreter')
85+
print_error('Unable to compress with WSH technique without Meterpreter')
8486
return
8587
end
8688

8789
steal_token
8890
end
8991

90-
script = vbs(datastore['DESTINATION'], datastore['SOURCE'])
91-
tmp_path = "#{get_env('TEMP')}\\zip.vbs"
92-
print_status("VBS file uploaded to #{tmp_path}")
93-
write_file(tmp_path, script)
94-
cmd_exec("wscript.exe #{tmp_path}")
92+
script = wsh_script(datastore['DESTINATION'], datastore['SOURCE'])
93+
tmp_path = "#{get_env('TEMP')}\\zip.js"
94+
print_status("script file uploaded to #{tmp_path}")
95+
write_file(tmp_path, script.encode("UTF-16LE"))
96+
cmd_exec("cscript.exe #{tmp_path}")
9597
end
9698

9799
def do_7zip
@@ -110,8 +112,8 @@ def windows_zip
110112
print_status("Compressing #{datastore['DESTINATION']} via 7zip")
111113
do_7zip
112114
else
113-
print_status("Compressing #{datastore['DESTINATION']} via VBS")
114-
upload_exec_vbs_zip
115+
print_status("Compressing #{datastore['DESTINATION']} via WSH")
116+
upload_exec_wsh_script_zip
115117
end
116118
end
117119

0 commit comments

Comments
 (0)