1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-03-18 15:14:10 +01:00

Land #263, remove read-only attributes on delete for Windows platforms

Merge branch 'land-263' into upstream-master
This commit is contained in:
bwatters 2018-01-23 07:08:29 -06:00
commit 53ca1a608d
No known key found for this signature in database
GPG Key ID: ECC0F0A52E65F268
3 changed files with 47 additions and 33 deletions

View File

@ -5,7 +5,7 @@
BOOL DeleteFolderWR(LPCWSTR szPath) BOOL DeleteFolderWR(LPCWSTR szPath)
{ {
WIN32_FIND_DATAW FindFileData; WIN32_FIND_DATAW findFileData;
HANDLE hFind = INVALID_HANDLE_VALUE; HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError, dwAttrs; DWORD dwError, dwAttrs;
BOOL bRes; BOOL bRes;
@ -51,7 +51,7 @@ BOOL DeleteFolderWR(LPCWSTR szPath)
else else
wsprintfW(cPath, L"%s\\*.*", szPath); wsprintfW(cPath, L"%s\\*.*", szPath);
hFind = FindFirstFileW(cPath, &FindFileData); hFind = FindFirstFileW(cPath, &findFileData);
if (hFind == INVALID_HANDLE_VALUE) if (hFind == INVALID_HANDLE_VALUE)
return FALSE; return FALSE;
@ -62,22 +62,22 @@ BOOL DeleteFolderWR(LPCWSTR szPath)
do do
{ {
if (lstrcmpiW(FindFileData.cFileName, L".") == 0 || lstrcmpiW(FindFileData.cFileName, L"..") == 0) if (lstrcmpiW(findFileData.cFileName, L".") == 0 || lstrcmpiW(findFileData.cFileName, L"..") == 0)
continue; continue;
if (lstrlenW(cPath) + lstrlenW(L"\\") + lstrlenW(FindFileData.cFileName) + 1 > MAX_PATH) if (lstrlenW(cPath) + lstrlenW(L"\\") + lstrlenW(findFileData.cFileName) + 1 > MAX_PATH)
continue; continue;
wsprintfW(cCurrentFile, L"%s\\%s", cPath, FindFileData.cFileName); wsprintfW(cCurrentFile, L"%s\\%s", cPath, findFileData.cFileName);
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{ {
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
{ {
FindFileData.dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY; findFileData.dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
SetFileAttributesW(cCurrentFile, FindFileData.dwFileAttributes); SetFileAttributesW(cCurrentFile, findFileData.dwFileAttributes);
} }
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
bRes = RemoveDirectoryW(cCurrentFile); bRes = RemoveDirectoryW(cCurrentFile);
else else
bRes = DeleteFolderWR(cCurrentFile); bRes = DeleteFolderWR(cCurrentFile);
@ -85,13 +85,13 @@ BOOL DeleteFolderWR(LPCWSTR szPath)
else else
{ {
if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) || if ((findFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ||
(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) (findFileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
SetFileAttributesW(cCurrentFile, FILE_ATTRIBUTE_NORMAL); SetFileAttributesW(cCurrentFile, FILE_ATTRIBUTE_NORMAL);
DeleteFileW(cCurrentFile); DeleteFileW(cCurrentFile);
} }
} while (FindNextFileW(hFind, &FindFileData)); } while (FindNextFileW(hFind, &findFileData));
dwError = GetLastError(); dwError = GetLastError();
@ -268,6 +268,12 @@ int fs_delete_file(const char *path)
goto out; goto out;
} }
DWORD attrs = GetFileAttributesW(path_w);
if ((attrs != INVALID_FILE_ATTRIBUTES) && (attrs & FILE_ATTRIBUTE_READONLY)) {
attrs &= ~FILE_ATTRIBUTE_READONLY;
SetFileAttributesW(path_w, attrs);
}
if (DeleteFileW(path_w) == 0) { if (DeleteFileW(path_w) == 0) {
rc = GetLastError(); rc = GetLastError();
} }

View File

@ -278,8 +278,8 @@ function array_prepend($array, $string, $deep=false) {
## END Search Helpers ## END Search Helpers
if (!function_exists('cononicalize_path')) { if (!function_exists('canonicalize_path')) {
function cononicalize_path($path) { function canonicalize_path($path) {
$path = str_replace(array("/", "\\"), DIRECTORY_SEPARATOR, $path); $path = str_replace(array("/", "\\"), DIRECTORY_SEPARATOR, $path);
return $path; return $path;
} }
@ -288,7 +288,7 @@ function cononicalize_path($path) {
# #
# Need to nail down what this should actually do. Ruby's File.expand_path is # Need to nail down what this should actually do. Ruby's File.expand_path is
# for cononicalizing a path (e.g., removing /./ and ../) and expanding "~" into # for canonicalizing a path (e.g., removing /./ and ../) and expanding "~" into
# a path to the current user's homedir. In contrast, Meterpreter has # a path to the current user's homedir. In contrast, Meterpreter has
# traditionally used this to get environment variables from the server. # traditionally used this to get environment variables from the server.
# #
@ -336,7 +336,7 @@ register_command('stdapi_fs_delete_dir');
function stdapi_fs_delete_dir($req, &$pkt) { function stdapi_fs_delete_dir($req, &$pkt) {
my_print("doing rmdir"); my_print("doing rmdir");
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH); $path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
$ret = @rmdir(cononicalize_path($path_tlv['value'])); $ret = @rmdir(canonicalize_path($path_tlv['value']));
return $ret ? ERROR_SUCCESS : ERROR_FAILURE; return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
} }
} }
@ -346,7 +346,7 @@ register_command('stdapi_fs_mkdir');
function stdapi_fs_mkdir($req, &$pkt) { function stdapi_fs_mkdir($req, &$pkt) {
my_print("doing mkdir"); my_print("doing mkdir");
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH); $path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
$ret = @mkdir(cononicalize_path($path_tlv['value'])); $ret = @mkdir(canonicalize_path($path_tlv['value']));
return $ret ? ERROR_SUCCESS : ERROR_FAILURE; return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
} }
} }
@ -357,7 +357,7 @@ register_command('stdapi_fs_chdir');
function stdapi_fs_chdir($req, &$pkt) { function stdapi_fs_chdir($req, &$pkt) {
my_print("doing chdir"); my_print("doing chdir");
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH); $path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
$ret = @chdir(cononicalize_path($path_tlv['value'])); $ret = @chdir(canonicalize_path($path_tlv['value']));
return $ret ? ERROR_SUCCESS : ERROR_FAILURE; return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
} }
} }
@ -368,7 +368,11 @@ register_command('stdapi_fs_delete');
function stdapi_fs_delete($req, &$pkt) { function stdapi_fs_delete($req, &$pkt) {
my_print("doing delete"); my_print("doing delete");
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_NAME); $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_NAME);
$ret = @unlink(cononicalize_path($path_tlv['value'])); $path = canonicalize_path($path_tlv['value']);
if (is_windows()) {
exec("attrib.exe -r ".$path);
}
$ret = @unlink($path)
return $ret ? ERROR_SUCCESS : ERROR_FAILURE; return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
} }
} }
@ -380,8 +384,8 @@ function stdapi_fs_file_move($req, &$pkt) {
my_print("doing mv"); my_print("doing mv");
$old_file_tlv = packet_get_tlv($req, TLV_TYPE_FILE_NAME); $old_file_tlv = packet_get_tlv($req, TLV_TYPE_FILE_NAME);
$new_file_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH); $new_file_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
$old_file = cononicalize_path($old_file_tlv['value']); $old_file = canonicalize_path($old_file_tlv['value']);
$new_file = cononicalize_path($new_file_tlv['value']); $new_file = canonicalize_path($new_file_tlv['value']);
$ret = @rename($old_file, $new_file); $ret = @rename($old_file, $new_file);
return $ret ? ERROR_SUCCESS : ERROR_FAILURE; return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
} }
@ -394,8 +398,8 @@ function stdapi_fs_file_copy($req, &$pkt) {
my_print("doing cp"); my_print("doing cp");
$old_file_tlv = packet_get_tlv($req, TLV_TYPE_FILE_NAME); $old_file_tlv = packet_get_tlv($req, TLV_TYPE_FILE_NAME);
$new_file_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH); $new_file_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
$old_file = cononicalize_path($old_file_tlv['value']); $old_file = canonicalize_path($old_file_tlv['value']);
$new_file = cononicalize_path($new_file_tlv['value']); $new_file = canonicalize_path($new_file_tlv['value']);
$ret = @copy($old_file, $new_file); $ret = @copy($old_file, $new_file);
return $ret ? ERROR_SUCCESS : ERROR_FAILURE; return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
} }
@ -418,7 +422,7 @@ register_command('stdapi_fs_ls');
function stdapi_fs_ls($req, &$pkt) { function stdapi_fs_ls($req, &$pkt) {
my_print("doing ls"); my_print("doing ls");
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH); $path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
$path = cononicalize_path($path_tlv['value']); $path = canonicalize_path($path_tlv['value']);
$dir_handle = @opendir($path); $dir_handle = @opendir($path);
if ($dir_handle) { if ($dir_handle) {
@ -467,7 +471,7 @@ register_command('stdapi_fs_stat');
function stdapi_fs_stat($req, &$pkt) { function stdapi_fs_stat($req, &$pkt) {
my_print("doing stat"); my_print("doing stat");
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH); $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
$path = cononicalize_path($path_tlv['value']); $path = canonicalize_path($path_tlv['value']);
$st = stat($path); $st = stat($path);
if ($st) { if ($st) {
@ -500,7 +504,7 @@ register_command('stdapi_fs_delete_file');
function stdapi_fs_delete_file($req, &$pkt) { function stdapi_fs_delete_file($req, &$pkt) {
my_print("doing delete"); my_print("doing delete");
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH); $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
$path = cononicalize_path($path_tlv['value']); $path = canonicalize_path($path_tlv['value']);
if ($path && is_file($path)) { if ($path && is_file($path)) {
$worked = @unlink($path); $worked = @unlink($path);
@ -517,9 +521,9 @@ function stdapi_fs_search($req, &$pkt) {
my_print("doing search"); my_print("doing search");
$root_tlv = packet_get_tlv($req, TLV_TYPE_SEARCH_ROOT); $root_tlv = packet_get_tlv($req, TLV_TYPE_SEARCH_ROOT);
$root = cononicalize_path($root_tlv['value']); $root = canonicalize_path($root_tlv['value']);
$glob_tlv = packet_get_tlv($req, TLV_TYPE_SEARCH_GLOB); $glob_tlv = packet_get_tlv($req, TLV_TYPE_SEARCH_GLOB);
$glob = cononicalize_path($glob_tlv['value']); $glob = canonicalize_path($glob_tlv['value']);
$recurse_tlv = packet_get_tlv($req, TLV_TYPE_SEARCH_RECURSE); $recurse_tlv = packet_get_tlv($req, TLV_TYPE_SEARCH_RECURSE);
$recurse = $recurse_tlv['value']; $recurse = $recurse_tlv['value'];
@ -555,7 +559,7 @@ if (!function_exists('stdapi_fs_md5')) {
register_command("stdapi_fs_md5"); register_command("stdapi_fs_md5");
function stdapi_fs_md5($req, &$pkt) { function stdapi_fs_md5($req, &$pkt) {
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH); $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
$path = cononicalize_path($path_tlv['value']); $path = canonicalize_path($path_tlv['value']);
if (is_callable("md5_file")) { if (is_callable("md5_file")) {
$md5 = md5_file($path); $md5 = md5_file($path);
@ -573,7 +577,7 @@ if (!function_exists('stdapi_fs_sha1')) {
register_command("stdapi_fs_sha1"); register_command("stdapi_fs_sha1");
function stdapi_fs_sha1($req, &$pkt) { function stdapi_fs_sha1($req, &$pkt) {
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH); $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
$path = cononicalize_path($path_tlv['value']); $path = canonicalize_path($path_tlv['value']);
if (is_callable("sha1_file")) { if (is_callable("sha1_file")) {
$sha1 = sha1_file($path); $sha1 = sha1_file($path);

View File

@ -1220,8 +1220,10 @@ def stdapi_fs_chdir(request, response):
@register_function @register_function
def stdapi_fs_delete(request, response): def stdapi_fs_delete(request, response):
file_path = packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value'] file_path = unicode(packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value'])
os.unlink(unicode(file_path)) if has_windll:
subprocess.call(unicode("attrib.exe -r ") + file_path)
os.unlink(file_path)
return ERROR_SUCCESS, response return ERROR_SUCCESS, response
@register_function @register_function
@ -1238,6 +1240,8 @@ def stdapi_fs_delete_dir(request, response):
@register_function @register_function
def stdapi_fs_delete_file(request, response): def stdapi_fs_delete_file(request, response):
file_path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value'] file_path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
if has_windll:
subprocess.call(unicode("attrib.exe -r ") + file_path)
os.unlink(unicode(file_path)) os.unlink(unicode(file_path))
return ERROR_SUCCESS, response return ERROR_SUCCESS, response