前言
- 在开发Metasploit前端时需要实现一个搜索payload的功能,由于是通过rpc服务获取当前exploit可用的payload,这是在内存里的元数据获取的数据,所以并没有像数据库这样有过滤功能,就有了使用前端实现标签搜索。
实现思路
- 首先把payload的全称按照
/
分词生成标签,例如:windows/meterpreter/reverse_tcp
分割后变成windows
,meterpreter
和reverse_tcp
三个标签,按照这种方法将所有的payload分成标签,然后去重。
async compatible_payloads(fullname) {
await module_compatible_payloads(fullname).then(response => {
this.payloads_all = response.result.payloads
})
},
- 先获取当前exploit可用payload,存放在
payloads_all
,然后监听payloads_all
的变化,拷贝一份用于过滤操作,存放在payloads_filter
,当payloads_filter
变化时生成分词标签,将标签去重后存放在payloads_tags_all
,当payloads_tags_all
变化后再拷贝一份用于过滤操作,可能有点绕。
watch: {
// 拷贝一份用于过滤
payloads_all: function() {
this.payloads_filter = this.payloads_all
},
// 拷贝一份用于过滤
payloads_tags_all: function() {
this.payloads_tags_filter = this.payloads_tags_all
},
payloads_filter: function() {
var tags = []
this.payloads_filter.forEach(payload_line => {
// 生成payload标签
tags.push(...payload_line.split('/'))
})
this.payloads_tags_all = Array.from(new Set(tags))
}
},
payload标签搜索
- 在element的选择器中定义下面属性,远程方法为
load_tags
<el-select
v-if="activeStep==1"
v-model="payload.tags"
default-first-option
clearable
multiple
filterable
remote
style="width: 350px"
placeholder="tags"
:remote-method="load_tags"
:loading="tags_loading"
@change="select_payload_tags"
>
<el-option
v-for="(p,index) in payloads_tags_filter"
:key="index"
:label="p"
:value="p"
/>
</el-select>
- 下面的是
load_tags
的方法,和一般过滤一样,没什么特别的,判断过滤的关键词不为空就过滤,关键词为空就将之前保存的payloads_tags_all
覆盖掉payloads_tags_filter
。
load_tags(query) {
if (query !== '') {
this.tags_loading = true
this.payloads_tags_filter = this.payloads_tags_all.filter(p => {
return p.toLowerCase().indexOf(query.toLowerCase()) > -1
})
this.tags_loading = false
} else {
this.payloads_tags_filter = this.payloads_tags_all
}
},
- 这个方法最后改变了
payloads_tags_filter
,将payload标签可选范围缩小了。
select_payload_tags() {
this.load_payload('')
},
- 最后点击标签触发payload搜索
load_payload
方法。
payload搜索
- 在element的选择器中定义下面属性,远程方法为
load_payload
<el-select
v-model="payload.fullname"
default-first-option
clearable
filterable
remote
reserve-keyword
style="width: 350px"
placeholder="fullname"
:remote-method="load_payload"
:loading="select_loading"
>
<el-option
v-for="(p,index) in payloads_filter"
:key="index"
:label="p"
:value="p"
/>
</el-select>
load_payload(query) {
// 搜索payload标签
if (query !== '' || this.payload.tags.length) {
this.select_loading = true
this.payloads_filter = this.payloads_all.filter(p => {
var is_include = (intersection(compact(p.split('/')), compact(this.payload.tags)).length === this.payload.tags.length)
if (!is_include) {
return false
} else if (query !== '') {
return p.toLowerCase().indexOf(query.toLowerCase()) > -1
} else {
return true
}
})
this.select_loading = false
} else {
this.payloads_filter = this.payloads_all
}
},
- 有两个地方触发了
load_payload
方法,第一个在payload搜索时触发,会传关键词搜索;第二个在选择标签后改变payload.tags
数组后触发,会传一个空字符串搜索,先判断关键词是否为空,或者payload.tags
数组的长度是否大于0,有一个为真就加锁进入过滤操作,下面讲一下搜索过滤的思路。
搜索过滤
- 因为我们
payload.tags
是一个数组集合,这不用每一个标签都去判断是否在payload的全称里,有一个非常简单的方法,先将payload的全称分割得到标签,再和payload.tags
做集合求并集操作,得到并集后和payload.tags
作比较,如果是一样就表明payload全称里有payload.tags
里的标签,而且是准确的。