GRAPL

 A Graph Platform for

Detection and Response

Twitter: 

@GraplSec

PYRAMID OF PAIN

WE WANT

TO BE HERE!

AT BEST,

WE'RE HERE

MOST ARE HERE

This is not

how we climb

the pyramid of pain:

image_name="procdump"
args = "*-ma*"
args = "*lsass.exe*"
{
  "host_id": "cobrien-mac",
  "parent_pid": 3,
  "pid": 4,
  "image_name": "word.exe",
  "create_time": 600,
}
{
  "host_id": "cobrien-mac",
  "parent_pid": 4,
  "pid": 5,
  "image_name": "payload.exe",
  "create_time": 650,
}

explorer.exe

payload.exe

word.exe

word.exe

payload.exe

word.exe

word.exe

payload.exe

ssh.exe

/secret/file

11.22.34.55

mal.doc

PARSING

SUBGRAPH

GENERATION

IDENTIFICATION

MERGING

ANALYSIS

ENGAGEMENTS

Dropper:

  • Dropper executes
  • Dropper reaches out to network
  • Dropper creates file
  • Dropper executes file

A process that downloads

a payload & executes it.

// Search all processes over 1 hour for dropper-like behavior
search process_executions
| join [
    | search process_executions process_id = $parent_process_id$
]
| join [
    | search network_connections process_id = $parent_process_id$
]
| join [
    | search file_creations creator=$parent_process_id$ 
      AND $file_path$ = image_name 
]
// TODO: Handle pid collisions

"By default, subsearches return a maximum of 10,000 results and have a

maximum runtime of 60 seconds. In large production environments,

it is possible that subsearches [..] will timeout"

"Performing full SQL-style joins in a distributed system like

Elasticsearch is prohibitively expensive." [..]

 

"If you care about query performance, do not use this query."

class DropperAnalyzer(Analyzer):
    def get_queries(self) -> OneOrMany[ProcessQuery]:
        return (
            ProcessQuery().with_bin_file()
            .with_parent(
            	ProcessQuery()
            	.with_external_connections()
                .with_created_files()
            )
         )

    def on_response(self, payload: ProcessView, output: Sender):
    	dropper = payload.get_parent()
        if payload.bin_file.get_file_path() in dropper.get_created_files():
          output.send(
              ExecutionHit(
                  analyzer_name="Dropper",
                  node_view=payload,
                  risk_score=75,
              )
          )

<any process>

<any file>

<external ip>

Process with external network access creates file, executes child from it

<any browser>

Browser Executing Child Process

<any process>

<winrar/7zip/zip>

<any file>

Process Executed From Unpacked Binary

<any process>

created fi​le

executed as

Mitre ATT&CK |  T1204 - User Execution

<any process>

Rare Parent Child Process

<any process>

executed

executed

created file

executed as

connected to

executed

<any process>

Rare Parent LOLBAS Process

<any process>

executed

<binary>

<lolbas path>

<word/reader/etc>

Commonly Target Application with Non-Whitelisted Child Process

<non whitelisted process>

executed

<any process>

[GraphThePlanet 5MIN] - Grapl

By Colin

[GraphThePlanet 5MIN] - Grapl

  • 1,131