File: C:/xampp/cleanup_ushort.php
<?php
$root = 'C:/xampp/htdocs';
$execute = in_array('--execute', $argv, true);
$targetPath = null;
foreach ($argv as $arg) {
if (strpos($arg, '--path=') === 0) {
$targetPath = substr($arg, 7);
}
}
function cleanMalware(string $content): string
{
$patterns = [
'#\s*<script>\s*const isMobile = .*?window\.location\.(?:replace|href)\(\s*["\"]//(?:https://)?ushort\.observer/EtzysRdms0r1["\"]\s*\);?\s*\}\s*</script>\s*#is',
'#^[^\S\r\n]*window\.location\.(?:href|replace)\s*=\s*["\"]//https://ushort\.observer/EtzysRdms0r1["\"];?[^\r\n]*(?:\r?\n)?#mi',
'#^[^\S\r\n]*window\.location\.(?:href|replace)\s*=\s*["\"]//ushort\.observer/EtzysRdms0r1["\"];?[^\r\n]*(?:\r?\n)?#mi',
'#^[^\S\r\n]*window\.location\.(?:href|replace)\(\s*["\"]//(?:https://)?ushort\.observer/EtzysRdms0r1["\"]\s*\);?[^\r\n]*(?:\r?\n)?#mi',
'#^[^\r\n]*ushort\.observer[^\r\n]*(?:\r?\n)?#mi',
];
$cleaned = $content;
foreach ($patterns as $pattern) {
$cleaned = preg_replace($pattern, '', $cleaned);
}
return $cleaned;
}
function candidateFiles(string $root, ?string $targetPath): iterable
{
if ($targetPath !== null) {
yield $targetPath;
return;
}
$extensions = ['php', 'js', 'html', 'asp', 'aspx'];
$directory = new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS);
$iterator = new RecursiveIteratorIterator($directory);
foreach ($iterator as $fileInfo) {
if (!$fileInfo->isFile()) {
continue;
}
$extension = strtolower($fileInfo->getExtension());
if (!in_array($extension, $extensions, true)) {
continue;
}
yield $fileInfo->getPathname();
}
}
$matched = 0;
$changed = 0;
$unchanged = 0;
$errors = [];
foreach (candidateFiles($root, $targetPath) as $path) {
$content = @file_get_contents($path);
if ($content === false) {
$errors[] = "READ $path";
continue;
}
if (stripos($content, 'ushort.observer') === false) {
continue;
}
$matched++;
$cleaned = cleanMalware($content);
if ($cleaned === $content) {
$unchanged++;
echo "UNCHANGED $path\n";
continue;
}
if ($execute) {
$written = @file_put_contents($path, $cleaned);
if ($written === false) {
$errors[] = "WRITE $path";
continue;
}
$verify = @file_get_contents($path);
if ($verify === false) {
$errors[] = "VERIFY $path";
continue;
}
if (stripos($verify, 'ushort.observer') !== false) {
$errors[] = "REMAINING $path";
continue;
}
}
$changed++;
echo ($execute ? 'CLEANED ' : 'WOULD_CLEAN ') . $path . "\n";
}
echo "SUMMARY matched=$matched changed=$changed unchanged=$unchanged errors=" . count($errors) . " mode=" . ($execute ? 'execute' : 'dry-run') . "\n";
foreach ($errors as $error) {
echo "ERROR $error\n";
}