Skip to content

Commit

Permalink
webapp: add payload search filter
Browse files Browse the repository at this point in the history
  • Loading branch information
aiooss-anssi committed May 13, 2024
1 parent e6f0112 commit e93093b
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 5 deletions.
22 changes: 20 additions & 2 deletions webapp/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,16 @@ async def api_flow_list(request):
ts_to = request.query_params.get("to", str(int(1e10)))
services = request.query_params.getlist("service")
app_proto = request.query_params.get("app_proto")
search = request.query_params.get("search")
tags = request.query_params.getlist("tag")
if not ts_to.isnumeric():
raise HTTPException(400)

# Query flows and associated tags using filters
query = """
WITH fsrvs AS (SELECT value FROM json_each(?1)),
ftags AS (SELECT value FROM json_each(?2))
ftags AS (SELECT value FROM json_each(?2)),
fsearchfid AS (SELECT value FROM json_each(?5))
SELECT id, ts_start, ts_end, dest_ipport, app_proto,
(SELECT GROUP_CONCAT(tag) FROM alert WHERE flow_id = flow.id) AS tags
FROM flow WHERE ts_start <= ?3 AND (?4 IS NULL OR app_proto = ?4)
Expand All @@ -64,10 +66,26 @@ async def api_flow_list(request):
HAVING COUNT(*) = (SELECT COUNT(*) FROM ftags)
)
"""
search_fid = []
if search:
cursor = await payload_database.execute(
"SELECT flow_id FROM raw WHERE blob GLOB ?1",
(search,),
)
rows = await cursor.fetchall()
search_fid = [r["flow_id"] for r in rows]
query += " AND flow.id IN fsearchfid"
query += " ORDER BY ts_start DESC LIMIT 100"

cursor = await eve_database.execute(
query, (json.dumps(services), json.dumps(tags), int(ts_to) * 1000, app_proto)
query,
(
json.dumps(services),
json.dumps(tags),
int(ts_to) * 1000,
app_proto,
json.dumps(search_fid),
),
)
rows = await cursor.fetchall()
flows = [dict(row) for row in rows]
Expand Down
6 changes: 5 additions & 1 deletion webapp/static/js/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ export default class Api {
* @param {Number} timestampTo Keep only flows before this timestamp
* @param {Array} services Keep only flows matching these IP address and ports
* @param {String} appProto Keep only flows matching this app-layer protocol
* @param {String} search Search for this glob pattern in flows payloads
* @param {Array} tags Keep only flows matching these tags
*/
async listFlows (timestampFrom, timestampTo, services, appProto, tags) {
async listFlows (timestampFrom, timestampTo, services, appProto, search, tags) {
const url = new URL(`${location.origin}${location.pathname}api/flow`)
if (typeof timestampFrom === 'number') {
url.searchParams.append('from', timestampFrom)
Expand All @@ -35,6 +36,9 @@ export default class Api {
if (appProto) {
url.searchParams.append('app_proto', appProto)
}
if (search) {
url.searchParams.append('search', search)
}
tags?.forEach((t) => {
url.searchParams.append('tag', t)
})
Expand Down
25 changes: 24 additions & 1 deletion webapp/static/js/flowlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,22 @@ class FlowList {
this.update()
})

// On glob search filter submit, update URL then update flows list
document.getElementById('filter-search').addEventListener('keyup', e => {
if (e.key !== 'Enter') {
return
}
const search = e.target.value
const url = new URL(document.location)
if (search) {
url.searchParams.set('search', search)
} else {
url.searchParams.delete('search')
}
window.history.pushState(null, '', url.href)
this.update()
})

// On tags filter change, update URL then update flows list
document.getElementById('filter-tag').addEventListener('click', e => {
const tag = e.target.closest('a')?.dataset.tag
Expand Down Expand Up @@ -358,22 +374,29 @@ class FlowList {
const toTs = url.searchParams.get('to')
const services = url.searchParams.getAll('service')
const filterAppProto = url.searchParams.get('app_proto')
const filterSearch = url.searchParams.get('search')
const filterTags = url.searchParams.getAll('tag')
const { flows, appProto, tags } = await this.apiClient.listFlows(
fromTs ? Number(fromTs) : null,
toTs ? Number(toTs) : null,
services,
filterAppProto,
filterSearch,
filterTags
)

// Update search input
const searchInput = document.getElementById('filter-search')
searchInput.value = filterSearch ?? ''
searchInput.classList.toggle('is-active', filterSearch !== null)

await this.updateProtocolFilter(appProto)
this.updateTagFilter(tags)
await this.updateFlowsList(flows, tags)
this.updateActiveFlow()

// Update filter dropdown visual indicator
document.querySelector('#dropdown-filter > button').classList.toggle('text-bg-purple', toTs || filterTags.length || filterAppProto)
document.querySelector('#dropdown-filter > button').classList.toggle('text-bg-purple', toTs || filterTags.length || filterAppProto || filterSearch)

// Update service filter select state
document.getElementById('services-select').value = services.join(',')
Expand Down
8 changes: 7 additions & 1 deletion webapp/templates/index.html.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@
</span>
<select class="form-select" id="filter-protocol"></select>
</div>
<div class="input-group flex-nowrap mb-3">
<span class="input-group-text">
Search
</span>
<input type="text" class="form-control" placeholder="glob, e.g. '?PNG*'" id="filter-search">
</div>
<div id="filter-tag"></div>
</div>
</div>
Expand Down Expand Up @@ -166,4 +172,4 @@
</main>
</body>

</html>
</html>

0 comments on commit e93093b

Please sign in to comment.