 my talk, broadcasting from my quarantine bunker to yours. My talk is Yippee-ki-yay, MFA-er, bypassing multi-factor authentication with real-time replay session instantiation attacks. So before we get started, I'll go ahead and introduce myself. My name is Hutch. I am the Consulting Services Practice Lead at a company called Set Solutions. I lead our government's risk and compliance, cyber incident response, threat hunting, penetration testing, and red teaming operations at the company. I have a master's in information systems and multiple different certifications on both the blue and red team side. 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. Aside from my hacktivity interests, I do enjoy spending time with my family. I enjoy country life and getting away from the big city, algorithmic trading, and last but not least, street tacos. 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. 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. 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. 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. 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. So the security industry's response to these types of attacks was multi-factor authentication. And by multi-factor authentication, the common understanding is that that's any combination of at least two of the following authentication factors, something you know, such as a password, something you have, such as a mobile device or a hardware token or something you are, such as biometrics. 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. 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. Multi-factor authentication stands in the way and is better securing remote access services. Fortunately, not all hope is lost for the red team. When it comes to multi-factor authentication implementation, the right way is also the hard way. And what I mean by the right way is phyto-compliant UTF or universal second factor authentication. 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. Unfortunately, the overhead involved in supporting a UTF program at an enterprise level is extremely difficult for most organizations to achieve. So the reality is most organizations are doing multi-factor authentication the wrong way. 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. 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. You have the factor of something that you know which is the username and password. But, and the assumption is with these two types of authentication that the second factor is something that you have. But in reality, it's not 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. Instead, you look at that one-time password that's good for say 30 seconds. 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. And so it becomes subject to the same types of attacks that those username and passwords are specifically, they are replayable. 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. Instead, it's done completely out of band and your phone just receives a notification. So it makes it very easy to bypass as well. 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. 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. For the sake of conversation, we will call this office worker Dwight Schrute. 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. Unfortunately for Dwight, there are bad people in this world that seek to do harm to business organizations. 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. 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. And because this server looks identical to the original server that Dwight is accustomed to log into, he then supplies its credentials. 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. And so unfortunately without multifactor authentication, this leaves our employees vulnerable. This gets the attention of upper level management who then decides to call in the IT department to implement multifactor authentication. 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. So multifactor authentication saves the day, the fortress is impenetrable and all of the hackers have given up, right? Not exactly. So now let's talk about how this attack can be performed in order to bypass that multifactor authentication. So similarly, we have our white collar worker, the attacker that sends the email. The email looks exactly the same and the victim then clicks the update account link. Accesses the site and similar to before enters his credentials. And this time to include his multifactor authentication token. So then upon logging into 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 multifactor authentication token is still valid to the actual server. This establishes a legitimate login session with the actual server. And the session token is then forwarded back to the attacker. 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. So now let's look through a couple of demonstrations. First, we're gonna look through a way that we can use this type of attack to defeat multifactor authentication on a common web service. And then we're gonna look at a more unique scenario where we can use the same methodology in order to defeat multifactor authentication using a binary remote access client. So for the first scenario where we are attempting to bypass multifactor authentication on a web service, the stack that we're gonna use is Flask as our micro framework for our web service. We are going to use Apache to independently host the copied or replicated content from the legitimate remote access server. 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. For this demo, I have used a Flask one-time pass multifactor authentication proof of concept that was published by Miguel Greenberg who does some fantastic Python and Flask stuff. And so definitely worth checking out. But fortunately for us, it makes a convenient option to test different attacks on multifactor authentication without having to do a full deployment ourselves. So you can essentially just get clone this repository, run it through Python, and you will have a one-time pass multifactor authentication portal that you can perform testing on. Of course, we did some slight cosmetic changes in order to fit with the theme. So first we're gonna look at how we can use Python and Selenium in order to execute real-time logins to the actual multifactor authentication remote access service. So the first thing that we're gonna need to do in order to achieve the multifactor authentication bypass is we are going to need to be able to programmatically log in to the actual multifactor authentication service. So we're gonna do that with Python and we're gonna start with from Selenium import web driver. Then we are going to create an instance of web driver. So driver equals webdriver.firefox. And you should see a browser open in the graphical interface. And next we're going to browse to the actual site. So we will do driver.get and then the URL. It's worth noting that for this demo, I did modify my Etsy hosts file and I do not actually own this domain. So then what we wanna do is we want to enter text values in each of these different parameters, username, password and token. So in order to do this, we're gonna inspect the element. 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. So in order to interact with it, we will just do driver.findElementByID and then pass it that value username. And then we wanna send it the keys of the username we wanna send. So I'll put hutch. And as you can see it programmatically populates that field. We can then do the same thing for password by inspecting it. And here we can see that the ID value for password is also password. So we'll do driver.findElementByID password then send keys and my password. And as you can see it then populates the password field. And finally for token, we can do the same thing inspect element. The ID is token. So we can do the same thing, but this time we'll make our token value one, two, three, four, five, six and the ID is token. So now that all the fields are populated we just need to click the login button. So we just right click this and inspect element. And here we can see that the ID value for that login button is the word submit. So all we have to do is driver.findElementByIDSubmit and then this time instead of send keys we'll use dot click. And as you can see by the error returned valid username password or token we were able to programmatically make a login attempt to the actual site. 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. So in order to make the replica website we'll start by opening up a web browser and then we will browse to the page that we want to clone. 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 it save page as. And this will save a full recursive copy of the website. If you wanna drop it directly into your web root browse to var www.html. 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. Then save. And then next you'll wanna go to that directory so var www.html. You'll see that we've now saved the index.html and then all the supporting files to include JavaScript and CSS files in this index files page. And actually what's helpful about this is it actually rewrites all of the links in the HTML content to these different paths dynamically. So essentially the only thing that we need to do is chmod 755. Oh make this recursive dash R 755 everything. And then we can open up a web browser and make sure that the Apache service is on. So Apache to start. And then we access 127.0.0.1. And there you have it. You now are hosting a cloned website that looks identical to the original login. 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. So I have a proof of concept that I have published on GitHub. I have the link available here. In order to test this out what you're gonna wanna do is just get cloned repository. If you want to test this for yourself extract the app from the OTP target app.zip file and then you can run that via Python. You'll need to register a victim user with an OTP client or a one-time pass client at the slash register URL. 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. So real quick, let's just step through the code here. First we do our imports JSON for parsing. We've got a few Selenium functions that are imported and then we also have our Flask functions that are imported. You'll also need to update the login URL to wherever you're hosting the target app that you extracted. In this case, I'm using a modified version of Etsy hosts to have it hosted at dundermiflin.com slash login. And we have a couple different functions. The first is create browser. So this is very similar to what we did previously in step one. However, the one difference is that we've changed it to headless so that it isn't visibly apparent within the GUI. Then we have a login function that receives the username password and token and it performs the same Selenium login that we coded in step one of the process. And then finally, the last part is the Flask component and this is actually the Flask receiver. We have a intent mapped to the slash harvester location and this will receive from a post method request the username password and token that is sent. It will print those to the user and then it will also use that login function, pass it those credentials in real time and execute the real time relay. It will then print the cookies back to us and we can then use these cookies as the attacker to hijack the compromised session. So finally, we also have the malicious Flask handler hosted on a separate port. In this case, I have it hosted on 8080 but a separate port then the content that we're hosting for the cloned evil twin replica site. 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 and then we are hosting the handler through a separate service which is used by Flask. 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. Unfortunately, this becomes a lot more complicated than just using the relative links that exist whenever you save it because you then have to update all of the different links and map them to the static directories within Flask. So it's actually much easier to just host it on two separate ports. So now let's go ahead and look at how we can get clone this bypass script and execute it within our own environment. Okay, so now we are going to clone the repository and launch the bypass script. So we'll go to the GitHub repository and then we will copy the clone path and do get clone, paste selection, right? And then we now have our clones directory and we can do Python 3 bypass and it is now running on port 8080. Okay, so now we have our cloned web app content for the target web app and we are hosting that on Apache. We also have our harvester that will gather credentials and that's running on Flask on a separate port. 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. Okay, so we are going to go into our web root directory where we previously cloned the web content. So var www.html then list the contents and again we had written the HTML file to index.html and all of the recursive supporting files such as CSS, JavaScript are all here within the index files directory and all the content is automatically mapped. So the only thing that we need to change in this Apache directory is where the form will post to. So we can use any text editor. I'll use nano then index.html and then I'll use control w for the find function and search for the word action. Now action in an HTML form tag defines where the post will or where the form will be submitted to 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. So what we need to do is update this to say HTTP colon backslash backslash dunder myth and I used a one for the L for the malicious app. So dunder mifflin looks almost identical.com slash harvester and you also need to specify the port. So we're hosting it on port 8080. So it would be HTTP your malicious app that you're hosting through a flask and then the port that you're hosting it on by default I have it set to 8080 and then the path of the flask receiver which is slash harvester. Otherwise there's nothing else that we need to change so we can do control X and then Y to save the content. 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. Okay so we now have everything set up. 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 and then when they enter their credentials all should work as planned and we should be able to hijack their session. So now it's time to exploit our target. You will look at two different screens here. First we have the victim that has accessed or been enticed to access our fake dundermifflin.com login site and then as you recall we have our Apache service hosting the cloned content and we also have the flask bypass that is running our harvester on port 8080 and as you can see the attacker currently is not logged in if we refresh this page to the actual dundermifflin site. Okay so once the hijack is completed we'll actually send the initial user back to the actual dundermifflin.com login page so that they don't suspect that anything has gone wrong. However on our attacking side we can now see that we have received the username, we have received the password, we have intercepted the token, we also replayed the token in real time and we're able to acquire the session token for that user. So once again we are not currently logged into the actual site as the attacker and we are going to attempt to hijack that user session. So what we're gonna do is we're going to open a cookie manager and there's a bunch of different plugins that you can use for this and we're going to manage cookies for dundermifflin 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. So we will copy this and then drop this into the value of the previous session token and then we save the contents of the cookie and we go back to dundermifflin.com, the actual site, click enter and we have now successfully bypassed the multi-factor authentication without having to enter the username, password or token. Undoubtedly at this point somebody is thinking that this sounds an awful lot like Evil Gen X and admittedly the first proof of concept that we discussed is something that you could accomplish with Evil Gen X. For any that aren't familiar Evil Gen X is a multi-factor authentication bypass toolkit that allows you to perform very similar attacks to the ones that we just discussed with the only difference being that instead of operating 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. But there's an inherent problem with relying on script kitty toolkits in red teaming. 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. 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. But most importantly, any time 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. 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. So Evil Gen X is an HTTP proxy, which means it can only operate within the context of relaying multi-factor authentication sequences over a web service. However, a lot of times these days where we're entering a multi-factor authentication credentials are not web services at all, 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. So for our second proof of concept, we're gonna 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. So our attack stack in this scenario is slightly different. We are still using Flask to handle the authentication requests and map those to the replay functions. And we're still using Apache in order to host the login content. The only real difference is that instead of using Selenium to hook into the browser, we're instead using something called AutoIT to hook into the operating system in order to control operating system functions, such as mouse movement or entering text or clicking and thereby performing authentication sequences within local authentication clients. So first let's look at how we can use AutoIT in order to perform operating system login functions that we could potentially use in a real-time replay attack. 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. So in order to do that, we're gonna use a different Python library this time. So instead of Selenium, we're gonna use AutoIT. And in order to import that, we're gonna do import and then pie auto GUI. And a few different functions that we need to be aware of. There is the move to function, which allows us to specify where it will move the mouse on the screen. There is the type write function, which allows us to type text. And then there's a click function that allows us to click the mouse button. 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. So we will demonstrate that real quick, pie auto GUI.position. And we can see that the X and Y coordinates for the current cursor location is 674-334. Now what we wanna 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. 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. And now we know that the coordinates of the mouse hovering over the username field is 227-369. Now with that knowledge, we can easily create a quick function that allows us to enter text into that particular location. 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. So first we'll do pie auto GUI.move2, and then we'll supply it those X and Y values of 227-369. Then the next thing that we wanna do after we hover it over the username is we want it to click in that field to activate that particular input field. So for that we'll do pie auto GUI.click. And finally, now that the field is clicked and activated, we wanna supply it the text that we provided. So we'll do pie auto GUI.type write and then the username that's supplied. Okay, so now that we've created that very basic function, we can execute that function with a given username. So we'll do supply username and then we'll try the username hutch and press enter. And as you can see, it automatically moves the mouse over activates that field and types in the word hutch. 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. So now that we know that we can interact with and authenticate to a local login client using auto IT, we want to use a similar process to what we did before where we create a phishing web service. But this time we modify the authentication replay sequence so that rather than replaying it to a separate web service, we simply use auto IT 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. Now we have slightly modified the previous proof of concept in order to accomplish precisely this. So let's quickly look at kind of what we've done here that is different. This time instead of importing Selenium, we're using PyAuto GUI. We do have a few additional parameters. 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 and then in the second step, the password is supplied. So because of this, we have two different redirects. The first redirect from the initial authentication sequence step and then the other redirect URL is where the victim will be redirected after they complete the entire malicious multi-factor authentication sequence. 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. And again, we accomplished this the same way as what we just looked at. We have a function for validating the token using the username and token value. 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. The second step in the process is essentially doing the same thing, but this time supplying the user password. And then we have a Flask app that has two different URL receivers or routes at this point. The first is the initial harvester one that represents that first step in the process of the username and the multi-factor authentication token. And as you can see that then invokes the validate token function from above. And then the second is the second step in that multi-factor authentication sequence which is validating the password for that particular user. And again, you see that we then invoke the validate password function that we created above. 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. So a few different things to take note of here on this proof concept. On the right side here, we have the malicious app that we are using to fish the victim's credentials to include their multi-factor authentication token. On the left side, we have the actual client that we would use in order to enter the intercepted username, passcode, and password. And here at the bottom left corner, you can see the bypass code running with client bypass.py. So we're gonna run that once again, running on port 8080. And then we're gonna simulate the victim entering their credentials. And here you can see that using auto-IT, it was able to successfully migrate the client on our desktop. And then we're going to simulate the user entering the second component of the authentication which is the password. And then they click login. And similarly, credentials are intercepted, replayed. The victim is redirected to a VMware Horizon client website. The password is disclosed at the bottom left corner and it successfully loads our desktop and allows us to bypass multi-factor authentication. So we've now established that it's possible to bypass one-time pass-based multi-factor authentication for both web and non-web clients. But what about push-based multi-factor authentication? 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. So you enter your username and password just as you would with any type of authentication sequence. 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. And that request indicates that an authentication attempt was performed and then asks whether or not you approve or authorized that authentication attempt. Now on the surface, this may seem like the more secure solution because there is no temporary password to be replayed. The problem is because of the out-of-band nature of this authentication sequence, it makes it just as easy to bypass. So let's look at our attack sequence and look at it within the context of push-based multi-factor authentication. So similar to before, we have a cyber criminal that sends a phishing email to our victim. The phishing email has a link that leads that victim to an evil twin clone server. The victim supplies their credentials and attempts to log in to what they think is the legitimate remote access service. That evil twin clone site replays in real time those credentials to the legitimate remote access service. The remote access service sees that it has an authentication attempt. So now it sends a push authorization to our victim. Now, again, keep in mind that our victim believes that they've just logged in to the legitimate remote access service. So they're fully expecting that they're going to get an authentication authorization request. So not thinking twice about it, the victim is gonna click yes, it's me and approve this authentication attempt. So our victim has now informed the server that the authentication request is good and the session is established. And just like before the rest is history, we are able to use the evil twin server and the established session to harvest those session tokens and thereby hijack the session of the victim user. So we've now demonstrated that it's possible to bypass multi-factor authentication for one-time pass and push-based multi-factor authentication. So I'll close out here with just a few final parting thoughts. 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 wanna get out of it. 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. The obvious best thing that you can do is to use U2F for prevention. But if you can't do that at this time, then you probably need to focus more on your detection skills and identifying these type of attacks. And if you're looking for any other recommendations because I don't wanna spend too much time solutioning in Red Team Village, you can look to phytoleliance.org, which has a lot of good recommendations around how to effectively do multi-factor authentication. Or you can also check out some blogs that we did and that I authored at Set Solutions called Doing MFA the Right Way. If you're on the Red Team, I encourage you to remain flexible anytime you're doing penetration testing or Red Team engagements. Remember that penetration testing is more art than audit. And what I mean by that is that you're never gonna get anywhere by going into an organization and attempting to perform such an assessment by checking off a series of tests in a list. You need to be flexible. 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. 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 that no matter how good you get, there's always more that you can learn. So obviously continue to improve yourself in any way that you can. Be creative and think outside the box. I know that it's somewhat controversial to say this because some people will tell you that you can be just as effective of penetration tester without being able to code. Learning to code is like a superpower whenever you're doing Red Team 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 and always kind of approach things with that mentality of picking it apart, understanding how it works and then putting it back together. To the staff at DEF CON and also for the Red Team Village staff, I really appreciate the opportunity. This has been awesome. Thank you for making this happen despite everything that's going on. And to everyone else, stay happy, stay healthy, stay hacking. This definitely has sucked, I think, for everybody. 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. But I think this is something that we can all get through together. We'll put behind us and hopefully we'll see you guys next year. Quick shameless plug, check out our podcast, Ready Set Secure from Set Solutions. Also feel free to follow my research at sociosploit.com or follow me on Twitter at Hacket Hutch. And that's a wrap. Chris Clark!