TP-Docs
HTML5 Icon HTML5 Icon HTML5 Icon
TP on Social Media

Recent

Welcome to TinyPortal. Please login or sign up.

Members
  • Total Members: 3,963
  • Latest: BiZaJe
Stats
  • Total Posts: 195,917
  • Total Topics: 21,308
  • Online today: 884
  • Online ever: 8,223 (February 19, 2025, 04:35:35 AM)
Users Online
  • Users: 0
  • Guests: 395
  • Total: 395

[Block] Clean up rogue .htaccess w/random number php files hack

Started by Thurnok, February 21, 2007, 03:14:20 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Thurnok

Have you been hacked?

You just might be.  There are a number of SMF mods out there that might be attributable to some sites getting hacked.  I traced one down that "appears" to have been due to the SMF File Manager mod.  Another user swears he got hacked via some "pretty urls" mod.

If you have some rogue .htaccess files in every subdirectory from your SMF root on down, and each has some random numbered php file (like 345167.php for example), then this will clean up your directories for you.  It won't resolve the original reason you've been hacked.  For that, you will have to do some legwork to figure out what allowed it, and remove the offending mod/hack/whatever from your site.

The reason I wrote this cleanup code: Based on the number of Themes, mods, and other things you have under SMF, there can be literal hundreds of subdirectories under an SMF root.  It can take hours to clean up manually.  This cleanup code looks for .htaccess files in all directories under your SMF root and checks to see if the ErrorDocument 404 redirect is in place.  If you are curious what that means, it basically allows you to launch any HTML file (or in the case of this hack that spawned this cleanup, a PHP file) whenever someone would normally receive the 404 document error from your siite.  That happens when someone requests a page that doesn't exist on your site for example.

Basically, the person that wrote the hack that infects your site, creates a .htaccess file in every directory telling it to launch a php file it creates (which uses random numbers for the filename) whenever a 404 document error is to be sent from your server.  This cleanup removes the offending php file, and the .htaccess file (since the culprit doesn't just modify your original if you had an existing one, he simply overwrote it instead).

This should not affect any normal .htaccess files you have on your site unless you are redirecting 404 documents to a file located in the same directory as your .htaccess file.  You would know if that is the case, since you would have had to do it yourself - its never setup by default like that from any hosting company.

The following code can be put into any php block/article, though I recommend you put it in either an article, or a center block.  And if you put into a center block, make that block only available to admins.  Then disable it after you run through it once, so you don't run on your site every time you view the page.  Not that it will hurt anything, though it does take time to iterate through all your directories so there is a noticable slow down before getting the page viewed.  It only needs to run once, so putting it in an article (that DOES NOT show on the frontpage) is better, then you can simply run it from there any time you think you have been infected.  For example, if you create a php article and put the code in that article, and that article number is 24, then you can either create a link to the article or simply enter a direct link to it in your browser URL bar (example: http://www.mydomain.com/index.php?page=24).  The code already contains logic to only run if an admin is running it.

The code displays some status info as well so you know what it did.  Here's the code:

global $context;

if ($context['user']['is_admin']){

if (!function_exists("stripos")){
function stripos($haystack, $needle, $offset = 0){
return strpos(strtolower($haystack), strtolower($needle), $offset);
}
}

function dirTree($dir, &$arrDir) {
if (substr($dir, strlen($dir) - 1) != '/')
$dir .= '/';
$arrDir[] = $dir;
$d = dir($dir);
while (false !== ($entry = $d->read())) {
if($entry != '.' && $entry != '..' && is_dir($dir.$entry))
dirTree($dir.$entry.'/', $arrDir);
}
$d->close();
return;
}

global $boarddir;
$arrDir = array();
// root dir to search from - use SMF $boarddir
$dir = $boarddir;
// fill our arrDir array with a directory tree list - all dirs under boarddir
dirTree($dir, $arrDir);

$dirs_affected = 0;
$htfound = 0;
$hdr = "Hacked .htaccess files found!<br />Deleting following files:<br /><br />";
foreach ($arrDir as $key => $value){
// search each directory for the .htaccess file
$hfile = $value.'.htaccess';
$rogue_exists = false;
if (file_exists($hfile)){
$htfound++;
$handle = fopen($hfile, "r");
// read .htaccess file and see if it is a rogue one
$contents = fread($handle, filesize($hfile));
$pos = stripos($contents, "ErrorDocument 404 ");
if ($pos !== false){
// find our path, after it should be file we are looking for
// set the relative path that will be found in the .htaccess file
$path = str_replace($boarddir, "", $value);
$pos = stripos($contents, $path, $pos);
if ($pos !== false){
// this is an infected htaccess file, add to count
$dirs_affected++;
$rogue_exists = true;
// get line ending
$lepos = stripos($contents, "\r\n", $pos);
if ($lepos === false){
$lepos = stripos($contents, "\n", $pos);
if ($lepos === false){
$lepos = strlen($contents);
}
}
// find rogue file
$spos = $pos + strlen($path);
$rogue_file = substr($contents, $spos, $lepos - $spos);
}
}
fclose($handle);
if ($rogue_exists){
// delete the rogue file, and the hacked .htaccess file
echo $value.".htaccess ";
if (@unlink($value.".htaccess")){
echo "&nbsp;&nbsp;&nbsp; (Success)<br />";
} else {
echo "&nbsp;&nbsp;&nbsp; (<b>FAILED!</b>)<br />";
}
echo $value.$rogue_file;
if (@unlink($value.$rogue_file)){
echo "&nbsp;&nbsp;&nbsp; (Success)<br />";
} else {
echo "&nbsp;&nbsp;&nbsp; (<b>FAILED!</b>)<br />";
}
}
}
}
echo "<hr />Total .htaccess files found = ".$htfound."<br />";
echo "Number of directories affected (rouge .htaccess files) = ".$dirs_affected."<br />";

}


akulion


G6Cad

Again, thank you Thurnok, and thank you for knowing those things to help us that doesent have a clue.

technodragon73


Thurnok

Modified the code in the first message.

If you (or the php program actually) do not have sufficient rights (wrong owner, etc.) to remove the file, the error was posted to the SMF error log.  I changed it to skip that, since the code displays for you those that were not successful (Failed to delete).

RoarinRow


SMF 2.0 RC3
TP 1.0 beta 5-1
Wordpress 3.0

Sin69

Wow, brilliant code Thurnok,

I'm absolutely amazed by what can be achieved within a block!


rctxtreme

Potentially this can be used outside of SMF, although there would obviously need some minor changes in the code...

pvcblue

GREAT JOB Thurnok!! I put this isn a php article and happily it said no hacks!!  :laugh:

This website is proudly hosted on Crocweb Cloud Website Hosting.