zoukankan      html  css  js  c++  java
  • MongoDb学习

    快速了解MongoDB

    基础概念

      MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于JSON对象。字段值可以包含其他文档,数组及文档数组。
    image.png
    image.png

    常用MongoDB语句分析

      通常使用findone(),find().pretty()find()函数来对文档进行查询,find() 方法以非结构化的方式来显示所有文档,加上pretty()方法以格式化的方式来显示所有文档(实际上就是显示起来更易读),findone()只返回一个文档。MongoDB 中存储的文档必须有一个_id键,这个键的值可以是任何类型的,默认是个 ObjectId 对象,可以把它当作关系型数据库中的唯一主键吧。

    语句分析

      首先要知道几个比较常用的比较运算符,对于这种带$的标识符,在MongoDB中我们都可以把它们当作是一种表达式,把他们放在花括号{}中就行。
    image.png
      下面就简单看看MongoDB PHP扩展与Mongodb shell下以及相应Mysql的相应查询语句对比,这样能更快让我们学会和理解MongoDB的相关语法。

    <?php
    echo extension_loaded("mongo") ? "loaded
    " : "not loaded
    ";
    $m = new MongoClient("mongodb://localhost:27017"); // 连接
    $db = $m->test->tr1ple;
    $cursor = $db->find();
    foreach ($cursor as $document) {
        var_dump($document). "
    ";
    }
    ?>
    

      内置数据如下
    image.png
      例1.
      MongoDB shell:db.tr1ple.find({num:{$gt:2}})
    image.png
      MongoDB php:$db->find(['num'=> ['$gt'=>2]]);
    image.png
      Mysql: select * from tr1ple where num>2
      例2.
      对于OR和AND这种运算符我们既可以对单个变量进行多个条件限制,也可以针对多个变量进行条件限制
      and->单个变量多条件限制:
      MongoDB shell:db.tr1ple.find({'num':{"$gt":2,"$lt":4}})
    image.png
      MongoDB php:$db->find(['num'=>['$gt'=>2,'$lt'=>4]]);
    image.png
      Mysql: select * from tr1ple where num>2 and num <4
      例3.
      and->多个变量条件限制:
      MongoDB shell:db.tr1ple.find({'num':{"$gt":2},'name':'test_3'})
    image.png
      MongoDB php:$db->find(["num"=>['$gt'=>2],"name"=>"test_3"])
    image.png
      Mysql: select * from tr1ple where num>2 and name="test_3"
      例4.
      而对于or连接,语法可能稍有不同:
      MongoDB shell:db.tr1ple.find({$or:[{"name":"test_1"},{"name":"test_2"}]})
    image.png
      MongoDB php:$db->find(['$or'=>[["name"=>"test_1"],["name"=>"test_2"]]]);
    image.png
      Mysql: select * from tr1ple where name=“test_1“ or name = "test_2"
      例5.
      当然也可以将and和or结合进行查询:
      MongoDB shell:db.tr1ple.find({"num":{"$gt":1},$or:[{"name":"test_1"},{"name":"test_2"}]})
      MongoDB php:$db->find(["num"=>['$gt'=>1],'$or'=>[["name"=>"test_1"],["name"=>"test_2"]]]);
      Mysql: select * from tr1ple where num>1 and (name="test_1" or name="test_2")
      最后还要再了解一点关于MongoDB的管道的概念,同样我们可以类比Linux上的管道概念来进行理解
      MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果,有点类似sql语句中的count(*)。MongoDB的管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的,以下是几个管道相关操作中的表达式:
      $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档,可以把它当作指定域,因为默认find()函数将范围集合中所有的域的数据(ps:这个域前面表里说过了可以把它当作SQL里面的字段来理解)。
      $limit:用来限制MongoDB聚合管道返回的文档数。
      $group:将集合中的文档分组,可用于统计结果。
      $sort:将输入文档排序后输出。(使用1和-1来指定排序的方式,其中1为升序排列,而-1是用于降序排列)

    NopeSQL解题

      题目环境还没关,地址:http://173.199.118.226/index.php?
      web题,拿到题,先扫目录,有.git泄露,githack走起,就能得到index.php的源码了。
    image.png
    image.png
      接下来就是代码审计,其中登陆验证的逻辑在这里
    image.png
    image.png
      将post的用户名和密码直接带入find0ne()函数进行查找,所以明显在这里存在注入,我们可以看到query为'{"username": "'.$username.'", "password": "'.$password.'"}',因此我们可以很容易闭合它,用户名随意,比如username=123password=111","password":{"$ne":"tr1ple"},"username":"admin,这里相当于我们既闭合了后面的双引号,又对username和password的值进行了覆盖,那么findOne最终相当于执行:
    db.news.findOne({"username":"123","password:"111",username":"admin","password":{"$ne":"tr1ple"}}),这样自然会返回admin的那条记录(ps:这里$ne表达式即不等于)。
      在本地测试两次赋值查询结果如下图:
    image.png
      index.php未认证情况下显示的只有news这个集合的文档title域
    image.png
      所以注入password进行绕过
    image.png
    image.png
      登陆成功,接下来有两个选项供选择,根据题目意思也就是根据我们所选择的域用来进行分组,根据题目逻辑,也就是根据我们提供的filter参数来进行分组:
    image.png
    image.png
    image.png
      可以明显看到当选择$category当做分组标准时,可以看到输出中出现了flags,那么很明显以$category域为分组标准是接下来解题的目标,回去看看这里进行查询的逻辑:
    image.png
      这里就用到了刚才我们上面所说的MongoDB聚合管道,这里可以理解成先用$pipeline所定义的条件过滤一次,然后再用$filter所定义的条件过滤一次,最终得到数据。
      先看看$pipeline的查询逻辑,可以理解为类比SQL:
      select category,count(*) from news group by category desc limit5
    image.png
      然后再和$filter定义的条件进行过滤,这里用到了$project,也就是我们通过它可以修改输入文档的结构,我们的可控变量$filter也在这里,接下来用php的array_merge()函数首先将数组$pipeline和数组$filter进行合并,然后使用mongodb的聚合函数aggregate来获得最终的数据集合。而重点是这里的category实际上是可以替换的,而替换的内容又是我们可以控制的,而通过$project我们可以修改返回的域,这里主键可以是前面说的category,也可以是publicity,当然也可以是我们想要恶意构造的值,若为publicity,即为:
      select publicity,count(*) from news group by publicity desc limit5
    image.png
      当然因为$filter是可以控制的,并且我们知道category里面有flags这个键,并且之前通过$news['title'],我们知道集合news里面的文档存在域title,那么flags目录对应的文档也有title域,所以我们直接通过if判断来得到当前category为flags时的title,这里要用到if:then:else:判断块,还是看官方文档吧(https://docs.mongodb.com/manual/reference/operator/aggregation/project/index.html), 其中有解释对$project的用法,有个例子里面就有对if的使用:
    image.png
      而通过mongodb的官方对$project的例子,我们可以看到可以使用$cond来进行if条件判断,此时我们在filter变量处注入一个$cond判断条件,参考文档中例子的写法,我们要注入的filter肯定是一个数组,其只有一个键$cond,而键值为由if、then、else构成的一个数组,并且if条件对应的键值也是一个二维数组,因为前面说了要用到表达式就要把它放在花括号里,那么这里用到$eq,肯定要把它放在一个数组里,而键$eq的键值又由等号两边的值构成一个数组,数组的内容即flags和category,(即当category为flags时)。接下来是then,根据示例代码我们之前已经可以知道要查的集合是news,所以我们猜测每一条记录都有一个titile值,那我们是不是可以尝试先找到flags category所对应的title的值,所以构造payload:
      filter[$cond][if][$eq][]=flags&filter[$cond][if][$eq][]=$category&filter[$cond][then]=$title&filter[$cond][else]=$category
      其中else我们可以任意构造即可
    image.png
      可以由返回的信息看到这里明显返回的有一个提示,this is a flag text,所以此时我们猜测这里是提示我们flag是文本索引的,所以通过$text我们可以获得category为flags的文本(即flag),所以构造:
    filter[$cond][if][$eq][]=flags&filter[$cond][if][$eq][]=$category&filter[$cond][then]=$text&filter[$cond][else]=$category
    image.png
      当然还有其它的payload可以用,impakho师傅博客里用的payload是:
    filter[$cond][if][$eq][][$strLenBytes]=$title&filter[$cond][if][$eq][][$toInt]=19&filter[$cond][then]=$text&filter[$cond][else]=12
      其实原理都差不多,这里是直接利用给的title提示来拿到flag,this is a flag text,刚好19个字符长度,又因为由上面的图已经知道以title为分组依据时this is a flag text返回 1 news,即它的文本域肯定就是flag了,只要结合一下$strLenBytes和$toInt表达式判断一下当前title的长度即可。

    总结

      说实话MongoDB的语句和Mysql比起来,刚开始看还是有点绕,可能是我太菜了==。这个题目还是不错的,遇到不会的知识点,查官方文档的确是事半功倍的好办法,当然这种类比着理解的方法我觉得也挺有用。

    参考

    https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/
    https://blog.csdn.net/newbie_907486852/article/details/82502815
    https://www.runoob.com/mongodb/mongodb-databases-documents-collections.html
    https://impakho.com/post/cybrics-ctf-2019-writeup#toc-7

  • 相关阅读:
    微信小程序学习Course 9-2 云存储功能
    微信小程序学习Course 9-1 云数据库功能
    微信小程序学习Course 9 云开发功能
    微信小程序学习Course 6 界面交互API函数
    微信小程序学习Course 3-3 JS时间类型学习
    微信小程序案例TODO备忘录
    微信小程序学习Course 3-2 JS数组对象学习
    微信小程序学习Course 8 本地缓存API
    微信小程序学习Course 7 定时器功能
    常用excel函数语法及说明
  • 原文地址:https://www.cnblogs.com/tr1ple/p/11288112.html
Copyright © 2011-2022 走看看