Abuse of include
1. Cause of the vulnerability:
Include is the most commonly used function in writing PHP websites and supports relative paths. There are many PHP scripts that directly use an input variable as an Include parameter, causing vulnerabilities such as arbitrary script reference and absolute path leakage. Look at the following code:
...
$includepage=$_GET["includepage"];
include($includepage);
...
Obviously, we only need to submit different Includepage variables to get the desired page. If you submit a page that does not exist, you can cause the PHP script to error and leak the actual absolute path (the solution to this problem is explained in the following article).
2. Vulnerability resolution:
The solution to this vulnerability is very simple, which is to first determine whether the page exists and then include it. Or more strictly, use an array to specify the files that can be included. Look at the following code:
$pagelist=array("test1.php","test2.php","test3.php"); //This specifies files that can be included
if(isset($_GET["includepage"])) //Determine whether there is $includepage
{
$includepage=$_GET["includepage"];
foreach($pagelist as $prepage)
{
if($includepage==$prepage) //Check whether the file is in the allowed list
{
include($prepage);
$checkfind=true;
break;
}
}
if($checkfind==true){ unset($checkfind); }
else{ die("Invalid reference page!"); }
}
This will solve the problem very well.
Tip: Functions with this problem include: require(), require_once(), include_once(), readfile(), etc. You should also pay attention when writing.
Input variables are not filtered
1. Cause of the vulnerability:
This vulnerability has long appeared in ASP, causing countless injection vulnerabilities at that time. But because PHP had a small influence at the time, not many people could pay attention to this. For PHP, the impact of this vulnerability is greater than that of ASP, because more PHP scripts use text databases. Of course, there is also the problem of SQL statement injection. To give a more classic example, the first is the database:
$id=$_GET["id"];
$query="SELECT * FROM my_table where id='".$id."'"; //A very classic SQL injection vulnerability
$result=mysql_query($query);
It is obvious here that we can use injection to obtain other contents of the database. I won’t describe it in detail here. Just like ASP injection, you can take a look at previous black defenses. Then we look at the problem of text databases:
$text1=$_POST["text1"];
$text2=$_POST["text2"];
$text3=$_POST["text3"];
$fd=fopen("test.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
The vulnerability of the text is arguably even more serious. If we insert a small piece of PHP code into the submitted variable, we can turn this text database test.php into a PHP backdoor. Even inserting the upload code allows us to upload a complete PHP backdoor. Then increase the privileges and the server is yours.
2. Vulnerability resolution:
The solution to this vulnerability is actually very simple, which is to strictly filter all submitted variables. Replace some sensitive characters. We can replace the content of HTML with the help of the htmlspecialchars() function provided by PHP. Here is an example:
//Construct filter function www.knowsky.com
function flt_tags($text)
{
$badwords=array("Fuck you","fuck"); //Word filter list
$text=rtrim($text);
foreach($badwords as $badword) //Filter vocabulary here
{
if(stristr($text,$badword)==true){ die("Error: The content you submitted contains sensitive words, please do not submit sensitive content."); }
}
$text=htmlspecialchars($text); //HTML replacement
//These two lines replace the carriage return with
$text=str_replace("r","
",$text);
$text=str_replace("n","",$text);
$text=str_replace("&line;","│",$text); //Replace the text database separator "&line;" with the full-width "│"
$text=preg_replace("/s{ 2 }/"," ",$text); //space replacement
$text=preg_replace("/t/"," ",$text); // Still replacing spaces
if(get_magic_quotes_gpc()){ $text=stripslashes($text); } //If magic_quotes is turned on, replace '
return $text;
}
$text1=$_POST["text1"];
$text2=$_POST["text2"];
$text3=$_POST["text3"];
//Filter all input
$text1=flt_tags($text1);
$text2=flt_tags($text2);
$text3=flt_tags($text3);
$fd=fopen("test.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
After some replacement and filtering, you can safely write the data to text or a database.
The administrator’s judgment is incomplete
1. Cause of the vulnerability:
We use PHP to write scripts, which usually involve administrator permissions. Some scripts only make a "yes" judgment on administrator permissions, but often ignore the "no" judgment. When register_globals is turned on in the PHP configuration file (it is turned off by default in versions after 4.2.0, but many people turn it on for convenience, which is extremely dangerous behavior), there will be situations where variables are submitted to impersonate administrators. Let's take a look at the example code:
$cookiesign="admincookiesign"; //Determine whether Admin's cookie variable
$adminsign=$_COOKIE["sign"]; //Get the user's cookie variable
if($adminsign==$cookiesign)
{
$admin=true;
}
if($admin){ echo "You are now an administrator."; }
It looks very safe, haha. Now we assume that register_globals is turned on in the PHP configuration file. We submitted such an address "test.php?admin=true", have you seen the result? Although we do not have the correct cookie, because register_globals is turned on, the admin variable we submitted is automatically registered as true. Moreover, the script lacks a "no" judgment, which allows us to successfully obtain administrator permissions through admin=true. This problem exists on most websites and forums.
2. Vulnerability resolution:
To solve this problem, we only need to add a "no" judgment to the administrator in the script. We still assume that register_globals is turned on in the PHP configuration file. Take a look at the code:
$cookiesign="admincookiesign"; //Determine whether Admin's cookie variable
$adminsign=$_COOKIE["sign"]; //Get the user's cookie variable
if($adminsign==$cookiesign)
{
$admin=true;
}
else
{
$admin=false;
}
if($admin){ echo "You are now an administrator."; }
In this way, even if the attacker submits the variable admin=true without the correct cookie, the script will set $admin to False in future judgments. This solves part of the problem. However, since $admin is a variable, if a loophole occurs in other script references in the future and $admin is reassigned, a new crisis will occur. Therefore, we should use constants to store the determination of administrator permissions. Use the Define() statement to define an admin constant to record administrator permissions. If it is reassigned after this, an error will occur, achieving the purpose of protection. Look at the following code:
$cookiesign="admincookiesign"; //Determine whether Admin's cookie variable
$adminsign=$_COOKIE["sign"]; //Get the user's cookie variable
if($adminsign==$cookiesign)
{
define(admin,true);
}
else
{
define(admin,false);
}
if(admin){ echo "You are now in administrator status."; }
It is worth noting that we use the Define statement, so when calling the Admin constant, do not habitually add the variable symbol $ in front, but use Admin and !admin.
Text database exposed
1. Cause of the vulnerability:
As mentioned earlier, due to the great flexibility of text databases, no external support is required. In addition, PHP has very strong file processing capabilities, so text databases are widely used in PHP scripts. There are even several 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 acts as an ordinary file, which can be downloaded, just like an MDB. Therefore, we need to protect text databases in the same way as MDBs. Change the suffix name of the text database to .PHP. and join in the first row of the database. This way the text database will be treated as a PHP file and execution will exit on the first line. That is, an empty page is returned to achieve the purpose of protecting the text database.
Wrong path leaked
1. Cause of the vulnerability:
When PHP encounters an error, it will give the location, line number and reason of the error script, for example:
Notice: Use of undefined constant test - assumed 'test' in D:interpubbigflytest.php on line 3
A lot of people say it's not a big deal. But the consequences of leaking the actual path are unimaginable. For some intruders, this information is very important. In fact, many servers now have this problem.
Some network administrators simply set display_errors in the PHP configuration file to Off to solve the problem, but I think this method is too negative. Sometimes, we really need PHP to return error information for debugging. And when something goes wrong, you may also need to give the user an explanation or even navigate to another page.
2. Vulnerability resolution:
PHP has provided a custom error handling handle function function set_error_handler() since 4.1.0, but few script writers know it. Among the many PHP forums, I have seen only a few handle this situation. The usage of set_error_handler is as follows:
string set_error_handler ( callback error_handler [, int error_types])
Now we use custom error handling to filter out the actual paths.
//Admin is the identity determination of the administrator, true is the administrator.
//The custom error handling function must have these four input variables $errno, $errstr, $errfile, $errline, otherwise it will be invalid.
function my_error_handler($errno,$errstr,$errfile,$errline)
{
//If you are not an administrator, filter the actual path
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.";
//Exit the script when encountering an Error level error
exit;
break;
case E_WARNING:
echo "WARNING: [ID $errno] $errstr (Line: $errline of $errfile)
n";
break;
default:
//Do not display Notice level errors
break;
}
}
//Set error handling to my_error_handler function
set_error_handler("my_error_handler");
…
In this way, the contradiction between security and debugging convenience can be well resolved. And you can also put some thought into making the error message more beautiful to match the style of the website. But note two points:
(1) E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, and E_COMPILE_WARNING will not be processed by this handle, that is, they will be displayed in the most original way. However, these errors are caused by compilation or PHP kernel errors and will not occur under normal circumstances.
(2) After using set_error_handler(), error_reporting () will be invalid. That is, all errors (except the above-mentioned errors) will be handed over to the custom function for processing.
For other information about set_error_handler(), you can refer to the official PHP manual.
POST vulnerability
1. Cause of the vulnerability:
As mentioned before, relying on register_globals to register variables is a bad habit. In some guestbook and forum programs, it is even more necessary to strictly check the method of obtaining pages and the time interval between submissions. To prevent spam posts and external submissions. Let’s take a look at the following code for a guestbook program:
...
$text1=flt_tags($text1);
$text2=flt_tags($text2);
$text3=flt_tags($text3);
$fd=fopen("data.php","a");
fwrite($fd,"rn$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 normally. This program does not detect the source of the variables and how the browser obtained the page. If we submit multiple submissions to this page, it will cause flooding. There are also some softwares that take advantage of this vulnerability to post advertisements on forums or guestbooks, which is a shameful behavior (my friend's guestbook was flooded with more than 10 pages in one week, which was helpless).
2. Vulnerability resolution:
Before processing and saving data, first determine how the browser obtains the page. Use the $_SERVER["REQUEST_METHOD"] variable to obtain the browser's method of obtaining the page. Check if it is "POST". Use session in the script to record whether the user submits data through normal channels (that is, the page where the submission content is filled in). Or use $_SERVER["HTTP_REFERER"] to detect this, but this is not recommended. Because some browsers do not set REFERER, some firewalls will also block REFERER. In addition, we also need to check the submitted content to see if there is duplicate content in the database. Take the guestbook as an example, use Session to make the determination:
In the page where you fill in the browsing content, we add at the front end:
$_SESSION["allowgbookpost"]=time(); //The time when registration is filled in. In the page where message data is accepted and saved, we also use Session to perform the following processing before data processing:
if(strtoupper($_SERVER["REQUEST_METHOD"])!="POST"){ die("Error: Do not submit externally."); } //Check whether the page acquisition method is POST
if(!isset($_SESSION["allowgbookpost"]) or (time()-$_SESSION["allowgbookpost"] < 10)){ die("Error: Do not submit externally."); } //Check the message Time when filling in
if(isset($_SESSION["gbookposttime"]) and (time()-$_SESSION["gbookposttime"] < 120)){ die("Error: The interval between two submissions of messages must not be less than 2 minutes."); } //Check the message interval
unset($_SESSION["allowgbookpost"]); //Unregister the allowgbookpost variable to prevent multiple submissions from entering the fill-in page at one time
$_SESSION["gbookposttime"]=time(); //Register the time to send messages to prevent spamming or malicious attacks
...
Data processing and storage
...
After such multiple reviews, your program will be much safer.