1. 云栖社区>
  2. PHP教程>
  3. 正文

php+mongo下的注入学

作者:用户 来源:互联网 时间:2017-12-01 17:57:09

phpmongo学习注入

php+mongo下的注入学 - 摘要: 本文讲的是php+mongo下的注入学, 今天看了freebuf上的一篇介绍php环境下mongo注入的文章:www.freebuf.com/articles/database/95314.html 写的非常不错,于是自己也学习了一下,写个文章作为自己的学习总结。 由于mong

今天看了freebuf上的一篇介绍php环境下mongo注入的文章:www.freebuf.com/articles/database/95314.html

写的非常不错,于是自己也学习了一下,写个文章作为自己的学习总结。


由于mongo查询语法的特殊性,导致传统的sql注入攻击并不适用于mongodb的注入。但是在php环境下,因为php内的数组要求不是很严格,所以

有可能导致利用php数组实现mongodb的注入攻击。

有如下在mongo的查询语句:

db.student.find({ "age":{ "$lt":27, "$gt":20 }})  #查询年龄在20-27的学生

在php+mongo的环境下,会是如下的实现形式:

$c->find( array( 'age'->array( '$lt'->27,'$gt'->20 )))

如果是一个登录查询,那么比较典型的查询如下:

$c->find( array( 'name'->$name, 'passwd'->$passwd))

可是如果这个时候,$name传进来的是一个数组,那么就有可能改变查询逻辑,导致注入发生。


以www.root-me.org中,一个nosql-injection的challenge为例:

挑战页面提供了一个登录窗口,要求用户输入用户名和密码,提交后会看到账户信息是通过url参数以get方式提交的。

http://challenge01.root-me.org/web-serveur/ch38/?login=a&pass=b

这里我们就可以假设它的后台查询语句按照上面的登录查询例子实现,如果修改url的参数值,将变量改为数组,并插入一些其他条件,那么就可以成功登录。

?login[$ne]=a&pass[$ne]=b

按照如上的url发起请求时,最后提交到mongo中的查询语句会变为如下的形式:

$c->find( array( 'name'->array(  '$ne'->'a' ), 'passwd'->array( '$ne'->'b' ) )) #查询用户名不为a,且密码不为b的账户

这样最后的查询结果为真,攻击者成功登录。

这里主要利用到了php的一个特性,我们可以直接在url中将变量赋值为一个数组。

例子中的url,最后的两个变量分别称为了只有一个元素的数组:array( '$ne'->'a')和array('$ne'->'b')。

php的这个特性还挺奇妙的,我还特意弄两个wamp环境试了一下,在url中也可以将变量赋值为一个有多个元素的数组,使用如下的url

test.php?test['a']=123&test['b']=456

最后通过$_GET["test"]获取到的value为array( 'a'->'123','b'->'456')

这个特性让我想起了asp中的副参数,即在url中同一个参数出现多次,最后asp会把所有的value用逗号组合为一个value,如下:

test.asp?test=123&test=456

最后asp中获取到的test变量的value为‘123,456’,这个特性有时候也可以用来作为web攻击中针对ips的逃逸手段。

回到刚刚那个root-me的例子,题目是要找到一个隐藏的用户名,每次登录成功后都会显示当前登录的用户名,通过?login[$ne]=a&pass[$ne]=b这种方式,首先会登录成功,此时提示用户名为admin,然后再试一次?login[$ne]=admin&pass[$ne]=b,会出现test账户,但是接下来用?login[$ne]=test&pass[$ne]=b,却又是以admin账户登录的。

freebuf文章中的作者结合了sql注入中的盲注猜字段value的方式先猜到了两个账号的密码,然后再结合与或条件最后以隐藏账号的方式登录成功。其实也可以直接盲注隐藏的用户名。

我试着用字符串比较的方式来排除admin和test账户:

?login[$ne]=admin&pass[$ne]=b&login[$ne]=test

这样也可以直接以隐藏账户的方式登录获得flag。不过后来看到有留言用了正则匹配的方式,排除以a和t开头的账户,如下:

login[$regex]=^[^(a|t)]&pass[$ne]=


不过这都不是问题,关键的步骤在于了解php下查询mongo的使用方式,以及熟悉php中数组的一些特性,这样才有机会完成root-me中的这个挑战。

(补充:又抓包看了一下,服务器的返回头中也没有x-powered-by之类的头部,所以应该不太好确认就是mongo+php环境,所以感觉这个挑战难度还是挺大的)


以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索php , mongo , 学习 注入 ,以便于您获取更多的相关知识。