PHP program vulnerability causes analysis and prevention methods

  • 2021-01-25 07:18:00
  • OfStack

Abuse include

1. Cause of vulnerability:

Include is the most commonly used function for writing PHP websites and supports relative paths. Many PHP scripts take an input variable directly as an Include parameter, causing arbitrary reference scripts, absolute path leaks, and so on. Look at the following code:

...
$includepage=$_GET["includepage"];
include($includepage);
...

Obviously, we just need to submit different Includepage variables to get the page we want. Submitting a non-existent page can cause an error in the PHP script to reveal the actual absolute path (a solution to this problem is explained in the following article).

2. Vulnerability resolution:

The fix for this vulnerability is as simple as checking whether the page exists before running Include. Or, more strictly, use arrays to specify files that can Include. Look at the following code:


$pagelist=array("test1.php","test2.php","test3.php"); // It is stipulated here that it can be carried out include The file  
if(isset($_GET["includepage"])) // To see if there is $includepage 
{ 
$includepage=$_GET["includepage"]; 
foreach($pagelist as $prepage) 
{ 
if($includepage==$prepage) // Check if the file is in the allowed list  
{ 
include($prepage); 
$checkfind=true; 
break; 
} 
} 
if($checkfind==true){ unset($checkfind); } 
else{ die(" Invalid page reference! "); } 
}

So that's a good way to solve the problem.

require (), require_once(), include_once(), readfile(), readfile(), require(), include_once(), readfile(), etc.

Input variables are not filtered

1. Cause of vulnerability:

This vulnerability appeared earlier in ES46en and caused numerous injection vulnerabilities. But since PHP had little influence at the time, not many people noticed. For PHP, this vulnerability is more of a concern than for ASP, because more PHP scripts use text databases. Of course, there are also problems with injection of SQL statements. A classic example is the database:


$id=$_GET["id"]; 
$query="SELECT * FROM my_table where id='".$id."'"; // Very classic SQL Injection vulnerabilities  
$result=mysql_query($query);

Here it is clear that we can use injection to get the rest of the database. I will not go into details here, and ASP injection 1, you can look at the previous black defense. Then we look at the text database problem:

$text1=$_POST["text1"]; 
$text2=$_POST["text2"]; 
$text3=$_POST["text3"]; 
$fd=fopen("test.php","a"); 
fwrite($fd,"\r\n$text1&line;$text2&line;$text3"); 
fclose($fd);

The text's flaws are arguably more serious. If we insert a small PHP code into the submitted variable, we can make the text database test.php a backdoor to PHP. Even insert upload code so that we can upload a complete ES63en backdoor. Then promote authority, the server is yours.

2. Vulnerability resolution:

The solution to this vulnerability is as simple as strictly filtering all submitted variables. Replace some sensitive characters. We can replace the contents of HTML with the function htmlspecialchars() provided by PHP. Here's an example:


// Constructing a Filter Function  
function flt_tags($text) 
{ 
$badwords=array(" fuck ","fuck"); // Word filtering list  
$text=rtrim($text); 
foreach($badwords as $badword) // This is a word filter  
{ 
if(stristr($text,$badword)==true){ die(" Error: Your submission contains sensitive words. Please do not submit sensitive content. "); } 
} 
$text=htmlspecialchars($text); //HTML replace  
// These two lines replace carriage return with carriage return  
$text=str_replace("\r"," ",$text); 
$text=str_replace("\n","",$text); 
$text=str_replace("&line;"," │ ",$text); // Text database delimiter "&line;" I'm going to replace it with the full Angle " │ " 
$text=preg_replace("/\s{ 2 }/"," ",$text); // Spaces replaced   China Network Management Alliance 
$text=preg_replace("/\t/"," ",$text); // Again, space substitution  
if(get_magic_quotes_gpc()){ $text=stripslashes($text); } // if magic_quotes Open, proceed \' The replacement of  
return $text; 
} 
$text1=$_POST["text1"]; 
$text2=$_POST["text2"]; 
$text3=$_POST["text3"]; 
// Filter all inputs  
$text1=flt_tags($text1); 
$text2=flt_tags($text2); 
$text3=flt_tags($text3); 
$fd=fopen("test.php","a"); 
fwrite($fd,"\r\n$text1&line;$text2&line;$text3"); 
fclose($fd);

After a bit of substitution and filtering, you can safely write data to text or a database.

The administrator's judgment is incomplete

1. Cause of vulnerability:

When we write scripts in PHP, we usually have to deal with administrator permissions. Some scripts only make a "yes" judgment for administrator permissions, and often ignore a "no" judgment. When register_globals is turned on in the PHP configuration file (which is turned off by default after 4.2.0, but many people turn it on for convenience, which is extremely dangerous), it is possible to submit variables impersonating administrators. Let's look at the example code below:


$cookiesign="admincookiesign"; // Determine whether Admin the cookie variable  
$adminsign=$_COOKIE["sign"]; // Get the user's cookie variable  
if($adminsign==$cookiesign) 
{ 
$admin=true; 
} 
if($admin){ echo " We are now in administrator status. "; }

Looks very safe, hehe. Now let's assume that register_globals is open in the PHP configuration file. We submit an address like "test.php? admin=true ". See? Although we do not have the correct Cookie, since register_globals is open, the variable admin we submitted is automatically registered as true. The script also lacks a "no" check, which allows us to get administrator privileges with admin=true. This problem exists on most websites and forums.

2. Vulnerability resolution:

To solve this problem, we simply need to add "no" to the script for the administrator. We still assume that register_globals is open in the PHP configuration file. Look at the code below:


$cookiesign="admincookiesign"; // Determine whether Admin the cookie variable  
$adminsign=$_COOKIE["sign"]; // Get the user's cookie variable  
if($adminsign==$cookiesign) 
{ 
$admin=true; 
} 
else 
{ 
$admin=false; 
} 
if($admin){ echo " We are now in administrator status. "; }

In this case, even if the attacker submits the variable admin=true without correct Cookie, the script will later set $admin to False. So that solves part of the problem. However, because $admin is a variable, it could cause a new crisis if $admin is reassigned in the future due to a bug in other script references. Therefore, we should use constants to store administrator permissions. Use the Define() statement to define an admin constant to record administrator privileges. After this, re-assignment will result in an error. See the following generation code:

$cookiesign="admincookiesign"; // Determine whether Admin the cookie variable  
$adminsign=$_COOKIE["sign"]; // Get the user's cookie variable  
if($adminsign==$cookiesign) 
{ 
define(admin,true); 
} 
else 
{ 
define(admin,false); 
} 
if(admin){ echo " We are now in administrator status. "; }

It's worth noting that we used the Define statement, so instead of the usual $prefix when calling Admin constants, we should use Admin and! admin.

Text database exposure

1. Cause of vulnerability:

As mentioned earlier, text databases do not require any external support due to their great flexibility. In addition, PHP has a strong ability to handle files, so text databases are widely used in PHP scripts. There are even a few good forum programs that use text databases. But there are gains and losses, and the security of text databases is lower than other databases.

2. Vulnerability resolution:

The text database is a normal file that can be downloaded, just like MDB1. So we will protect the text database the same way we protect MDB. Change the suffix name of the text database to.PHP. It is added at line 1 of the database. The text database is then exited as an PHP file at line 1. That is to return an empty page, thus achieving the purpose of protecting the text database.

Error path leak

1. Cause of vulnerability:

When PHP encounters an error, it gives the location, number of lines, and reason of the script that failed, for example:

Notice: Use of undefined constant test - assumed 'test' in D:\interpub\bigfly\test.php on line 3

There are a lot of people who say it's not that big a deal. However, the consequences of revealing the actual path can not be imagined, for some intruders, this information is very important, and in fact there are many servers have this problem.

Some network administrators simply set display_errors in the PHP configuration file to Off to solve this problem, but I think this method is too negative. Sometimes, we do need PHP to return error information for debugging purposes. And you may need to give the user an explanation or even navigate to another page when something goes wrong.

2. Vulnerability resolution:

PHP has provided the custom error handling function set_error_handler() since 4.1.0, but few script writers are aware of it. In the numerous PHP forums, I have seen very few sections dealing with this situation. set_error_handler is used as follows:

string set_error_handler ( callback error_handler [, int error_types])

Now let's filter out the actual path with our custom error handling.


//admin Is the administrator's identity determination, true For administrators.  
// Custom error handlers 1 You have to have these four input variables $errno,$errstr,$errfile,$errline Otherwise, it is invalid.  
function my_error_handler($errno,$errstr,$errfile,$errline) 
{ 
// Filter the actual path if it is not an administrator  
if(!admin) 
{ 
$errfile=str_replace(getcwd(),"",$errfile); 
$errstr=str_replace(getcwd(),"",$errstr); 
} 
switch($errno) 
{ 
case E_ERROR: 
echo "ERROR: [ID $errno] $errstr (Line: $errline of $errfile) 
\n"; 
echo " The program has stopped running, please contact the administrator. "; 
// encounter Error Quit the script when a level error occurs  
exit; 
break; 
case E_WARNING: 
echo "WARNING: [ID $errno] $errstr (Line: $errline of $errfile) 
\n"; 
break; 
default: 
// Don't show Notice With a magnitude of error  
break; 
} 
} 
// Set error handling to my_error_handler function  
set_error_handler("my_error_handler"); 
 ... 

In this way, can solve the contradiction of safety and debugging convenience very well. You can also take care to make the error message look nice to match the style of your site. But two things:

(1) E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING are not handled by this handle, that is, they will be displayed in the original mode. However, these errors are compilation or PHP kernel error, in the normal case will not occur.

(2) set_error_handler() will not be valid if error_reporting () is used. All errors (except the ones mentioned above) are handled by the custom function.
For more information on set_error_handler(), please refer to the official PHP handbook.

POST loopholes

1. Cause of vulnerability:

As mentioned earlier, it is a bad habit to rely on register_globals to register variables. In some message books and forum programs, check more closely how pages are obtained and the time interval between submissions. To prevent flooding posts and external submissions. Let's look at the code of this procedure:


... 
$text1=flt_tags($text1); 
$text2=flt_tags($text2); 
$text3=flt_tags($text3); 
$fd=fopen("data.php","a"); 
fwrite($fd,"\r\n$text1&line;$text2&line;$text3"); 
fclose($fd);

Obviously, if we submit the URL "post.php? text1=testhaha & text2=testhaha & text3 = testhaha ". The data will be written to the file as normal. This program does not detect the source of the variable or how the browser gets the page. If we repeat the submission to this page many times, it will be a flood of use. Now there are also some software to exploit this vulnerability to post advertisements in forums or message books, which is a shameful behavior (my friend's message book was filled with more than 10 pages in a week, but I have no choice).

2. Vulnerability resolution:

Before data processing and saving, first determine how the browser gets the page. Use the $_SERVER["REQUEST_METHOD"] variable to get how the browser gets the page. Check if it is "POST". session is used in the script to record whether the user submitted the data through the normal route, which is to fill in the submitted page. Or use $_SERVER ["HTTP_REFERER"], but this is not recommended. Because some browsers do not set REFERER, some firewalls will block REFERER. In addition, we also need to check the submissions to see if there are duplicates in the database. Taking the message book as an example, Session was used to determine:
In the page to fill in the browsing content, we add:

$_SESSION["allowgbookpost"]=time(); // The time when the registration is completed

In the pages that receive the message data and save it, we also use Session for the following processing before data processing:


if(strtoupper($_SERVER["REQUEST_METHOD"])!= " POST " ){ die(" Error: Do not submit externally. "); } // Check if the page fetch method is POST 
if(!isset($_SESSION["allowgbookpost"]) or (time()-$_SESSION["allowgbookpost"] < 10)){ die(" Error: Do not submit externally. "); } // Check the time when the message was filled in  
if(isset($_SESSION["gbookposttime"]) and (time()-$_SESSION["gbookposttime"] < 120)){ die(" Error: The interval between two messages should not be less than one  2  Minutes. "); } // Check message spacing  
unset($_SESSION["allowgbookpost"]); // The cancellation allowgbookpost Variables to prevent 1 Enter the filling page for submission for several times  
$_SESSION["gbookposttime"]=time(); // Register the time to send messages to prevent flooding or malicious attacks  
...

Data processing and storage


Related articles: