WEBVTT

00:00.000 --> 00:05.180
Welcome to my talk, broadcasting from my quarantine bunker to yours.

00:05.260 --> 00:12.520
My talk is Yippee-ki-yay MFA-er, bypassing multi-factor authentication with real-time replay session instantiation attacks.

00:13.600 --> 00:15.960
So before we get started, I'll go ahead and introduce myself.

00:15.960 --> 00:17.220
My name is Hutch.

00:17.220 --> 00:20.460
I am the consulting services practice lead at a company called Set Solutions.

00:20.460 --> 00:29.520
I lead our government's risk and compliance, cyber incident response, threat hunting, penetration testing, and red teaming operations at the company.

00:29.520 --> 00:35.480
I have a master's in information systems and multiple different certifications on both the blue and red team side.

00:35.620 --> 00:46.580
I got into information security in the United States Air Force, did many years of consulting, went in industry for about three years into the financial sector, and now back at the consulting game.

00:47.160 --> 00:51.900
Aside from my hacktivity interests, I do enjoy spending time with my family.

00:51.900 --> 00:58.300
I enjoy country life and getting away from the big city, algorithmic trading, and last but not least, street tacos.

01:02.060 --> 01:12.740
So when I got started in penetration testing and red teaming, I remember that it was fairly easy to breach the perimeter and gain unauthorized access to an organization's network using usually one of two different attacks.

01:12.740 --> 01:25.840
One was password spray attacks, where we would take a large number of different potential usernames and we would iterate through those usernames and attempt a common guessable password.

01:25.840 --> 01:38.140
And we would usually do this multiple times every few hours in order to prevent any user accounts from being locked out, but still attempting thousands of different password attempts every hour.

01:38.880 --> 01:51.640
The other attack that we would commonly use would be credential harvesting attacks, where we would send a phishing email to our different targets, and we would set up a fake evil twin replica site of their login portal.

01:51.640 --> 02:03.920
We would use that site to harvest their usernames and passwords, and then we would subsequently use those compromised credentials to log into the actual site and gain remote access to those networks.

02:05.540 --> 02:12.080
So the security industry's response to these types of attacks was multi-factor authentication.

02:12.400 --> 02:20.220
And by multi-factor authentication, the common understanding is that that's any combination of at least two of the following authentication factors.

02:20.220 --> 02:22.600
Something you know, such as a password.

02:22.600 --> 02:26.480
Something you have, such as a mobile device or a hardware token.

02:26.480 --> 02:29.100
Or something you are, such as biometrics.

02:29.380 --> 02:49.520
So the thinking was that even if an attacker was to gain usernames and passwords through credential harvesting attacks, or even if they were to perform password sprays against an external service, they would not be able to gain access to the network because there would still be that second factor standing in their way.

02:52.020 --> 03:07.120
So now things become a lot harder for red teamers these days because they can no longer easily perform those basic password sprays or those credential harvesting attacks in order to immediately gain access to a corporate network.

03:07.120 --> 03:13.980
Multi-factor authentication stands in the way and is better securing remote access services.

03:15.780 --> 03:19.260
Fortunately, not all hope is lost for the red team.

03:19.260 --> 03:24.260
When it comes to multi-factor authentication implementation, the right way is also the hard way.

03:24.260 --> 03:31.680
And what I mean by the right way is FIDO compliant UTF or universal second factor authentication.

03:32.180 --> 03:52.540
And this is a legitimate form of something you have because the hardware device that you use for UTF authentication does an actual cryptographic authentication sequence within the same authentication sequence that you are performing to access the remote service.

03:53.520 --> 04:02.880
Unfortunately, the overhead involved in supporting a UTF program at an enterprise level is extremely difficult for most organizations to achieve.

04:02.880 --> 04:08.400
So the reality is most organizations are doing multi-factor authentication the wrong way.

04:08.400 --> 04:18.080
And the two most common types of multi-factor authentication that we're seeing for remote access services are either one-time pass or push-based notifications.

04:18.220 --> 04:28.900
And the reason that I say that this is the wrong way is because in reality, if you look at the way that these two different authentication sequences are performed, it's not actual multi-factor authentication.

04:28.920 --> 04:32.720
You have the factor of something that you know, which is the username and password.

04:33.340 --> 04:38.900
And the assumption is with these two types of authentication that the second factor is something that you have.

04:38.900 --> 04:40.360
But in reality, it's not.

04:40.360 --> 04:48.600
Because with the one-time pass, while you do have possession of the phone, the phone is not the thing that's actually authenticating to the service.

04:48.680 --> 04:53.780
Instead, you look at that one-time password that's good for, say, 30 seconds.

04:53.780 --> 05:01.900
And within that 30 seconds, that becomes something you know, and then you supply to the access portal in the same way that you would supply your username and password.

05:02.080 --> 05:07.720
And so it becomes subject to the same types of attacks that those username and passwords are.

05:07.720 --> 05:09.920
Specifically, they are replayable.

05:10.380 --> 05:23.520
And the other type of multi-factor authentication, which is push notifications, actually doesn't even operate within the same sequence as the original authentication sequence to access that service.

05:23.520 --> 05:27.300
Instead, it's done completely out of band, and your phone just receives a notification.

05:27.300 --> 05:30.060
So it makes it very easy to bypass as well.

05:30.740 --> 05:43.300
So because most organizations are using one-time pass or push-based notifications, this makes it very easy for the red team to still bypass these remote access services and gain access.

05:43.580 --> 05:53.500
So for an example to demonstrate the types of attacks that we're discussing, let's consider a scenario of a life and a guy of a typical white-collar office worker.

05:53.500 --> 05:57.340
For the sake of conversation, we will call this office worker Dwight Schrute.

05:57.560 --> 06:12.480
And Dwight, like most white-collar workers, occasionally does work from home, and when he does, he has to access his corporate remote access service by using his username and password to access corporate resources like email, file shares, or VPN.

06:13.920 --> 06:21.020
Unfortunately, for Dwight, there are bad people in this world that seek to do harm to business organizations.

06:21.280 --> 06:38.760
So let's suppose, hypothetically, that we have a hardened cyber criminal that has sent an email to our office worker, and this email indicates that Dunder Mifflin is making an update on its servers and that it needs the employee to log in in order to ensure that their account is migrated properly.

06:38.960 --> 06:51.120
Because this email looks like legitimate email, Dwight Schrute then clicks the link and browses to what is actually an evil twin clone server hosted by the hardened cyber criminal.

06:52.180 --> 07:00.100
And because this server looks identical to the original server that Dwight is accustomed to log into, he then supplies its credentials.

07:01.100 --> 07:11.280
So those credentials are then forwarded to the attacker, and the attacker is able to use those to log in to the legitimate remote access service.

07:13.700 --> 07:18.700
And so, unfortunately, without multi-factor authentication, this leaves our employees vulnerable.

07:19.580 --> 07:29.100
This gets the attention of upper-level management, who then decides to call in the IT department to implement multi-factor authentication.

07:29.100 --> 07:36.640
And now, when Dwight logs in to his remote access portal, he doesn't just have to supply a username and password, but he also has to supply a token passcode.

07:38.560 --> 07:44.440
So multi-factor authentication saves the day, the fortress is impenetrable, and all of the hackers have given up, right?

07:44.740 --> 07:45.780
Not exactly.

07:46.360 --> 07:51.300
So now let's talk about how this attack can be performed in order to bypass that multi-factor authentication.

07:51.600 --> 07:55.700
So, similarly, we have our white-collar worker, the attacker that sends the email.

07:56.110 --> 08:03.000
The email looks exactly the same, and the victim then clicks the update account link,

08:06.130 --> 08:10.040
accesses the site, and, similar to before, enters his credentials,

08:13.230 --> 08:17.990
and this time to include his multi-factor authentication token.

08:21.400 --> 08:36.700
So then, upon logging in to the malicious evil twin site, instead of sending those credentials to the cyber criminal, the site replays them in real time while that one-time pass multi-factor authentication token is still valid to the actual server.

08:36.700 --> 08:45.960
This establishes a legitimate login session with the actual server, and the session token is then forwarded back to the attacker.

08:46.140 --> 08:58.520
The attacker is then able to use that session token in his browser in order to assume the compromised session, and thereby gain remote access to the legitimate remote access server.

09:00.980 --> 09:03.140
So, now let's look through a couple demonstrations.

09:03.140 --> 09:09.820
First, we're going to look through a way that we can use this type of attack to defeat multi-factor authentication on a common web service.

09:10.000 --> 09:20.400
And then we're going to look at a more unique scenario where we can use the same methodology in order to defeat multi-factor authentication using a binary remote access client.

09:23.910 --> 09:33.720
So, for the first scenario where we are attempting to bypass multi-factor authentication on a web service, the stack that we're going to use is Flask as our micro framework for our web service.

09:33.720 --> 09:42.260
We are going to use Apache to independently host the copied or replicated content from the legitimate remote access server.

09:42.260 --> 09:54.700
And then we are going to be using Selenium in order to emulate and execute browser operations that will allow us to replay those credentials and execute a login in real time.

09:57.420 --> 10:10.200
For this demo, I have used a Flask one-time pass multi-factor authentication proof of concept that was published by Miguel Grinberg, who does some fantastic Python and Flask stuff.

10:10.200 --> 10:12.300
And so, definitely worth checking out.

10:12.320 --> 10:23.460
But fortunately for us, it makes a convenient option to test different attacks on multi-factor authentication without having to do a full deployment ourselves.

10:23.460 --> 10:33.560
So , you can essentially just git clone this repository, run it through Python, and you will have a one -time pass multi-factor authentication portal that you can perform testing on.

10:33.560 --> 10:38.060
Of course, we did some slight cosmetic changes in order to fit with the theme.

10:43.770 --> 10:56.050
So , first we're going to look at how we can use Python and Selenium in order to execute real-time logins to the actual multi-factor authentication remote access service.

10:58.440 --> 11:08.980
So, the first thing that we're going to need to do in order to achieve the multi-factor authentication bypass is we are going to need to be able to programmatically log in to the actual multi-factor authentication service.

11:08.980 --> 11:10.520
So, we're going to do that with Python.

11:10.680 --> 11:16.840
And we're going to start with from Selenium import WebDriver.

11:18.220 --> 11:20.940
Then we are going to create an instance of WebDriver.

11:20.940 --> 11:24.760
So, driver equals WebDriver.firefox.

11:25.980 --> 11:30.020
And you should see a browser open in the graphical interface.

11:32.510 --> 11:35.230
And next, we're going to browse to the actual site.

11:35.230 --> 11:39.190
So, we will do driver.get and then the URL.

11:47.220 --> 11:53.760
It's worth noting that for this demo, I did modify my Etsy hosts file, and I do not actually own this domain.

11:53.760 --> 12:01.540
So, then what we want to do is we want to enter text values in each of these different parameters, username, password, and token.

12:02.000 --> 12:04.660
So, in order to do this, we're going to inspect the element.

12:05.540 --> 12:14.120
And here, you'll see the Firefox inspector, which shows you the HTML element and also shows you the ID for the element is username.

12:14.160 --> 12:22.860
So, in order to interact with it, we will just do driver.findElementById and then pass it that value, username.

12:23.480 --> 12:28.860
And then we want to send it the keys of the username we want to send.

12:28.860 --> 12:30.020
So, I'll put Hutch.

12:30.320 --> 12:34.120
And as you can see, it programmatically populates that field.

12:34.120 --> 12:37.300
We can then do the same thing for password by inspecting it.

12:37.520 --> 12:42.180
And here, we can see that the ID value for password is also password.

12:42.180 --> 12:56.880
So, we'll do driver.findElementById password, then send keys, and my password.

13:00.260 --> 13:02.620
And as you can see, it then populates the password field.

13:02.620 --> 13:04.440
And finally, for token, we can do the same thing.

13:04.440 --> 13:05.580
Inspect element.

13:05.720 --> 13:07.520
The ID is token.

13:07.940 --> 13:16.740
So, we can do the same thing, but this time, we'll make our token value 1, 2, 3, 4, 5, 6, and the ID is token.

13:19.700 --> 13:22.680
So, now that all the fields are populated, we just need to click the login button.

13:22.680 --> 13:26.380
So, we just right-click this and inspect element.

13:26.380 --> 13:31.740
And here, we can see that the ID value for that login button is the word submit.

13:31.840 --> 13:40.260
So, all we have to do is driver.findElementById submit.

13:41.220 --> 13:45.180
And then this time, instead of send keys, we'll use dot click.

13:48.820 --> 13:57.540
And as you can see, by the error returned, invalid username, password, or token, we were able to programmatically make a login attempt to the actual site.

13:58.040 --> 14:06.560
So, now that we've created our Selenium login script, we also need to create a replica of the site that we are attempting to gain remote access to.

14:06.560 --> 14:10.280
So, in order to make the replica website, we'll start by opening up a web browser.

14:10.280 --> 14:14.060
And then we will browse to the page that we want to clone.

14:21.760 --> 14:29.220
And then to save a recursive copy of the page, all you have to do is go over to the menu bar over here and do save page as.

14:30.920 --> 14:34.960
And this will save a full recursive copy of the website.

14:34.960 --> 14:40.080
If you want to drop it directly into your web root, browse to var www.html.

14:40.140 --> 14:48.340
And then even better yet, if you want it to be the web root index file, then you can just name this file as index.html.

14:49.180 --> 14:50.680
Then save.

14:53.220 --> 14:56.060
And then next, you'll want to go to that directory.

14:56.060 --> 14:58.140
So, var www.html.

14:58.400 --> 15:01.960
You'll see that we've now saved the index.html.

15:01.960 --> 15:08.620
And then all the supporting files to include JavaScript and CSS files in this index files page.

15:08.620 --> 15:18.160
And actually, what's helpful about this is it actually rewrites all of the links in the HTML content to these different paths dynamically.

15:20.410 --> 15:25.290
So, essentially, the only thing that we need to do is chmod 755.

15:26.050 --> 15:27.510
Make this recursive.

15:27.510 --> 15:30.010
Dash r 755 everything.

15:31.310 --> 15:35.550
And then we can open up a web browser.

15:39.350 --> 15:42.210
And make sure that the Apache service is on.

15:42.210 --> 15:44.070
So, apache2 start.

15:44.070 --> 15:48.590
And then we access 127.0.0.1.

15:50.050 --> 15:50.750
And there you have it.

15:50.750 --> 15:54.410
You now are hosting a cloned website that looks identical to the original login.

15:54.410 --> 16:12.010
Now that we have the target website cloned, and we also have our Selenium login scripts, the next step is to create a Flask authentication handler that will receive any authentication attempts to our evil clone, and then connect those to the Selenium logins to replay those credentials in real time.

16:15.370 --> 16:19.770
So, I have a proof of concept that I have published on GitHub.

16:19.770 --> 16:21.450
I have the link available here.

16:22.390 --> 16:26.690
In order to test this out, what you're going to want to do is just git clone the repository.

16:26.970 --> 16:32.710
If you want to test this for yourself, extract the app from the OTP target app.zip file.

16:33.030 --> 16:35.610
And then you can run that via Python.

16:35.930 --> 16:44.530
You'll need to register a victim user with an OTP client, a one-time pass client, at the slash register URL.

16:44.870 --> 16:55.810
And then you can use this proof of concept to host the malicious clone that will then target and bypass the multi-factor authentication on that target app.

16:55.810 --> 16:58.110
So real quick, let's just step through the code here.

16:58.110 --> 17:01.670
First, we do our imports JSON for parsing.

17:01.670 --> 17:04.750
We've got a few Selenium functions that are imported.

17:04.790 --> 17:08.250
And then we also have our Flask functions that are imported.

17:10.790 --> 17:17.070
We you'll also need to update the login URL to wherever you're hosting the target app that you extracted.

17:17.110 --> 17:24.270
In this case, I'm using a modified version of Etsy hosts to have it hosted at dundermifflin.com slash login.

17:24.610 --> 17:26.210
And we have a couple different functions.

17:26.210 --> 17:27.570
The first is create browser.

17:27.570 --> 17:31.130
So this is very similar to what we did previously in step one.

17:31.130 --> 17:38.470
However, the one difference is that we've changed it to headless so that it isn't visibly apparent within the GUI.

17:39.590 --> 17:43.830
Then we have a login function that receives the username, password, and token.

17:43.830 --> 17:48.860
And it performs the same Selenium login that we coded in step one of the process.

17:49.230 --> 17:53.670
And then finally, the last part is the Flask component.

17:53.670 --> 17:56.390
And this is actually the Flask receiver.

17:56.390 --> 18:01.750
We have a intent mapped to the slash harvester location.

18:01.750 --> 18:07.990
And this will receive from a post method request the username, password, and token.

18:07.990 --> 18:09.410
That is sent.

18:09.410 --> 18:12.710
It will print those to the user.

18:12.710 --> 18:16.210
And then it will also use that login function.

18:17.730 --> 18:21.930
Pass it those credentials in real time and execute the real time relay.

18:21.930 --> 18:24.190
It will then print the cookies back to us.

18:24.190 --> 18:30.290
And we can then use these cookies as the attacker to hijack the compromised session.

18:30.430 --> 18:38.290
So finally, we also have the malicious Flask handler hosted on a separate port.

18:38.290 --> 18:40.310
In this case, I have it hosted on 8080.

18:40.310 --> 18:46.930
But a separate port than the content that we're hosting for the cloned Evil Twin replica site.

18:46.930 --> 18:54.890
And the reason that we have these hosted on two different ports is because of the fact that we are running the clone content through Apache.

18:54.890 --> 19:01.790
And then we are hosting the handler through a separate service, which is used by Flask.

19:01.790 --> 19:13.990
Now, you could actually do this all within the Flask app by just having the HTML, CSS, and JavaScript content that you cloned within static files in the Flask app.

19:13.990 --> 19:19.710
Unfortunately, this becomes a lot more complicated than just using the relative links that exist whenever you save it.

19:19.710 --> 19:25.590
Because you then have to update all of the different links and map them to the static directories within Flask.

19:25.590 --> 19:28.990
So it's actually much easier to just host it on two separate ports.

19:30.910 --> 19:38.230
So now let's go ahead and look at how we can git clone this bypass script and execute it within our own environment.

19:38.730 --> 19:42.610
Okay, so now we are going to clone the repository and launch the bypass script.

19:42.610 --> 19:45.830
So we'll go to the GitHub repository.

19:46.730 --> 19:58.890
And then we will copy the clone path and do git clone paste selection.

20:00.450 --> 20:01.610
All right.

20:01.610 --> 20:04.500
And then we now have our cloned directory.

20:05.070 --> 20:09.350
And we can do python3 bypass.

20:10.170 --> 20:12.950
And it is now running on port 8080.

20:14.450 --> 20:19.250
Okay, so now we have our cloned web app content for the target web app.

20:19.270 --> 20:21.190
And we are hosting that on Apache.

20:21.190 --> 20:24.630
We also have our harvester that will gather credentials.

20:24.630 --> 20:27.110
And that's running on Flask on a separate port.

20:27.110 --> 20:39.490
What we need to do is now update the cloned content to where whenever a post is submitted with that form, it then submits it to our Flask harvester on port 8080.

20:42.570 --> 20:48.490
Okay, so we are going to go into our web root directory where we previously cloned the web content.

20:48.490 --> 20:53.210
So var www.html, then list the contents.

20:53.430 --> 20:58.470
And again, we had written the HTML file to index.html.

20:58.470 --> 21:06.850
All of the recursive supporting files, such as CSS, JavaScript, are all here within the index files directory.

21:07.330 --> 21:09.530
And all the content is automatically mapped.

21:10.170 --> 21:16.350
So the only thing that we need to change in this Apache directory is where the form will post to.

21:16.350 --> 21:17.850
So we can use any text editor.

21:17.850 --> 21:20.810
I'll use nano, then index.html.

21:20.810 --> 21:25.610
And then I'll use ctrl w for the find function and search for the word action.

21:26.250 --> 21:35.130
Now action in an HTML form tag defines where the post will or where the form will be submitted to.

21:35.130 --> 21:43.570
And here, when it's empty, it actually just submits it to the same directory or the same URL path as it's currently on.

21:43.570 --> 21:49.890
So what we need to do is update this to say http colon backslash backslash dunder mif.

21:49.890 --> 21:54.750
And I used a one for the L for the malicious app.

21:54.750 --> 22:00.370
So dunder miflin looks almost identical dot com slash harvester.

22:00.830 --> 22:03.410
And you also need to specify the port.

22:03.410 --> 22:05.550
So we're hosting it on port 8080.

22:05.650 --> 22:11.350
So it would be HTTP, your malicious app that you're hosting through Flask.

22:11.590 --> 22:14.690
And then the port that you're hosting it on.

22:14.690 --> 22:16.730
By default, I have it set to 8080.

22:16.770 --> 22:22.350
And then the path of the Flask receiver, which is slash harvester.

22:22.690 --> 22:24.650
Otherwise, there's nothing else that we need to change.

22:24.650 --> 22:28.590
We can do control X and then Y to save the content.

22:31.590 --> 22:45.230
So now whenever an authentication form is submitted to your evil twin copied content, it will submit the authentication request to your Flask handler in order to be able to be replayed in real time.

22:45.970 --> 22:47.470
Okay, so we now have everything set up.

22:47.470 --> 22:57.970
The only thing left to do is use our social engineering techniques, most likely phishing, to entice our victim to access the fake site and convince them that it's the real site.

22:57.970 --> 23:03.250
And then when they enter their credentials, all should work as planned and we should be able to hijack their session.

23:04.950 --> 23:07.150
So now it's time to exploit our target.

23:07.150 --> 23:08.770
You will look at two different screens here.

23:08.770 --> 23:18.050
First, we have the victim that has accessed or been enticed to access our fake dundermifflin.com login site.

23:18.050 --> 23:22.710
And then, as you recall, we have our Apache service hosting the clone content.

23:22.710 --> 23:30.590
And we also have the Flask bypass that is running our harvester on port 8080.

23:30.590 --> 23:38.490
And as you can see, the attacker currently is not logged in, if we refresh this page, to the actual dundermifflin site.

24:03.400 --> 24:13.860
Okay, so once the hijack is completed, it will actually send the initial user back to the actual dundermifflin.com login page so they don't suspect that anything has gone wrong.

24:13.860 --> 24:18.880
However, on our attacking side, we can now see that we have received the username.

24:18.900 --> 24:20.740
We have received the password.

24:20.740 --> 24:22.640
We have intercepted the token.

24:22.640 --> 24:25.640
We also replayed the token in real time.

24:25.640 --> 24:30.020
And we're able to acquire the session token for that user.

24:30.020 --> 24:34.220
So once again, we are not currently logged into the actual site as the attacker.

24:34.220 --> 24:37.000
And we are going to attempt to hijack that user session.

24:37.000 --> 24:40.640
So what we're going to do is we're going to open a cookie manager.

24:40.640 --> 24:43.160
And there's a bunch of different plugins that you can use for this.

24:43.160 --> 24:47.100
And we're going to manage cookies for dundermifflin.

24:47.420 --> 24:55.740
And then the only thing that we have to do is we have to modify this session token so that it has the value of the compromised session.

24:55.740 --> 24:57.800
So we will copy this.

25:01.450 --> 25:07.790
And then drop this into the value of the previous session token.

25:07.890 --> 25:10.570
And then we save the contents of the cookie.

25:10.570 --> 25:13.390
And we go back to dundermifflin.com, the actual site.

25:13.390 --> 25:14.010
Click enter.

25:14.010 --> 25:21.830
And we have now successfully bypassed the multi-factor authentication without having to enter the username, password, or token.

25:23.030 --> 25:27.450
Undoubtedly, at this point, somebody is thinking that this sounds an awful lot like EvilGinX.

25:27.450 --> 25:33.550
And admittedly, the first proof of concept that we discussed is something that you could accomplish with EvilGinX.

25:33.670 --> 25:43.990
For any that aren't familiar, EvilGinX is a multi-factor authentication bypass toolkit that allows you to perform very similar attacks to the ones that we just discussed.

25:44.010 --> 26:05.470
With the only difference being that instead of operating at the application layer, it operates as an HTTP proxy relaying communication for the authentication sequence and then also thereby intercepting the session tokens and providing those back to the attacker in order to allow them to assume the compromised sessions.

26:06.390 --> 26:11.330
But there's an inherent problem with relying on ScriptKitty toolkits and red teaming.

26:11.330 --> 26:18.950
For one, if the developers of the toolkit decides to stop supporting it and it no longer works, then you're dead in the water.

26:18.950 --> 26:27.910
Similarly, if something breaks in that toolkit and you don't understand the underlying components well enough to be able to troubleshoot it, there's also nothing else that you can do.

26:28.150 --> 26:40.230
But most importantly, anytime that you're relying on a cookie cutter toolkit, it will likely address the bulk number of instances where you need to use that exploit.

26:40.230 --> 26:53.390
But the reality is because you don't have control over all of the integral components of that exploit, it makes it very difficult for you to be able to tailor those attacks to unique and unconventional environments.

26:55.670 --> 27:07.650
So EvilGenX is an HTTP proxy, which means it can only operate within the context of relaying multi-factor authentication sequences over a web service.

27:07.650 --> 27:15.370
However, a lot of times these days where we're entering our multi-factor authentication credentials are not web services at all.

27:15.370 --> 27:26.490
But instead, they are login clients that exist on your local operating system, such as operating system level multi-factor authentication, VPN clients, or remote access clients.

27:28.830 --> 27:45.070
So for our second proof of concept, we're going to look at just such a scenario where we would want to take the credentials that were compromised via our phishing web service and be able to relay those to a local login client that requires multi-factor authentication.

27:45.610 --> 27:49.350
So our attack stack in this scenario is slightly different.

27:49.350 --> 27:57.570
We are still using Flask to handle the authentication requests and map those to the replay functions.

27:57.570 --> 28:02.730
And we're still using Apache in order to host the login content.

28:02.730 --> 28:17.170
The only real difference is that instead of using Selenium to hook into the browser, we're instead using something called Auto-IT to hook into the operating system in order to control operating system functions, such as mouse movement or entering text or clicking,

28:17.570 --> 28:23.990
and thereby performing authentication sequences within local authentication clients.

28:24.750 --> 28:36.230
So first, let's look at how we can use Auto-IT in order to perform operating system login functions that we could potentially use in a real-time replay attack.

28:36.530 --> 28:53.370
So in order to perform a real-time replay attack that includes the one-time pass-based multi-factor authentication with a login client as opposed to a login web service, we need to be able to programmatically interact with the underlying operating system instead of just the web browser.

28:53.410 --> 28:57.190
So in order to do that, we're going to use a different Python library this time.

28:57.190 --> 28:59.690
So instead of Selenium, we're going to use Auto-IT.

28:59.730 --> 29:04.750
And in order to import that, we're going to do import and then pyAutoGUI.

29:07.310 --> 29:09.710
And a few different functions that we need to be aware of.

29:09.710 --> 29:17.290
There is the moveTo function, which allows us to specify where it will move the mouse on the screen.

29:17.410 --> 29:21.190
There is the typeWrite function, which allows us to type text.

29:21.190 --> 29:24.670
And then there's a click function that allows us to click the mouse button.

29:24.870 --> 29:33.770
And one other function that's worth mentioning is the position function, which tells you what the coordinates are for the mouse at any given time.

29:33.910 --> 29:36.630
So we will demonstrate that real quick.

29:37.810 --> 29:39.490
pyAutoGUI.position.

29:40.150 --> 29:46.630
And we can see that the X and Y coordinates for the current cursor location is 674,334.

29:46.630 --> 29:59.130
Now, what we want to do is determine what the coordinates are of the cursor whenever it's hovering over the username field so that we can tell the mouse to go over to the username field to click and then to enter text.

29:59.430 --> 30:08.750
So what we'll do is we will use the same command, the same function, but this time before executing it, we will hover the mouse over the username field and press enter.

30:09.150 --> 30:15.510
And now we know that the coordinates of the mouse hovering over the username field is 227,369.

30:15.510 --> 30:23.890
Now, with that knowledge, we can easily create a quick function that allows us to enter text into that particular location.

30:23.890 --> 30:33.450
So to do that, we'll create a function with def and we'll call this supply username and then we'll pass it a username value.

30:34.270 --> 30:45.110
So first we'll do py autogui.moveTo and then we'll supply it those X and Y values of 227,369.

30:46.190 --> 30:53.890
Then the next thing that we want to do after we hover it over the usernames, we want it to click in that field to activate that particular input field.

30:53.890 --> 30:59.350
So for that, we'll do py autogui.click.

30:59.910 --> 31:05.790
And finally, now that the field is clicked and activated, we want to supply it the text that we provided.

31:05.790 --> 31:13.490
So we'll do py autogui.typeWrite and then the username that's supplied.

31:15.050 --> 31:20.590
Okay, so now that we've created that very basic function, we can execute that function with a given username.

31:20.590 --> 31:28.610
We'll do supply username and then we'll try the username Hutch and press enter.

31:28.910 --> 31:34.530
And as you can see, it automatically moves the mouse over, activates that field and types in the word Hutch.

31:34.530 --> 31:57.510
Now we can use all of these different functions of moving the mouse around, clicking and entering text in order to fully populate the different parameters within the multi-factor authentication sequence in order to relay communications from a malicious web app that's phishing credentials into a client in order to gain access via the client login.

31:58.070 --> 32:13.730
So now that we know that we can interact with and authenticate to a local login client using AutoIT, we want to use a similar process to what we did before where we create a phishing web service.

32:13.730 --> 32:34.470
But this time we modify the authentication replay sequence so that rather than replaying it to a separate web service, we simply use AutoIT in order to replay those credentials real-time to include the multi-factor authentication token to the login client in order to gain remote access.

32:35.910 --> 32:43.310
Now we have slightly modified the previous proof of concept in order to accomplish precisely this.

32:43.730 --> 32:48.370
So let's quickly look at what we've done here that is different.

32:48.990 --> 32:53.670
This time, instead of importing Selenium, we're using PyAuto GUI.

32:54.330 --> 32:56.870
We do have a few additional parameters.

32:56.870 --> 33:07.770
We are doing a two-step multi-factor authentication sequence process where in the first step, the username and the multi-factor authentication token is supplied.

33:07.770 --> 33:10.670
And then in the second step, the password is supplied.

33:10.670 --> 33:13.330
So because of this, we have two different redirects.

33:13.330 --> 33:18.830
The first redirect from the initial authentication sequence step.

33:18.830 --> 33:31.610
And then the other redirect URL is where the victim will be redirected after they complete the entire malicious multi-factor authentication sequence.

33:33.450 --> 33:45.970
Now, in order for this to be successful, we do have to define the specific coordinates of where different login components and buttons are within the GUI login interface.

33:45.970 --> 33:49.890
And again, we accomplish this the same way as what we just looked at.

33:50.810 --> 33:58.210
We have a function for validating the token using the username and token value.

33:58.210 --> 34:10.820
And this is accomplished, once again, by using Auto-IT and just moving the mouse to the location of specific fields, clicking on those fields to activate them, supplying the text, and then moving on.

34:11.630 --> 34:17.750
The second step in the process is essentially doing the same thing, but this time supplying the user password.

34:19.630 --> 34:28.850
And then we have a Flask app that has two different URL receivers or routes at this point.

34:28.850 --> 34:36.730
The first is the initial harvester one that represents that first step in the process of the username and the multi-factor authentication token.

34:38.690 --> 34:44.830
And as you can see, that then invokes the validate token function from above.

34:44.830 --> 34:54.670
And then the second is the second step in that multi-factor authentication sequence, which is validating the password for that particular user.

34:54.670 --> 34:59.810
And again, you see that we then invoke the validate password function that we created above.

34:59.810 --> 35:11.190
And similar to before, we are executing this or hosting this on a port that is different from the one that we are hosting the malicious replica web service on.

35:13.010 --> 35:16.430
So a few different things to take note of here on this proof concept.

35:16.430 --> 35:25.010
On the right side here, we have the malicious app that we are using to phish the victim's credentials to include their multi-factor authentication token.

35:25.010 --> 35:34.350
On the left side, we have the actual client that we would use in order to enter the intercepted username, passcode, and password.

35:34.550 --> 35:41.310
And here at the bottom left corner, you can see the bypass code running with client bypass.py.

35:41.310 --> 35:44.050
So we're going to run that once again running on port 8080.

35:44.050 --> 35:47.150
And then we're going to simulate the victim entering their credentials.

36:00.410 --> 36:08.170
And here you can see that using auto-IT, it was able to successfully migrate the client on our desktop.

36:08.170 --> 36:16.310
And then we're going to simulate the user entering the second component of the authentication, which is the password.

36:17.810 --> 36:19.910
And then they click login.

36:20.010 --> 36:23.510
And similarly, credentials are intercepted, replayed.

36:23.870 --> 36:28.290
The victim is redirected to a VMware Horizon client website.

36:29.370 --> 36:32.190
The password is disclosed at the bottom left corner.

36:32.190 --> 36:37.970
And it successfully loads our desktop and allows us to bypass multi-factor authentication.

36:39.270 --> 36:46.710
So we've now established that it is possible to bypass one-time pass-based multi-factor authentication for both web and non-web clients.

36:46.710 --> 36:49.790
But what about push-based multi-factor authentication?

36:49.790 --> 36:58.010
For anybody that's not familiar, push-based multi-factor authentication is a second factor that's initiated by the server side instead of the client side.

36:58.010 --> 37:04.430
So you enter your username and password, just as you would with any type of authentication sequence.

37:04.430 --> 37:15.870
And then for the second factor, instead of sending a temporary password that you retrieve from your mobile device to the server, the server instead sends a request to an app that you have loaded onto your device.

37:15.870 --> 37:25.510
And that request indicates that an authentication attempt was performed and then asks whether or not you approve or authorize that authentication attempt.

37:25.510 --> 37:32.470
Now, on the surface, this may seem like the more secure solution because there is no temporary password to be replayed.

37:32.610 --> 37:40.830
The problem is because of the out-of-band nature of this authentication sequence, it makes it just as easy to bypass.

37:40.870 --> 37:46.890
So let's look at our attack sequence and look at it within the context of push-based multi-factor authentication.

37:46.890 --> 37:52.810
So similar to before, we have a cybercriminal that sends a phishing email to our victim.

37:52.810 --> 37:58.390
The phishing email has a link that leads that victim to an evil twin clone server.

37:58.390 --> 38:04.890
The victim supplies their credentials and attempts to log in to what they think is the legitimate remote access service.

38:04.970 --> 38:12.990
That evil twin clone site replays in real time those credentials to the legitimate remote access service.

38:13.190 --> 38:22.790
The remote access service sees that it has an authentication attempt, so now it sends a push authorization to our victim.

38:22.810 --> 38:29.490
Now again, keep in mind that our victim believes that they've just logged into the legitimate remote access service.

38:29.490 --> 38:34.090
So they're fully expecting that they're going to get an authentication authorization request.

38:34.530 --> 38:41.470
So not thinking twice about it, the victim is going to click yes, it's me and approve this authentication attempt.

38:41.470 --> 38:49.290
So our victim is now informed of the server that the authentication request is good and the session is established.

38:49.290 --> 38:51.810
Just like before, the rest is history.

38:51.810 --> 39:01.810
We are able to use the evil twin server in the established session to harvest those session tokens and thereby hijack the session of the victim user.

39:04.010 --> 39:11.910
So we've now demonstrated that it's possible to bypass multi-factor authentication for one-time pass and push-based multi-factor authentication.

39:12.390 --> 39:15.950
So I'll close out here with just a few final parting thoughts.

39:16.810 --> 39:25.930
If you're on the blue team, we've probably established that your multi-factor authentication solution sucks and that you're likely not getting out of it what you want to get out of it.

39:25.930 --> 39:40.290
And don't feel bad because almost everybody in the industry is in that boat because everybody is using either push-based or one-time pass-based multi-factor authentication with only a very small percentage of organizations that have now moved to U2F.

39:40.290 --> 39:46.850
The obvious best thing that you can do is to use U2F for prevention.

39:46.850 --> 39:55.410
But if you can't do that at this time, then you probably need to focus more on your detection skills and identifying these types of attacks.

39:55.410 --> 40:10.950
And if you're looking for any other recommendations, because I don't want to spend too much time solutioning in red team village, you can look to FidoAlliance.org, which has a lot of good recommendations around how to effectively do multi-factor authentication.

40:10.970 --> 40:18.770
Or you can also check out some blogs that we did and that I authored at SetSolutions called Doing MFA the Right Way.

40:21.730 --> 40:27.890
If you're on the red team, I encourage you to remain flexible anytime you're doing penetration testing or red team engagements.

40:27.890 --> 40:31.970
Remember that penetration testing is more art than audit.

40:32.050 --> 40:43.230
And what I mean by that is that you're never going to get anywhere by going into an organization and attempting to perform such an assessment by checking off a series of tests in a list.

40:43.230 --> 40:44.950
You need to be flexible.

40:44.950 --> 40:59.350
You need to familiarize yourself with the environment that you're in and then be ready to adapt and create your own tools and solutions in order to exploit the ways that different components are communicating within that organization.

41:00.030 --> 41:13.530
One of the great things that I love about InfoSec is the fact that there is so much knowledge within this field and so much potential information in so many different areas that you can potentially specialize in.

41:13.530 --> 41:17.210
No matter how good you get, there's always more that you can learn.

41:17.890 --> 41:22.370
So obviously, continue to improve yourself in any way that you can.

41:22.370 --> 41:24.490
Be creative and think outside the box.

41:24.670 --> 41:32.590
I know that it's somewhat controversial to say this because some people will tell you that you can be just as effective of a penetration tester without being able to code.

41:32.590 --> 41:47.430
Learning to code is like a superpower whenever you're doing red teaming and penetration testing because of scenarios just like this where you can adaptively and quickly prototype exploits that are unique to the environment that you are attempting to assess.

41:47.730 --> 41:54.270
And always kind of approach things with that mentality of picking it apart, understanding how it works, and then putting it back together.

41:55.750 --> 42:01.090
To the staff at DEF CON and also for the Red Team Village staff, I really appreciate the opportunity.

42:01.090 --> 42:02.130
This has been awesome.

42:02.970 --> 42:06.590
Thank you for making this happen despite everything that's going on.

42:08.430 --> 42:12.810
And to everyone else, stay happy, stay healthy, stay hacking.

42:13.610 --> 42:16.130
This definitely has sucked, I think, for everybody.

42:17.110 --> 42:26.130
I admittedly was somewhat disappointed to not be going to Vegas this year for DEF CON and definitely will miss seeing all you guys out there.

42:26.850 --> 42:29.810
But I think this is something that we can all get through together.

42:29.810 --> 42:33.210
We'll put behind us and hopefully we'll see you guys next year.

42:34.610 --> 42:35.910
Quick shameless plug.

42:35.910 --> 42:39.170
Check out our podcast, Ready, Set, Secure, from Set Solutions.

42:39.470 --> 42:45.090
Also, feel free to follow my research at sociosploit.com or follow me on Twitter at Hackett Hutch.

42:46.550 --> 42:47.870
And that's a wrap.

42:48.310 --> 42:48.970
CREASE CLOSED!

