daemon-sec-lotl

DÆMONBins: GTFOBins × LOLBAS × WADComs × LOOBins in one filterable catalog
git clone https://git.daemon-sec.xyz/daemon-sec-lotl.git
Log | Files | Refs | Submodules | README | LICENSE

catalog-workspace.test.mjs (4219B)


      1 import { test } from 'node:test';
      2 import assert from 'node:assert/strict';
      3 import { readFileSync } from 'node:fs';
      4 import { loadTs } from './_loadts.mjs';
      5 import { normalizeTechnique, stableId } from '../scripts/enrich-data.mjs';
      6 import { LIST_FIELDS as indexFields } from '../scripts/build-index.mjs';
      7 const { configureCommand, quoteArgument, groupTechniques, contextualCounts, sortTechniques } = await loadTs('src/lib/catalog-workspace.ts');
      8 const { matches, EMPTY_FILTERS, filtersToSearch, filtersFromSearch } = await loadTs('src/lib/techniques.ts');
      9 const { LIST_FIELDS, renderRow } = await loadTs('src/lib/render-row.ts');
     10 const row = (over = {}) => ({ id:'a', toolId:'gtfo:vim', toolName:'vim', source:'GTFOBins', command:'vim', platform:['Linux'], capability:['Execution'], nativeCategory:[], mitre:[], references:[], ...over });
     11 
     12 test('context/access/service/environment filters compose and round-trip', () => {
     13   const t = row({ context:'sudo', requires:['Shell'], services:['SMB'], environment:['Local host'], aliases:['vi'] });
     14   const f = { ...EMPTY_FILTERS, context:['sudo'], requires:['Shell'], services:['SMB'], environment:['Local host'], query:'vi sudo' };
     15   assert.equal(matches(t,f),true); assert.deepEqual(filtersFromSearch(filtersToSearch(f)),f);
     16   assert.equal(matches(t,{ ...f, context:['suid'] }),false);
     17   assert.equal(matches(t,{ ...f, query:'vi missing' }),false);
     18 });
     19 test('facet counts exclude their own facet but retain the other filters', () => {
     20   const rows = [row({context:'sudo'}),row({id:'b',context:'suid'}),row({id:'c',context:'suid',platform:['Windows']})];
     21   const counts = contextualCounts(rows,{...EMPTY_FILTERS,platform:['Linux'],context:['sudo']});
     22   assert.deepEqual(counts.context,{sudo:1,suid:1}); assert.deepEqual(counts.platform,{Linux:1});
     23 });
     24 test('grouping retains variants and exact tool matches sort first', () => {
     25   const rows = [row(),row({id:'b',context:'sudo'}),row({id:'c',toolId:'daemon:aws',toolName:'aws'})];
     26   assert.equal(groupTechniques(rows).length,2); assert.equal(groupTechniques(rows)[0].length,2);
     27   assert.equal(sortTechniques(rows,'tool','vim')[0].toolName,'vim');
     28 });
     29 test('template variables are quoted as arguments and cannot introduce new lines', () => {
     30   const tpl = {shell:'posix',command:'tool --host {{host}}',variables:[{key:'host',label:'Host',default:'example.test'}]};
     31   assert.equal(configureCommand(tpl,{}),"tool --host 'example.test'");
     32   assert.equal(configureCommand(tpl,{host:"x'; echo bad; '"}),"tool --host 'x'\"'\"'; echo bad; '\"'\"''");
     33   assert.equal(quoteArgument("a'b",'powershell'),"'a''b'");
     34   assert.throws(()=>configureCommand(tpl,{host:'x\ncommand'}));
     35   assert.throws(()=>configureCommand({...tpl,command:'tool {{missing}}'},{}));
     36 });
     37 test('list payload retains the fields required by filters and configuration', () => {
     38   assert.deepEqual(LIST_FIELDS,indexFields);
     39   for (const key of ['context','requires','services','environment','template','references']) assert.ok(indexFields.includes(key));
     40 });
     41 test('row markup keeps navigation links outside interactive buttons', () => {
     42   const html = renderRow(row());
     43   for (const button of html.matchAll(/<button\b[^>]*>([\s\S]*?)<\/button>/g)) assert.doesNotMatch(button[1],/<a\b/);
     44 });
     45 test('normalization removes unverified macOS tags and category pollution', () => {
     46   const t = normalizeTechnique(row({platform:['Linux','macOS'],requires:['Exploitation','powershell','PowerShell','Hash'],services:['Enumeration','SMB']}));
     47   assert.deepEqual(t.platform,['Linux']); assert.deepEqual(t.requires,['PowerShell','NTLM hash']); assert.deepEqual(t.services,['SMB']);
     48   assert.equal(stableId('tool','command'),stableId('tool','command'));
     49 });
     50 test('committed additions and imported examples carry explicit evidence', () => {
     51   const rows = JSON.parse(readFileSync('src/data/techniques.json'));
     52   const mac = rows.filter(t=>t.source==='LOOBins'); assert.equal(mac.length,183);
     53   assert.ok(mac.every(t=>t.verification==='Upstream reference' && t.references.some(r=>r.includes('/blob/'))));
     54   assert.ok(!rows.some(t=>t.source==='GTFOBins' && t.platform.includes('macOS')));
     55   assert.equal(JSON.parse(readFileSync('src/data/sources/wadcoms-additions.json')).length,134);
     56 });