[00:00.000 --> 00:05.560] Welcome everybody to APT's Love PowerShell and Why You Should Too. I'm Anthony. I'm here with [00:05.560 --> 00:10.820] Jake. We're going to be going over some of the interesting things that APTs do for PowerShell. [00:10.940 --> 00:18.000] And here we go. So once again, I'm Anthony. I go by coin. That's my handle. I got a master's in [00:18.000 --> 00:22.260] electrical engineering, same with my bachelor's. Some interesting things about me. I'm a lock [00:22.260 --> 00:26.620] picking hobbyist. You followed some of my work. I did some Bluetooth lock picking hacks over the [00:26.620 --> 00:32.300] years, as well as some wireless stuff. And then a lot of my focus recently has been building up [00:32.300 --> 00:38.240] Empire and Starkiller. And then I got Jake here as well. Yeah, hey guys. I've got... my background's [00:38.560 --> 00:43.600] a BS in astronautical engineering and I have an MBA. I actually ended up getting into cybersecurity [00:43.600 --> 00:49.020] while I was in the Air Force because I showed up at a new unit and they'd been told they had to [00:49.020 --> 00:54.920] have a cybersecurity person and I was voluntold that I was the new person. So after that, I ended [00:54.920 --> 01:02.280] up as a... doing some cyber testing for fighter aircraft for the Air Force. Then went on to a [01:02.280 --> 01:08.740] red team where I was a red team lead for about a year and a half, two years. And then I got out of [01:08.740 --> 01:15.080] the Air Force and now I'm currently focused on embedded systems security. And I'm kind of our [01:15.080 --> 01:20.840] PowerShell obfuscation expert for BC security. So I spend a lot of time on that too. So we get told [01:20.840 --> 01:25.120] this all the time and ask this question, you know, aren't PowerShell attacks dead? You know, [01:25.120 --> 01:30.400] offensive PowerShell's dead. Why don't you just move to C-sharp? Script logging to, you know, [01:30.400 --> 01:34.860] makes PowerShell attack completely impossible. You know, all these sort of things everybody [01:34.860 --> 01:41.420] always brings up. And we're constantly being told this, you know, why use PowerShell? Isn't it dead? [01:41.780 --> 01:47.680] Yeah. And just kind of a fun story about that bottom line about AMSI is going to catch [01:47.680 --> 01:53.860] offensive scripts is we gave a webinar back in February that was actually a workshop we taught [01:53.860 --> 01:59.920] at DEF CON last year. We had a Microsoft security guy show up with and gave us the challenge a [01:59.920 --> 02:04.320] couple of days beforehand that he was curious to see if we'd actually be able to get AMSI [02:05.080 --> 02:11.160] or passed AMSI on a fully patched machine. Whether it was intentional or not, they actually [02:11.160 --> 02:18.940] rolled out some updates to AMSI like the day before we started our course. Like they added [02:18.940 --> 02:23.000] some additional detections when you're using like invoke expression and that kind of stuff that did [02:23.000 --> 02:28.820] throw a little bit of a loop. But by the end of the class, the Microsoft guy was a little bit [02:28.820 --> 02:36.780] blown away by the fact that we could still get default Empire payloads past fully patched AMSI [02:36.780 --> 02:42.860] stuff just using obfuscation and some of the tactics and techniques we'll talk about a little [02:42.860 --> 02:49.100] more going forward. So obviously PowerShell is really, really dead. It can't be used for [02:49.100 --> 02:55.860] offensive PowerShell anymore. So this is just a quick poll that you can just go into Google and [02:55.860 --> 03:02.100] look over the last couple of months. What you can see is just APTs and threats are using offensive [03:02.100 --> 03:06.680] PowerShell pretty regularly for all types of things, not only just for breaches, but for [03:06.680 --> 03:12.900] ransomware attacks, for lateral movements, gaining initial access. It's being used for all sorts of [03:12.900 --> 03:21.840] things. Okay, so just a quick primer in case everyone's not fully aware of PowerShell. Why [03:21.840 --> 03:26.440] PowerShell and how it became a popular offensive tool in the first place is that it gives us full [03:26.440 --> 03:33.840] .NET access to Windows, which is kind of really the underlying architecture for being able to do a [03:33.840 --> 03:39.880] ton of lower level stuff in Windows. It gives us direct access to the Win32 API, which also gives [03:39.880 --> 03:46.960] us low level access to operating system functions. We can operate entirely out of memory, for the [03:46.960 --> 03:52.280] most part, and then installed by default in Windows. And admins typically leave it enabled [03:52.280 --> 03:59.240] because it is a huge efficiency enabler in terms of their jobs and that kind of stuff. [03:59.460 --> 04:04.300] And, you know, the theme of the day is going to be why PowerShell is still relevant and how we still [04:04.300 --> 04:09.680] see it being used by red teams. So this is just another tweet on the side about how Microsoft and [04:09.680 --> 04:16.540] red teams talk about PowerShell being totally played out. Meanwhile, APTs and criminal groups [04:16.540 --> 04:22.160] are using PowerShell every day. They might not be using it for the full attack chain, [04:22.160 --> 04:27.840] but almost every APT is using PowerShell in some way, shape or form during a breach. [04:28.660 --> 04:34.080] So now we're just going to do a quick timeline of PowerShell, like when it was released, [04:34.080 --> 04:39.260] when offensive tooling started coming out and when defenses were incorporated into it. [04:39.260 --> 04:45.140] So PowerShell version 1 came out in 2006. It was released for XP, Service Pack 2, Server [04:46.260 --> 04:52.080] 2003, and Vista. When it was first released, it didn't have a ton of capability. It was kind of [04:52.080 --> 04:59.480] more of a novelty thing. And PowerShell version 2 is when we really saw it start getting widely [04:59.480 --> 05:06.540] adopted. It was fully integrated into Windows 7 and Server 2008. It introduced a bunch of new [05:06.540 --> 05:11.760] features such as PowerShell remoting and background jobs. PowerShell version 2 was [05:11.760 --> 05:17.620] like when we saw the real adoption by sysadmins and that kind of stuff, to the point that many [05:17.620 --> 05:25.200] there are sysadmin tools that you will encounter on live networks still that run in PowerShell [05:25.200 --> 05:30.620] version 2 because that is what they were written in and they don't want to take the time to go [05:30.620 --> 05:36.720] port it to a different version. And so you'll find networks that still have PowerShell version 2 [05:36.720 --> 05:44.420] enabled because they want to be able to use their automation scripts. And so version 2 and version [05:44.420 --> 05:50.580] 5 that we'll talk about in a second are kind of the big delineators of what's going on in PowerShell [05:50.580 --> 05:54.840] version 2. If we can run in version 2, that's where we want to be as offensive people. And [05:54.840 --> 06:01.560] version 5 is where we got the full Gucci set of defenses. It had a few protections, but it had [06:01.560 --> 06:08.200] essentially no protections. And then Trusted Security, David Kennedy and Josh Kelly gave [06:08.200 --> 06:16.500] their PowerShell it's time to own talk in 2010. And that was when we saw the beginning of the [06:16.500 --> 06:23.060] wave of offensive use of PowerShell. They were really kind of the initialization of the movement [06:23.060 --> 06:28.960] for offensive PowerShell tooling was their talk that they gave in 2010. So that's when we started [06:28.960 --> 06:36.540] seeing people begin to adopt things. PowerShell version 3 came out two years later in 2012. [06:36.540 --> 06:41.320] It introduced module logging, which we will talk about that more. I actually think it's one of the [06:41.320 --> 06:47.820] more powerful logging capabilities in PowerShell, and it was introduced all the way back in version [06:47.820 --> 06:54.180] 3. But PowerSploit was first published in 2012. A lot of people don't realize just how old [06:54.180 --> 07:00.100] PowerSploit is at this point. And then Metasploit also introduced its execute PowerShell capability [07:00.960 --> 07:08.780] in 2012. And 2013, PowerShell version 4 came out. This was where rudimentary strip block logging [07:08.780 --> 07:17.000] was introduced. It's more akin to what PowerShell version 5 referred to as transcription logging. [07:17.000 --> 07:21.700] So it did do some script block logging, but it's not nearly as powerful as the [07:21.700 --> 07:28.720] one introduced in version 5. And then 2014 is where we start seeing like [07:29.720 --> 07:35.700] the just overwhelming wave of offensive tooling and everyone adopting it. PowerView gets published, [07:35.700 --> 07:42.240] PowerUp gets published, CobaltStrike incorporates PowerShell execution into its tooling, [07:42.240 --> 07:46.480] and that just kind of starts the major wave of offensive PowerShell. [07:47.000 --> 07:52.700] PowerShell version 5 was introduced in 2015 slash 2016. It's got two dates because it was [07:52.700 --> 07:58.160] officially released in 2015, but there was a major bug in it that required it to be re-released [07:58.160 --> 08:05.220] in 2016. So it sort of has two release dates. But in 2015, PowerShell hurts the blue team [08:05.220 --> 08:12.380] was published and it was a article published by Microsoft that introduced this whole host of [08:12.380 --> 08:20.340] PowerShell defenses to combat the offensive movement of malware through PowerShell. [08:20.340 --> 08:27.500] So it introduced what they call deep script block logging, transcription logging, talks about module [08:27.500 --> 08:33.240] logging some more, and then the big game changer was the introduction of AMSI, which we'll go to [08:33.240 --> 08:39.680] in more depth in a second. That's also where PowerShell Empire was released as well as PowerPick. [08:39.680 --> 08:49.640] So now that we've kind of gone through that timeline, we can see who's still using it today [08:49.640 --> 08:55.520] because we hear about people moving to C-sharp and that PowerShell, as we said, played out and [08:55.520 --> 09:01.320] that kind of stuff. But these are all the APTs that are currently still using PowerShell. So [09:01.320 --> 09:07.080] pretty much everyone. That's not to say that they're operating entirely in PowerShell, [09:07.080 --> 09:17.080] but they're using it in some way, shape or form. That's how we'll just said like just about every [09:17.080 --> 09:22.320] threat and every APT is using PowerShell in some sort of capacity. And when you're trying to go out [09:22.320 --> 09:26.120] as a red team and try to emulate those threats, you want to know what they're doing. I know we're [09:26.120 --> 09:31.400] focusing on a lot of PowerShell during this talk, but there are other tactics, techniques, procedures [09:31.400 --> 09:36.820] or TTPs that people use. So be able to do that research. You want to be able to research what [09:36.820 --> 09:41.160] those behaviors of the adversary is doing and kind of build that cyber threat intelligence [09:41.680 --> 09:46.620] based on whatever the threat is that we're looking at. And this is important because this is something [09:46.620 --> 09:51.100] that, you know, a lot of industry is going to be using, governments do, as well as some of the [09:51.100 --> 09:55.560] open source community. You can use things like FireEye if you want to pay for some of that [09:55.560 --> 10:01.520] threat intelligence info. Otherwise, another option is always go on to MITRE's page for the [10:01.520 --> 10:06.100] attack framework. And you can do some research there to see, you know, what techniques certain [10:06.100 --> 10:11.540] APTs are using, maybe get some more info if they're using PowerShell specifically, and then [10:11.540 --> 10:15.580] see, you know, what sort of lateral movements or what sort of privilege escalation techniques [10:15.580 --> 10:19.740] they're leveraging when they're focusing on PowerShell. So just a nice thing to mention, [10:19.740 --> 10:23.100] because we're doing a lot of, we're talking a lot about APTs and being able to go back [10:23.520 --> 10:26.940] and kind of do some more research with them is pretty important. [10:27.340 --> 10:31.380] So when you start doing some of that research on APTs, [10:32.560 --> 10:37.240] you'll find that they're using PowerShell for a lot of different reasons. [10:37.880 --> 10:41.980] Obviously, command and control is a big one. There's a lot of different C2 frameworks out [10:41.980 --> 10:48.060] there that are being used. You'll see some of the APTs using things like Empire or other C2 [10:48.060 --> 10:53.840] frameworks to kind of control whatever they're doing for their implants. PowerShell can be [10:53.840 --> 10:59.740] leveraged for their DLL hijacking. It can be used for key logging. One of the really big ones that's [10:59.740 --> 11:04.760] used for is lateral movement and privilege escalation. Lateral movement specifically for [11:04.760 --> 11:09.940] the PS exec, you have PS remoting, you have WIME. All those things are all leveraged using [11:09.940 --> 11:15.920] PowerShell. And then privilege escalation specifically for INVE. So really everybody's [11:15.920 --> 11:20.580] still using a lot of offensive PowerShell. These are some numbers that we pulled pretty recently. [11:20.580 --> 11:25.560] Most of these are within the last couple of months when these reports were published. [11:25.560 --> 11:30.640] Carbon Black put out that about 90% of target attacks are using PowerShell. So it's a very [11:30.640 --> 11:37.380] big significant number. As well as McAfee for this last quarter put out there was a 689% [11:37.380 --> 11:43.520] increase in target attacks using PowerShell. So not only is PowerShell still being used a lot, [11:43.520 --> 11:48.980] its use is increasing significantly by each quarter and every year. And the last one, [11:48.980 --> 11:54.360] CrowdStrike's most recent report said about 50% to 70% of target attacks, they observed PowerShell. [11:54.360 --> 11:58.940] Pretty wide range when you're talking about how many attacks are actually using PowerShell out [11:58.940 --> 12:05.560] there. One of the examples that we're going to talk through is APT33. If you do some research [12:05.560 --> 12:10.220] out there, you can see that they rely pretty significantly on PowerShell to be able to do [12:10.220 --> 12:16.520] their stuff. They are a suspected Iranian threat group. So they are state sponsored. [12:16.580 --> 12:21.320] And they're really going to be focusing on aerospace and energy industries. So a lot of [12:21.320 --> 12:26.720] defense contractors is what they're really aiming for. So trying to hurt the industrial [12:26.720 --> 12:31.000] base of a country when it comes to defense is really what their target is. And they're typically [12:31.000 --> 12:37.120] employing things like Empire, PowerSploit, and Mimikatz, focusing mostly on the PowerShell side [12:37.120 --> 12:41.980] of things. They have been seen to use things like CobaltStrike and other things for some of their [12:41.980 --> 12:47.020] beacons, but they're trying to stick mostly with a lot of the open source stuff that's put out there. [12:51.510 --> 12:56.630] So this is just an excerpt of one of their malicious files that they use that FireEye did [12:56.750 --> 13:02.310] a report on a couple of months ago. And what they did was they used a malicious HTA file, [13:02.310 --> 13:07.810] which is an HTML executable. And what that does, it has just a regular HTML on the top part [13:07.810 --> 13:14.990] that may point to a certain person. In this case, it was this aircraft company. And then after all [13:14.990 --> 13:21.110] that HTML, they embed a script. So the script that they're running launches a PowerShell [13:21.110 --> 13:27.250] hidden window with a base64 encoded payload attached to that. And this launching method [13:27.250 --> 13:31.110] is actually very similar to how Empire does a lot of their things. So you're talking about [13:31.110 --> 13:38.070] emulating what the threat does. Empire emulates this threat pretty well, especially with the HTA [13:38.070 --> 13:49.110] file. Next is WastedLocker ransomware. This has been pretty popular in the news recently. [13:49.110 --> 13:54.270] This is from the EvilCorp group or Drydex. And what this does is it leverages a few different [13:54.270 --> 13:59.250] things to be able to launch the ransomware. First, it leverages a CobaltStrikeBeacon and [13:59.250 --> 14:05.010] PowerView, kind of get that initial foothold. And it contains both PowerShell, JavaScript, [14:05.010 --> 14:10.110] and .NET. So it's really leveraging everything when you look at how they go about launching [14:10.110 --> 14:14.570] this ransomware. And once they get that initial access with that CobaltStrikeBeacon, [14:14.570 --> 14:19.310] what they're going to do is they're going to run PsExec, which is going to launch PowerShell and [14:19.310 --> 14:24.930] run the WastedLocker ransomware. And once that ransomware is in place, that's really where [14:24.930 --> 14:29.310] they're going to make their money. They're going to lock down companies, individuals, whatever they [14:29.310 --> 14:35.190] can, their machines. They're going to put out a Bitcoin address or whatever other cryptocurrency [14:35.190 --> 14:41.490] they want to get paid in. And they're going to then hide those keys until you guys pay the [14:42.370 --> 14:47.370] fees. And they've been very, very successful with this. The numbers being reported at the moment is [14:47.370 --> 14:52.210] they've made at least $100 million using this sort of ransomware. So it's a very profitable [14:52.210 --> 14:57.010] business for a threat to be able to use. So being able to see how they do it and then [14:57.730 --> 15:01.110] emulate what parts we can is very, very important. [15:02.710 --> 15:10.810] Yeah, and then this comes from a case study that Microsoft did on a breach that happened [15:10.810 --> 15:19.210] to Nepone Telegraph and Telephone. They actually didn't have enough indicators of compromise or [15:19.210 --> 15:28.170] enough access to the NTT findings to do a direct analysis of all the techniques themselves. [15:28.170 --> 15:35.810] But what they were able to do was build a lab that restructured the representative [15:36.770 --> 15:44.610] architecture of NTT and then kind of theorized how they would do it, which ended up using [15:45.590 --> 15:49.630] a decent amount of PowerShell. And we just included this one because we thought it was [15:50.510 --> 15:54.410] highly representative of like these major corporations that we're seeing being attacked [15:54.410 --> 16:00.990] now because they use a hybrid infrastructure of on-premise servers as well as cloud servers [16:01.450 --> 16:08.850] and then Active Directory and just it's a very complex attack surface. [16:09.350 --> 16:15.150] They still ended up utilizing PowerShell through several of the steps to pivot through. [16:17.560 --> 16:22.820] So they used phishing to get an initial foothold. Once they had that initial foothold, [16:22.820 --> 16:29.760] they were able to gain domain information. Then they scraped social media in addition to add to [16:29.760 --> 16:34.680] the information they had from the domain information to start building like what people's [16:34.680 --> 16:39.260] emails might look like or their usernames and that kind of stuff. Once they did that, they [16:39.260 --> 16:44.580] started password spraying to get access to the cloud server, which they designated server B [16:44.580 --> 16:47.820] as part of their case study. [16:50.100 --> 16:55.060] Once they got access to server B, we start seeing them use a lot more PowerShell [16:55.860 --> 17:00.900] because PowerShell in the cloud is still very effective. And what they ended up doing was [17:00.900 --> 17:06.000] building a brute force attack on user accounts on server A because server A was a privileged [17:06.000 --> 17:14.180] production server. And what they were looking for was accounts that had both cloud privileges [17:14.180 --> 17:18.900] as well as local privileges because those users don't always overlap. So they first use PowerShell [17:18.900 --> 17:26.720] to start trying to identify users that had had synced accounts between the local network on [17:26.720 --> 17:31.140] server A as well as the cloud network that was in server B. Then they were able to brute force [17:31.140 --> 17:38.140] those accounts to start trying to get access to server A. Once they got onto server A, they were [17:38.140 --> 17:44.620] able to extract passwords from LSAS and remote sessions to get remote access to the Active [17:44.620 --> 17:51.600] Directory server. Once the Active Directory server was compromised, they added a backdoor into it to [17:51.600 --> 17:57.000] maintain persistence. And if you look at these images, those are just showing some of the [17:57.000 --> 18:02.800] PowerShell they used. And again, we're just showing how this was used to target a major [18:02.800 --> 18:10.060] international telecommunications company that had servers in multiple locations as well as cloud and [18:10.060 --> 18:16.920] local-based. One of the last ones for our case studies that we just want to show some PowerShell [18:16.920 --> 18:22.600] usage in the wild is one that we were contacted about a couple of months ago. There was a very [18:22.600 --> 18:26.960] large international hotel chain that reached out to us and said that they detected some malicious [18:26.960 --> 18:32.280] activity on their network and they were downloading payloads from our GitHub specifically. And what [18:32.280 --> 18:37.240] was going on here was they were getting an initial foothold inside the network. They were trying to [18:37.240 --> 18:42.240] stay as lean as possible. They were going out through the web, reaching out to our GitHub, which [18:42.240 --> 18:48.400] we hosted Empire. They went specifically to one module, which was our Invoke Mimikatz module. [18:48.400 --> 18:52.400] Since we keep that pretty up to date, they were downloading that right onto the network so they [18:52.400 --> 18:57.000] can run it locally. And that way they could run Invoke Mimikatz completely locally. This technique [18:57.000 --> 19:02.380] of downloading things from GitHub and other destinations is a pretty popular technique among [19:02.380 --> 19:07.760] APTs. And you can find it in the CrowdStrike report for 2020. It's pretty widely used. [19:07.760 --> 19:12.780] One of the interesting traits about this though that really stood out to us was the fact that [19:12.780 --> 19:17.600] they were running things completely unobfuscated. They were running it just without any obfuscation [19:17.600 --> 19:21.660] or if they had any evasion at all, it was very, very basic techniques. Normally, you wouldn't [19:21.660 --> 19:27.780] see this from a threat, but it actually had some really interesting results from it. First, [19:27.780 --> 19:32.700] the defenders on this network waived it off initially because they thought it was the [19:32.700 --> 19:38.440] internal red team practicing. So since a lot of those weird obfuscation techniques really make [19:38.440 --> 19:42.820] things stand out in the logs, their blue team didn't think anything of it because they just [19:42.820 --> 19:47.160] thought it was the red team testing internally. So being unobfuscated in this case actually worked [19:47.160 --> 19:51.720] to their advantage. They still ended up getting caught eventually, but it really was a benefit [19:51.720 --> 19:59.860] for them. Yeah. And just to add to that, the hotel chain did stop them from compromising [19:59.860 --> 20:06.180] anything before they lost any user data or anything like that. It was just initially, [20:06.180 --> 20:13.540] they thought they waived it off the activity. So the attackers did have some extra time while [20:13.540 --> 20:18.900] they were trying to deconflict that it actually wasn't the red team that they thought it was. [20:19.740 --> 20:24.820] Now that we've talked about all those case studies, we've mentioned some of these logging [20:24.820 --> 20:30.480] techniques and that kind of stuff that have created, when fully implemented, created an [20:30.480 --> 20:37.040] environment that's actually fairly difficult to use PowerShell in. If you use the full capabilities [20:37.040 --> 20:42.620] of strip block logging and module logging and AMSI combined with an EDR, that does [20:43.280 --> 20:50.560] make PowerShell pretty hard to get through. But our point, especially we've specialized in [20:50.560 --> 20:57.160] working with smaller to medium-sized businesses, and you just don't see them using this fully. [20:57.160 --> 21:02.020] Maybe they do have strip block logging enabled or module logging enabled, but they're not [21:02.020 --> 21:06.340] ingesting it properly into their scene because it's producing so much data. [21:06.340 --> 21:09.880] And so, or they don't have good signature, they don't know how to build signatures that [21:09.880 --> 21:16.960] would flag on malicious data, but not on their admins. So it's not the protections that we [21:17.680 --> 21:25.440] often see it portrayed as in the offset community. They're just, oftentimes you see the [21:25.440 --> 21:30.180] limitations of real-world implementation don't meet what the full capability can be achieved in [21:30.380 --> 21:36.640] a lab. And then also just something else to note is that, you know, AMSI has already been [21:37.160 --> 21:44.160] incorporated into .NET. So C-Sharp now has to deal with AMSI and Microsoft is, you know, [21:44.160 --> 21:49.960] constantly innovating and looking at ways to start to improve the defense of .NET now that [21:49.960 --> 21:54.800] we're seeing a lot of people doing that. So the advantages that C-Sharp have today [21:55.600 --> 22:03.380] have already began shrinking from what PowerShell has and are, and will probably continue to shrink [22:03.380 --> 22:09.560] into the advantages that it has over PowerShell as Microsoft implements more and better defenses [22:09.560 --> 22:19.000] into .NET. So now we're going to talk about AMSI in a little more in-depth. We hear about it a lot, [22:19.000 --> 22:24.960] but often people don't really fully understand exactly how AMSI is working. So AMSI is the [22:24.960 --> 22:32.320] Windows Anti-Malware Scan Interface. I'm going to go ahead and read off the Microsoft definition [22:32.320 --> 22:38.600] for you guys. It's a versatile interface standard that allows your applications and services to [22:38.600 --> 22:43.480] integrate with any anti-malware product that's present on a machine. AMSI provides enhanced [22:43.480 --> 22:47.700] malware protection for your end users and their data applications and workloads. [22:50.220 --> 22:55.980] So that's great, but kind of what does it mean? And what that means is that AMSI, first of all, [22:55.980 --> 23:00.600] doesn't work with just PowerShell. It works with VBScript, it works with JScript, [23:00.600 --> 23:04.440] as well as other applications that we want to send information to. It's built to be [23:04.440 --> 23:11.400] kind of this all-purpose lower level layer that you can tell it has predefined interfaces [23:11.400 --> 23:18.140] that can then be connected to an antivirus. Traditionally that's Windows Defender, [23:18.140 --> 23:23.400] but also McAfee and others tie into AMSI and rely on its detection capabilities [23:24.040 --> 23:30.960] for seeing malicious things going on in memory. And it's also processing... the big advantage [23:30.960 --> 23:37.200] of AMSI is that it's processing the commands at as low a level as possible before it enters into [23:37.200 --> 23:42.500] the script engine. So a lot of obfuscation that is put in place is removed before AMSI [23:42.500 --> 23:48.140] even looks at it. And this is just a diagram of how that data flows through those layers. [23:50.980 --> 23:59.040] So as I said, it evaluates commands at runtime. So if you were to use XOR encoding or secure [23:59.040 --> 24:03.500] string or some of those other obfuscation techniques that you might see out there, [24:03.500 --> 24:08.860] that obfuscation has to be removed before it can go into the scripting engine because the [24:08.860 --> 24:13.620] scripting engine doesn't know how to translate a secure string or an XOR encoded string [24:13.620 --> 24:19.430] into commands that it knows how to read. So it helps us identify fileless threats. [24:20.100 --> 24:25.500] And as I mentioned previously as well, as of .NET 4.8, it is integrated into the common [24:25.500 --> 24:29.280] language runtime, which is what PowerShell and all these scripting languages are actually [24:29.840 --> 24:35.540] decompiled or compiled into the common language infrastructure that's ran in the common language [24:35.540 --> 24:41.820] runtime. So they actually all end up running in the same area. And now C Sharp also uses the [24:41.820 --> 24:47.880] common language runtime. And so AMSI has been integrated at that lower level to account for [24:47.880 --> 24:53.120] some of the other languages that it didn't initially account for. So AMSI is actually [24:53.120 --> 24:57.700] pretty powerful. And we'll talk... we've got a couple examples that we're going to go through [24:57.700 --> 25:03.620] here. One that Anthony will talk to more when we get to the obfuscation stuff. But this is just [25:03.620 --> 25:11.680] what a standard Empire implant looks like when you put everything in. And if we just make some [25:11.680 --> 25:15.800] changes on the structure of the code, it still goes through AMSI. Like it's still very, very [25:15.800 --> 25:23.460] heavily dependent on static signatures. So this is just our modified script. You know, we changed [25:23.460 --> 25:31.720] some variable names and changed some locations of where things were being done because some of the [25:31.720 --> 25:35.620] code was position independent. It just had to be ran before the end of the script. So we moved it [25:35.620 --> 25:42.300] around. And now it runs without issue. Well, this did run without issue. They are constantly [25:42.300 --> 25:47.820] updating signatures in this one. This specific implementation probably will not pass AMSI [25:47.820 --> 25:54.220] anymore. But when new AMSI signatures come out, it typically takes me about 30 minutes to an hour [25:54.220 --> 25:59.820] to be able to come up with a workaround for whatever they changed for the detections. [25:59.820 --> 26:04.320] It might be... it's worth us also pointing out that we get a lot of questions all the time [26:04.320 --> 26:08.500] since we do a lot of work on Empire of, you know, why don't you keep the signatures up to date [26:08.500 --> 26:14.800] constantly? So that way it's always avoiding AMSI and Microsoft and all the defenses that are out [26:14.800 --> 26:19.300] there. And it's really just a cat and mouse game at the end of the day. So if we go and update it, [26:19.300 --> 26:24.220] it's going to take them, you know, hours to get the new signatures updated. And then whatever [26:24.220 --> 26:29.620] all the work that we just did is now worthless. So for us, it's easy for us to easily make these [26:29.620 --> 26:34.740] changes and do it, but not publish it out there. So that's just something that we see a lot. And [26:34.740 --> 26:39.600] we get a lot of questions asked of just why we're not making these changes on the releasable stuff [26:39.600 --> 26:45.800] for Empire. And if you are interested in learning more about the obfuscation stuff, we do have like [26:45.900 --> 26:52.560] a YouTube video up on that goes like... it's about three and a half hours of how to [26:52.560 --> 26:57.020] bypass AMSI and avoid it. So there's plenty of information out there. [26:57.660 --> 27:02.280] So now we're going to talk about script block logging. It was first introduced in PowerShell [27:02.280 --> 27:07.460] version 4, but it was fairly rudimentary at that time. Version 5 introduced what Microsoft calls [27:07.460 --> 27:13.080] deep script block logging. What that means is that it follows the execution down through multiple [27:13.080 --> 27:20.740] levels, which we'll talk through in a second on these images. And then it's event ID 4104, [27:20.740 --> 27:26.180] if you go look at the PowerShell operational log in Event Viewer. During our demo, I'm going to go [27:26.180 --> 27:31.400] over a little more how you can find the Event Viewer and what's in those logs and how we can [27:31.400 --> 27:37.060] look at them and that kind of stuff. But for now, if you look over on the image on the left, [27:37.430 --> 27:47.100] the first six lines there are defining a function called super decrypt that is removing the XOR [27:48.100 --> 27:54.320] encryption of a string and then returning that string in Unicode. Now, if we go down to the [27:55.530 --> 28:06.340] next line, it's going to decrypt that string there, store it into a variable, [28:06.340 --> 28:11.600] and then they're going to use invoke expression to execute that decrypted string. And we won't [28:11.600 --> 28:17.300] see it on the transcription log, we just see what is entered into the command line. But if we go [28:17.300 --> 28:22.600] over and look at the script block logs on the right over here, we can see the first one where [28:22.600 --> 28:29.740] we defined our function. The next one down is you're running that decrypted equals super decrypt [28:29.740 --> 28:35.460] to run our function. Walk down to the next line, where you see invoke expression of the decrypted [28:35.460 --> 28:41.300] variable. And then this is where that kind of deep script block logging and following the things [28:41.300 --> 28:48.540] down becomes powerful for AMSI. After all of that, we see that what was actually executed [28:48.540 --> 28:55.720] from that encrypted string is that write host pwned. So that is like why AMSI is powerful, [28:55.720 --> 28:59.580] is even though we had this function that we didn't really know it was going on with like [28:59.580 --> 29:04.600] bytes and counter and all that stuff, and decrypting this XOR string that we couldn't [29:04.600 --> 29:10.480] see into, we still see what's executed by invoke expression at the end. And that's what makes [29:10.480 --> 29:15.200] AMSI power or script block logging powerful. But we'll talk about some ways that you can actually [29:15.200 --> 29:26.300] obfuscate the script block logging in a little bit later. So module logging, it was introduced [29:26.300 --> 29:32.840] in PowerShell version 3, and I think is the most powerful part of the PowerShell logging [29:32.840 --> 29:37.100] capabilities. It does have some issues in implementing and building proper signatures, [29:37.100 --> 29:44.780] because it does report each module individually. But it's nearly impossible to hit the log without [29:44.780 --> 29:50.480] being unobfuscated. I say nearly impossible because maybe someone knows a way of doing it, [29:50.480 --> 29:54.160] but I have never been able, I've never seen or been able to figure out a way [29:54.760 --> 30:01.040] where you can not hit this log unobfuscated. If you look over at that image on the right, [30:01.040 --> 30:08.080] that kind of setter block, the first line will say like command execution, or sorry, [30:08.080 --> 30:13.540] command invocation, new object, and it shows new object. That's telling us what module is being [30:13.540 --> 30:19.560] ran, which commandlet. And then the next line down, you know, says parameter binding. And then [30:19.560 --> 30:24.480] if you go all the way over to the right, it says value. And that is what is being passed to the [30:24.480 --> 30:30.960] commandlet. And that value is always unobfuscated from what I've seen. If someone knows of a way [30:30.960 --> 30:38.060] obfuscating this, I'd be really interested in hearing about it afterwards. But that's why it's [30:38.060 --> 30:44.160] so powerful, is the values being passed in as arguments for commandlets are always unobfuscated. [30:44.160 --> 30:50.780] But it produces a whole lot of alerts. FireEye went and did a study when some of this came out, [30:50.780 --> 30:56.240] and running invokeMimikatz, just that, nothing else going on on the network, [30:56.240 --> 31:03.240] running just invokeMimikatz produces 2,280 events, generating seven megabytes of logs [31:03.240 --> 31:09.320] from just running that one script. So as you can see, that generates a lot of data and a lot of [31:09.320 --> 31:15.980] events that we have to sort through to be able to build efficient signatures and not just have [31:15.980 --> 31:26.320] this data for after the fact. So PowerShell logging would make for a bad day for red teams [31:26.320 --> 31:32.900] if organizations actually use it properly. But unfortunately, we have a bunch of things that are [31:32.900 --> 31:38.440] in the operational world that are, you know, making that more difficult. You see alert fatigue, [31:38.440 --> 31:44.080] you know, administrators are using sketchy scripts. I've been to a Fortune 500 company where [31:44.700 --> 31:50.120] when we went and looked at the local logs on the machines, their EDR was interfacing [31:50.120 --> 31:58.720] with AMSI. And each individual machine was producing like 100 alerts every two or three [31:58.720 --> 32:05.740] hours because the admins had a script they were using for automation that was running every couple [32:05.740 --> 32:09.140] of hours to make sure all the baselines for everything was staying, but it was doing something [32:09.140 --> 32:15.060] sketchy that was triggering the EDR to say it was bad. And so basically they had all the alerts set [32:15.060 --> 32:21.540] to information only and the EDR wasn't doing anything to kill the PowerShell when it was [32:21.540 --> 32:26.840] being flagged as bad because the administrators didn't want their scripts being killed. And you [32:26.840 --> 32:35.940] now have your SOC dealing with just, you know, thousands of alerts every day that they know are [32:36.680 --> 32:41.500] not really alerts because it's just the admin guys. And, you know, the admin guys update their [32:41.500 --> 32:48.820] stuff so they don't necessarily have a good way of automatically knowing or automatically filtering [32:48.820 --> 32:52.860] out those admin scripts, although in an ideal world they would be able to do that. And then [32:52.860 --> 32:58.680] deep script block logging can result in multiple alerts for a single script execution. Again, [32:58.680 --> 33:04.780] FireEye was testing with invoke-mimikatz and it produced 116 events totaling five megabytes when [33:04.780 --> 33:09.360] you use just the standard script block logging settings. Script block logging actually has an [33:09.360 --> 33:14.280] additional setting that you can turn on that it has it record start and stop events for [33:14.280 --> 33:18.760] loading different modules and executing pieces of code and that kind of stuff. And when you [33:18.760 --> 33:25.120] enable that, your logs jump to 96,000 events totaling 50 megabytes of logs for running one [33:25.120 --> 33:32.480] script. And then on top of all of that, bypasses are still effective because things like script [33:32.480 --> 33:38.040] block log bypasses or AMSI bypasses that we'll talk about in a little bit are not considered [33:38.040 --> 33:46.180] as crossing the security boundary by Microsoft because it's all operating on its own process. [33:46.180 --> 33:51.800] And since it's the owner of that memory space for the process that it's working in, [33:51.800 --> 33:57.700] it's not breaking any boundaries because if it turns it off for itself, then there's no way [33:57.700 --> 34:07.470] to prevent it from doing that. So this is just a quick overview of kind of what Mandiant says. [34:07.470 --> 34:14.630] Should they recommend for doing logging? They say if you can to enable module logging, [34:14.630 --> 34:19.170] script block logging, and transcription. We didn't really talk about transcription because [34:19.170 --> 34:24.150] it's fairly straightforward. All it is, is recording what is written out on the command [34:24.150 --> 34:29.570] line. And it doesn't include... that's all it includes. It's just be... it's a replay [34:29.570 --> 34:35.430] or a text version of what was typed into... what you see as you're typing into the command line. [34:36.190 --> 34:41.550] And they say the unique data is recorded by each source. And then this is kind of the takeaway I [34:41.550 --> 34:46.630] like to point out to people when we... when everyone says like, oh, logging is like, you know, [34:46.630 --> 34:51.970] the end-all be-all for PowerShell. They say where log sizes cannot be significantly increased, [34:51.970 --> 34:57.530] only enable script block logging and transcription logging because it will cover most data. [34:58.430 --> 35:04.810] And module logging only buys you some. But as I talked about, we have some ways of obfuscating [35:05.430 --> 35:10.990] transcription and script block logging so that even if you do record that data without bypassing [35:10.990 --> 35:16.930] script block logging, you can't tell what's going on in the scripts. And then module logging is [35:16.930 --> 35:23.170] basically impossible to hit unobfuscated. So it provides much better insight, in my opinion, [35:23.170 --> 35:27.350] but does produce a whole bunch of data. And because events are individual, correlating [35:27.350 --> 35:32.870] them becomes harder. So now we're going to talk about why it's still really effective [35:32.870 --> 35:38.450] for red teams and APTs to still go after this stuff, you know, mitigating the mitigations. [35:38.810 --> 35:44.650] We'll go over a little bit of AMSI bypasses, some obfuscation, like standard obfuscation. [35:44.650 --> 35:51.110] What we refer to as keyword obfuscation, which is kind of doing some minimal obfuscation [35:52.070 --> 35:59.030] to bypass AMSI because heavily obfuscated scripts can be a flag in and of themselves. We'll talk a [35:59.030 --> 36:03.950] little bit about script block logging bypasses and then event tracing bypasses. Those will be [36:03.950 --> 36:12.390] primarily in the demo. So reflective bypass. It's the simplest bypass that currently works. [36:12.390 --> 36:19.790] It grabs the systemmanagement.automation.amsi.utils.dll. It grabs a reference to it and [36:19.790 --> 36:27.450] then changes a field that says AMSI init failed and sets it to true. So why this works is when [36:27.450 --> 36:33.770] they were incorporating AMSI into PowerShell, they decided that if there was an issue with [36:33.770 --> 36:38.590] AMSI starting up rather than just killing PowerShell, not allowing PowerShell to run [36:38.590 --> 36:45.590] if AMSI couldn't run, that it was better to basically fail safe and just have AMSI [36:46.330 --> 36:49.990] ignored by PowerShell so that the PowerShell tools could keep working. [36:50.530 --> 36:55.690] So when we're reflectively setting this field, we're saying that the initialization of AMSI [36:55.690 --> 37:01.930] failed. So just go ahead and return a clean finding regardless of what was actually done. [37:02.190 --> 37:06.170] And it doesn't even bother scanning the code. It just says there's something broken with AMSI. [37:06.170 --> 37:11.210] So we're just going to tell Defender that everything's fine in terms of malicious content [37:11.210 --> 37:14.810] because we don't know what's broken and we don't want to stop PowerShell from running. [37:14.810 --> 37:19.670] And then it's also just kind of cool because Matt Graber originally posted this in a tweet [37:19.670 --> 37:25.850] all the way back in 2016 and still works. So a more complicated bypass we can look at, [37:25.850 --> 37:33.030] and there's a bunch of different implementations floating around. This is one I wrote based off [37:33.030 --> 37:39.470] of Tal Lieberman's work that he published at BlackHat. Rostamaus has a very similar one [37:40.230 --> 37:45.530] implemented, as well as there's a few other places you can find ones that are based off of this [37:46.410 --> 37:53.750] off of this patching of the actual AMSI DOL in memory. So this is using some [37:54.970 --> 38:00.870] a C-sharp to export DOL functions to allow us to access some areas of memory. [38:01.410 --> 38:08.430] And then we are patching when AMSI goes to return the results, there's actually a numeric [38:09.610 --> 38:16.510] value that it measures to define your risk rate. And if it's over x amount, that's considered bad. [38:16.510 --> 38:22.950] If it's under x amount, then it's considered mostly good. And if it's a zero, it's considered [38:22.950 --> 38:27.670] good. Basically, you never see zero returned in real life. And you actually never see the [38:27.670 --> 38:33.650] different values with the actual value of your script rows, because when it returns the value, [38:33.650 --> 38:37.410] defaults it to one of those three. There's actually a couple others for [38:37.970 --> 38:42.890] policy implementation issues. But those are the three returns if it's just scanning your [38:42.890 --> 38:47.790] code without outside influence. And what this does is it patches it to always return that the [38:48.530 --> 38:53.090] code was good regardless of what the comparison finds of what the value actually came out from [38:53.090 --> 39:02.610] AMSI. It says just return a good value from the comparison and say that the script is fine. [39:02.610 --> 39:10.190] And so all of these work because AMSI is loaded as part of the memory space that our process is in, [39:10.190 --> 39:14.190] which means that we have unrestricted access to the memory space that we're in. We can modify it [39:14.190 --> 39:21.670] however we please. And so the reflective DLL tells AMSI to return a clean result prior to scanning [39:21.670 --> 39:26.570] it. And as I mentioned, the patched one tells it to return after it being scanned. [39:28.350 --> 39:33.070] So obfuscation, going in kind of a different direction with that, is taking that code that [39:33.070 --> 39:39.210] we've established and adding some more noise in there to kind of hide what we're doing. [39:39.310 --> 39:43.970] It's still very, very effective, but it does come with some costs. One of those being the [39:43.970 --> 39:47.990] complexity of your payload. Your payloads will become really, really complex and they'll add [39:48.150 --> 39:51.290] a lot of size to them because you're going to be running a bunch of different techniques. You may [39:51.290 --> 39:58.770] be encoding it on top of changing variable names and splitting things up. So you can easily exceed [39:59.350 --> 40:03.730] limits that are put in place by PowerShell on the size of a command. It also takes a lot of [40:03.730 --> 40:08.030] time to be able to encode these. So if you're running every command that's being sent across [40:08.030 --> 40:14.030] your C2 framework as obfuscated, there's going to be a delay there. Now that may not be a big deal [40:14.030 --> 40:17.670] to some people, but depending on what you're trying to emulate, that actually could be a big deal. [40:17.670 --> 40:21.850] Then, as Hubble talked about, some of the defenses that are in place, if they take all that [40:21.850 --> 40:25.910] obfuscation and they wait till the very end, they may be able to detect whatever you're trying to do [40:25.910 --> 40:32.910] at the very end because obfuscation helps you in breaking up signatures and dividing things up. So [40:32.910 --> 40:37.390] that way they might not be identified, but if they're waiting to the end to run their analysis, [40:37.390 --> 40:44.670] you may get caught. Here's just an example of some unobfuscated and obfuscated code for a [40:44.670 --> 40:52.190] launcher for Empire. The left one just shows the basic payload without any obfuscation in it. [40:52.190 --> 40:57.890] The right one has just the standard token all obfuscation set in place. And what it does, [40:57.890 --> 41:02.670] you can see here, it starts breaking things up. It starts encoding things. This right here actually [41:02.670 --> 41:06.370] won't get past AMSI, the way it's currently implemented, just because of the way token all [41:06.370 --> 41:11.630] does some of its things. I'm sure Hubble will want to chime in a little bit on that. But the [41:11.630 --> 41:16.130] important part, though, is really seeing how it actually encodes this and the big red flags [41:16.130 --> 41:23.390] that defenders would actually see if they saw this in their logs. Yes, so token all, the way [41:23.390 --> 41:30.790] it's implemented in invoke obfuscation, is a pseudo-randomized implementation of a bunch of [41:30.790 --> 41:38.050] various different obfuscation techniques. And it has kind of two issues. One, it's pseudo-random. [41:38.050 --> 41:44.750] At this point, invoke obfuscation has been out for a very long time. And all of the randomization, [41:44.750 --> 41:49.750] or all of the combinations for those six techniques that it has, are fairly well known [41:49.750 --> 41:54.970] at this point. And then there's also some issues with certain techniques interfere with each other [41:54.970 --> 42:01.250] if they're ran in the wrong order. So sometimes you run into issues with that in invoke obfuscation [42:01.250 --> 42:08.410] running token all, as it might run... you see some of the stuff where it's broken things up [42:08.410 --> 42:14.610] into a bunch of string numbers. And when it does that, it then can't search for commands to [42:14.610 --> 42:18.730] replace the name of the command, because that's already been broken up, so it can't find it. [42:18.930 --> 42:23.190] So some of these things work better if you run them in specific orders. And invoke [42:24.290 --> 42:28.410] obfuscation's token all doesn't always do that. So that's just some of the limitations on it. [42:28.410 --> 42:33.310] And just having those custom cocktails of different obfuscation techniques make a big [42:33.310 --> 42:39.030] difference. I know we have a couple that we keep for ourselves that seem to work almost all the time. [42:40.650 --> 42:45.250] So the obfuscation really does get you about 90% of the way there. Like I said, [42:45.250 --> 42:49.810] those custom cocktails that we have really do get us most of the way there. But there's some [42:49.810 --> 42:53.510] things that you just can't get rid of when you're obfuscating. And those are just like those common [42:53.510 --> 42:58.970] signatures that require you to restructure the code or eliminate certain keywords. One of the [42:58.970 --> 43:04.470] really good examples was something that we saw last year with the original Empire project. Prior [43:04.470 --> 43:10.730] to version 3, there was actually a mistake inside of the code where it double appended one of the [43:10.730 --> 43:15.650] headers. This allowed signatures to be based off of that issue, because it couldn't be obfuscated [43:15.650 --> 43:21.450] away. So any virus and AMSI and everything was detecting off of this specific mistake in the [43:21.450 --> 43:26.170] code. So just removing that and then rerunning the obfuscation with a slightly different technique [43:26.170 --> 43:31.870] allowed the payload to get through completely undetected. So really, that restructuring [43:31.870 --> 43:36.510] and making sure that those signatures are broken is really, really important. [43:36.590 --> 43:42.570] So now we're going to talk a little bit more about what we kind of call keyword aliasing. [43:42.730 --> 43:49.190] AMSI can search in memory for specific terms and that kind of stuff that are automatically [43:49.190 --> 43:55.350] flagged as bad or raise your threat level really high. And these can be triggered even when not [43:55.350 --> 44:02.510] ran directly by AMSI. For instance, if you run a PowerShell script as Base64 encoded [44:03.170 --> 44:08.550] and AMSI does not flag it as malicious, it still sees that as a very suspicious activity. [44:08.550 --> 44:13.890] So then it starts searching strings in memory, or Defender starts searching for strings in memory. [44:13.890 --> 44:18.750] And specifically, it'll actually do this even when AMSI has been disabled, because Defender [44:18.750 --> 44:22.710] is seeing that as an inherently suspicious activity and Defender goes and looks for it as [44:22.710 --> 44:28.690] well. So getting rid of these strings in memory becomes really key to getting our code through, [44:28.690 --> 44:34.850] especially in allowing us to not heavily obfuscate everything all the time, which increases our size [44:34.850 --> 44:38.830] and the amount of data we have to transfer and all that kind of stuff. Some of these [44:38.830 --> 44:46.450] strings to keep in mind are actually invokeMimikatz, invokeEmpire, powersploit. [44:47.010 --> 44:51.570] It's not in here, but another one that doesn't necessarily get you flagged as malicious but [44:51.570 --> 44:56.970] generates a warning-level event in your logs, which means that it thinks it's highly suspicious [44:56.970 --> 45:01.810] and would be a trigger for someone to potentially go look at, is if you're using an assembly and [45:01.810 --> 45:09.290] use .getField. GetField is, in and of itself, a string that gets triggered as a warning-level [45:09.290 --> 45:15.310] event and will go cause higher-level logs to be produced. Even if script block logging is off, [45:15.310 --> 45:22.630] that string will cause a script block log to be saved, even when script block logging is disabled. [45:22.710 --> 45:27.290] So if we change those terms, then we can make it really hard to detect us, because [45:27.950 --> 45:32.230] if we change all the references in our script, there is nothing to de-obfuscate it from. [45:32.230 --> 45:37.530] It just becomes that is the value that we are using. So in the example over on the right, [45:37.530 --> 45:47.210] we're changing InvokeMemeCats to QAD45 and InvokeEmpire to DLXZ9. This is how it's done in [45:47.210 --> 45:53.410] Empire now. On startup, it automatically makes entries to obfuscate those strings. If you really [45:53.410 --> 45:58.170] want to be even stealthier, instead of changing it to just kind of these random letters and numbers, [45:58.170 --> 46:02.430] because if you looked at a log, that would be kind of weird that someone's using a function name [46:02.430 --> 46:07.270] that's completely random, because what legitimate programmer would be using a completely random [46:07.270 --> 46:13.970] name? You could make these something like InvokeFileSearcher, InvokeOrganizer, so that [46:13.970 --> 46:18.810] it would look even less suspicious than just a random string. We don't do this to everything [46:18.810 --> 46:25.650] for a couple of reasons. You could do it, but it's time consuming to pick which values to alias. [46:25.650 --> 46:30.090] And then it also requires us to put in a lot of entries into the database, [46:30.090 --> 46:35.150] and that makes it just harder to track, because everything we want to alias has to be tracked [46:35.150 --> 46:39.090] individually. And we have to make sure it's being applied across all of our scripts, because if we [46:39.090 --> 46:47.030] had a reference in a script in one place and ran it outside of Empire, and it was looking for [46:47.030 --> 46:51.290] something that Empire had aliased, or we had aliased by hand, and those don't match anymore, then your [46:51.290 --> 46:55.550] stuff's going to break. So there's just some complexity added in the aliasing. And then, as we [46:55.550 --> 47:01.290] mentioned, heavy obfuscation can be a flag in and of itself, so we want to minimally obfuscate where [47:01.290 --> 47:10.810] we can. So here's a new... I have not seen this on open source stuff yet that I've been working on [47:10.810 --> 47:16.410] that's pretty fun to play with. You can actually import to avoid script logs, as well as the [47:16.410 --> 47:21.510] transcription log as well. ImportAlias is the one I've been playing with the most. [47:21.510 --> 47:28.170] What happens is, when we import our aliases, for those that don't know, let me take a step back. [47:28.170 --> 47:35.510] Aliasing, in terms of PowerShell, allows us to set whatever function name we want for any [47:35.510 --> 47:41.610] commandlet. So the get command, or get printer, write host, any of those, we can say [47:41.610 --> 47:50.750] set alias and change it to print instead of get printer. And then, whenever you type in [47:50.750 --> 47:57.490] print into PowerShell, it knows that that is the same as doing get printer. [47:58.890 --> 48:06.230] You can then save those aliases using ExportAlias. And then, when you import alias, [48:06.230 --> 48:13.570] those terms and different names for your commandlets never get seen by the log. [48:13.570 --> 48:18.890] They just get imported into memory. You can now run the command with the name that you gave it, [48:18.890 --> 48:24.090] and on the script block log, that's all it sees. It'll see print instead of get printer. [48:24.310 --> 48:30.990] If you have module logging enabled, then it will still see the module you're using. [48:31.290 --> 48:37.810] And so, ImportAlias does not get you around module logs, although the module logs will not [48:37.810 --> 48:41.970] see the values in ImportAlias, which is kind of interesting. But as we said, [48:41.970 --> 48:45.670] it's basically impossible to avoid hitting the module logging initially. [48:47.570 --> 48:53.510] So, this is kind of what it looks like to change things up. On the right is if I want to do [48:55.250 --> 48:59.250] InvokeExpressionNewObjectSystem.net.webClient. That's what it would look like. That's what it [48:59.250 --> 49:05.670] would look like in the logs. Instead, to run that, I went and did some aliasing by hand. [49:07.170 --> 49:14.830] And we can embed further commands into the alias description. And if you look at the [49:14.830 --> 49:23.890] import.alias.csv, that imported all of my alias commands. Now I run this completely [49:23.890 --> 49:30.350] nonsensical command to someone looking at it that says I parentheses ca.description. [49:30.970 --> 49:41.390] And then that caused another execution that was bcb.description. So, in this case, I was [49:42.190 --> 49:49.790] was InvokeExpression. And b was that new object. And then the description for new object was [49:49.790 --> 49:57.050] system.net.webClient. And so, I ended up achieving the same thing with this totally nonsensical [49:57.050 --> 50:03.250] script block log that there's no way for a defender to go figure out what that actually means. [50:03.250 --> 50:08.930] Because as soon as you close the PowerShell session, the aliasing is gone. It is not saved [50:10.210 --> 50:15.830] saved permanently anywhere. So, you have to import. If you want to use aliases consistently, [50:15.830 --> 50:19.090] you have to import them each time you start a new PowerShell session. That's why the [50:19.650 --> 50:25.530] function was built. So, as soon as we kill our PowerShell session, our aliasing is gone. And [50:25.530 --> 50:30.810] the key to what the script block log means is gone as well. Now we're going to go into demo [50:30.810 --> 50:35.870] where I'll talk a little bit about more the event viewer and how to look at the PowerShell logs, [50:35.870 --> 50:44.410] as well as show the script block log bypass and the event tracing bypass that is used by [50:44.410 --> 50:48.550] the disables module logging in conjunction with all the other PowerShell logging. [50:51.250 --> 50:57.110] First things first, how you get to the operational log for PowerShell is you're [50:57.110 --> 51:01.710] going to use event viewer. You're going to come down here and type in event viewer. You want to [51:01.710 --> 51:06.690] make sure you run it as an administrator. That just makes it easier to clear the logs when you're [51:06.690 --> 51:11.210] testing that kind of stuff. But you can't usually view it even as an unprivileged user. You just [51:11.210 --> 51:22.170] can't modify it. You'll then click on Microsoft, then Windows, then come down here to PowerShell, [51:22.170 --> 51:28.850] open PowerShell, and then click on operational. Right now I cleared the logs prior to starting [51:28.850 --> 51:33.570] this so that we can make it easier to see everything. So, if I go ahead and click on [51:33.570 --> 51:40.290] PowerShell and open it, it's actually just starting PowerShell generates some logs. [51:43.050 --> 51:48.810] As you can see here, we get these event IDs showing startup, as well as it looks like [51:48.810 --> 51:53.250] my computer was a little slow. So, if I refresh it again, we should get a few more. Yeah, there we go. [51:53.690 --> 51:59.230] So, you'll see this verbose prompt and script block logging that is just a default that always [51:59.230 --> 52:04.230] gets generated when PowerShell starts up and after each command. Then we'll see this strict mode that [52:05.030 --> 52:11.950] gets used throughout when you're running PowerShell. But as you can see, this one's 4104, [52:11.950 --> 52:17.290] which is our script block logging, and then we have 4103 is our module logging. [52:18.190 --> 52:27.050] If I go up and run just this right host test as our kind of test subject, we can come back over [52:27.050 --> 52:33.830] and refresh our logs, and we'll see a couple of new entries in here. As I said, prompt comes up [52:33.830 --> 52:39.430] after every execution. But if we go down here, we can see this right host test for our script block [52:39.430 --> 52:48.510] log in 4104. And then we can see this module logging where we get the command invocation [52:48.510 --> 52:54.970] for right host, as well as the value that was passed, which was our string of test. [52:55.590 --> 53:01.210] So, now we're going to go over here, now that we've seen that. And the first one we're going [53:01.210 --> 53:07.910] to talk about real quick is script block logging. This was published by Matt Graber. It's got a few [53:07.910 --> 53:14.230] modifications from his original one, but this comes from a default Empire implementation. [53:14.230 --> 53:22.550] All it's doing is it's creating a new dictionary that gets added to our cache group policy [53:22.550 --> 53:27.050] settings. We access that reflectively, and we're just telling it that script block logging has [53:27.050 --> 53:32.070] been turned off when it goes. So, when PowerShell goes to check if it's supposed to be recording, [53:32.070 --> 53:36.750] it sees that the value is set to zero, which means it's not supposed to be recording script block [53:36.750 --> 53:42.810] logging. We're able to do this because, just like the AMD bypass, this is all in our process [53:43.870 --> 53:50.250] memory. So, we have complete access to it. We can manipulate in essentially whatever way we want. [53:51.290 --> 53:56.150] So, if I go drop this in here, like so, and we hit enter, [53:57.430 --> 54:03.270] we will generate a bunch of new events because we haven't disabled it yet. So, all of that code [54:03.270 --> 54:11.130] that we just ran is going to hit our script block logging. And so, we go up here, and we can see [54:11.130 --> 54:17.130] that our script block was ran with all of our different values. Then we get our out default, [54:17.130 --> 54:23.570] which is the module when output is sent to the command line, and then some other ones. And since [54:23.570 --> 54:28.650] script block logging is using an assembly, that doesn't actually generate any module logging [54:28.650 --> 54:36.490] because it's obviously not a module. But now, if we go back up to here, and I do our write host test, [54:36.490 --> 54:41.870] we will still generate a new event because module logging is on, and we haven't bypassed that. [54:43.090 --> 54:50.030] But if you go look here, as you can see, the last script block log, that 4104, [54:50.030 --> 54:57.230] was our disabling a script block logging, and now all we have is module logging, which occurs here [54:57.230 --> 55:06.090] with our write host in our test string. So now, the other nice part about this is that [55:06.090 --> 55:10.510] only affects our local process. So, if I just close out PowerShell and clear our logs, [55:11.930 --> 55:21.450] we will reset everything. So we're going to go ahead and clear, and then when we go, if I open [55:21.450 --> 55:30.910] it again, we're now going to use a event tracing bypass that was published about the same time, [55:30.910 --> 55:35.210] actually, as the script block logging one. It just never really got a lot of traction. [55:35.890 --> 55:42.730] It's, I believe it's linked in our slides. If not, I have the link for everyone that I can share. [55:42.990 --> 55:48.670] And all we're doing is it's very similar to that script block logging bypass, where we're getting [55:48.670 --> 55:54.410] access to a table that PowerShell is checking to see what it's supposed to be doing for logging. [55:54.710 --> 55:58.950] But instead, we're disabling event tracing, which happens at a lower level. [55:58.950 --> 56:06.250] This event tracing actually disables our module logging as well. So we run this, [56:07.030 --> 56:11.150] and we go look at our logs. [56:13.110 --> 56:17.770] And we'll see that we get a warning level event. This is because of some of the strings [56:18.470 --> 56:24.910] that we mentioned during the briefing, like the get field string, as well as some of these [56:24.910 --> 56:30.070] non-public static and those kinds of things will automatically generate a warning level event, [56:30.070 --> 56:34.810] which means this would actually produce a log even if script block logging wasn't explicitly [56:34.810 --> 56:38.950] enabled. So we ran this, but as you can see, we don't have any of those standard, [56:38.950 --> 56:45.990] like the prompt logging or this out default that's normally there. And if we go run that [56:49.330 --> 56:57.790] right host test again, we can see that we have had produced no logs. So we still have viable ways [56:57.790 --> 57:04.270] of totally disabling PowerShell logging. And like I said, there are ways to get this down, [57:04.270 --> 57:08.670] so it won't produce a warning level event. And then the last thing I was going to show you guys [57:08.670 --> 57:13.770] real quick is just that import alias thing we talked about. I was just going to show it to you [57:13.770 --> 57:23.210] real time. So we'll go ahead and clear the log. Open PowerShell back up again. [57:27.010 --> 57:31.110] We're just going to go ahead and import our alias.csv. [57:33.210 --> 57:39.530] I'm going to go ahead and run this nonsensical looking thing. As we can see, it gives us an [57:39.530 --> 57:47.130] output that a new web request object was created. So now when we go look at our logging, [57:52.030 --> 57:56.950] we can see a couple of different script block logs were called. So I called this [57:59.210 --> 58:05.310] ICA.description initially. And this is where we can see that it's still hitting our module [58:05.310 --> 58:17.750] logging. Even the script block logging can't see it. It appears that C is aliased to get command, [58:17.750 --> 58:21.890] as we can see here. I'm looking through that. But as you can also see, it's a little hard to [58:21.890 --> 58:27.570] correlate exactly what's going on and figure out what called this module without some in-depth [58:27.570 --> 58:34.430] analysis of what's going on. So we have this value A that gets passed to it. Then we see it execute [58:34.430 --> 58:42.990] this bcb.description, which again is a git command. And then we also see that we're executing [58:43.170 --> 58:51.110] a new object that was being passed a system.net web client. And so that just shows you module [58:51.110 --> 58:56.730] logging is kind of effective at bypassing this import aliasing thing. But the import aliasing [58:57.810 --> 59:02.970] totally obfuscates logs in a way that you can't really undo it. And the other nice part is when [59:02.970 --> 59:08.190] you import alias, the whole reason that you can import and export aliases is that they are not [59:08.190 --> 59:13.970] persistent between sessions. So when we close out PowerShell, all of our aliasing key is gone, [59:13.970 --> 59:20.570] so they can't go look it up. So it's just another level of obfuscation. And it also makes it really [59:20.570 --> 59:25.290] hard for Amzie to see what's going on. So that's just something kind of fun to play with. But [59:25.290 --> 59:29.930] that's all I got. So I'll toss it back over to Anthony. And we should have just a little bit [59:29.930 --> 59:34.450] of time left. Thanks for having us at the Red Team Village. We're going to be in the channel [59:34.450 --> 59:36.010] for a little bit to answer any questions.