Path Traversal
Most web applications serve static resources like images and CSS
files. Frequently, applications simply serve all the files in a
folder. If the application isn't careful, the user can use a path
traversal attack to read files from other folders that they shouldn't
have access to. For example, in both Windows and
Linux, ..
represents the parent directory, so if you can
inject ../
in a path you can "escape" to the parent
directory.
If an attacker knows the structure of your file system, then they
can craft a URL that will traverse out of the installation directory
to /etc
. For example, if Picasa was vulnerable to path
traversal (it isn't) and the Picasa servers use a Unix-like system,
then the following would retrieve the password file:
https://www.picasa.com/../../../../../../../etc/passwd
Information
disclosure via path traversal
Find a way to read secret.txt
from
a running Gruyere server.
Amazingly, this attack is not even necessary in many cases:
people often install applications and never change the defaults. So
the first thing an attacker would try is the default value.
Hint 1
This isn't a black box attack because you need to know that
the secret.txt
file exists, where it's stored, and where
Gruyere stores its resource files. You don't need to look at any
source code.
Hint 2
How does the server know which URLs represent resource files? You can
use curl or a web proxy to craft request URLs that some browsers may
not allow.
Exploit and Fix
To exploit, you can steal secret.txt
via
this URL:
https://google-gruyere.appspot.com/123/../secret.txt
Some browsers, like Firefox and Chrome, optimize out ../
in URLs. This doesn't provide any security protection because an
attacker will use %2f
to represent /
in the URL;
or a tool like curl, a web proxy or a browser that
doesn't do that optimization. But if you test your application with
one of these browsers to see if you're vulnerable, you might think you
were protected when you're not.
To fix, we need to prevent access to files outside
the resources directory. Validating file paths is a bit tricky as
there are various ways to hide path elements like "../" or "~" that
allow escaping out of the resources folder. The best protection is to
only serve specific resource files. You can either hardcode a list or
when your application starts, you can crawl the resource directory and
build a list of files. Then only accept requests for those files. You
can even do some optimization here like caching small files in memory
which will make your application faster. If you are going to try to
file path validation, you need to do it on the final path, not on the
URL, as there are numerous ways to represent the same characters in
URLs. Note: Changing file permissions will NOT work. Gruyere has
to be able to read this file.
Data
tampering via path traversal
Find a way to replace secret.txt
on
a running Gruyere server.
Hint 1
Again, this isn't a black box attack because you need to know about
the directory structure that Gruyere uses, specifically where
uploaded files are stored.
Hint 2
If I log in as user brie
and upload a file, where does
the server store it? Can you trick the server into uploading a file
to ../../secret.txt
?
Exploit and Fix
To exploit, create a new user named ..
and upload your new secret.txt
. You could also create a
user named brie/../..
.
To fix, you should escape dangerous characters in the username
(replacing them with safe characters) before using it. It was earlier
suggested that we should restrict the characters allowed in a username,
but it probably didn't occur to you that "."
was a
dangerous character. It's worth noting that there's a vulnerability
unique to Windows servers with this implementation. On Windows,
filenames are not case sensitive but Gruyere usernames are. So one
user can attack another user's files by creating a similar username
that differs only in case, e.g., BRIE
instead
of brie
. So we need to not just escape unsafe characters
but convert the username to a canonical form that is different for
different usernames. Or we could avoid all these issues by assigning
each user a unique identifier instead.
Oops! This doesn't completely solve the problem. Even with the
above fix in place, there is another way to perform this attack. Can
you find it?
Hint
Are there any limits on the filename when you do an upload? You may
need to use a special tool like curl
or a web proxy to
perform this attack.
Another Exploit and Fix
Surprisingly, you can upload a file
named ../secret.txt
. Gruyere provides no protection
against this attack. Most browsers won't let you upload that file but,
again, you can do it with curl or other tools. You need the same kind
of protection when writing files as you do on read.
As a general rule, you should never store user data in the
same place as your application files but that alone won't protect
against these attacks since if the user can inject ../
into the file path, they can traverse all the way to the root of the
file system and then back down to the normal install location of your
application (or even the Python interpreter itself).
Denial of Service
A denial of service (DoS) attack is an attempt to make a server unable
to service ordinary requests. A common form of DoS attack is sending
more requests to a server than it can handle. The server spends all
its time servicing the attacker's requests that it has very little
time to service legitimate requests. Protecting an application against
these kinds of DoS attacks is outside the scope of this codelab. And
attacking Gruyere in this way would be interpreted as an attack on
App Engine.
Hackers can also prevent a server from servicing requests by
taking advantage of server bugs, such as sending requests that crash a
server, make it run out of memory, or otherwise cause it fail serving
legitimate requests in some way. In the next few challenges, you'll
take advantage of bugs in Gruyere to perform DoS attacks.
DoS - Quit the Server
The simplest form of denial of service is shutting down a service.
Find a way to make the server quit.
Hint
How does an administrator make the server quit? The server management
page is manage.gtl
.
Exploit and Fix
To exploit, make a request
to https://google-gruyere.appspot.com/123/quitserver
. You
should need to be logged in as an administrator to do this, but you
don't.
This is another example of a common bug. The server protects
against non-administrators accessing certain URLs but the list
includes /quit
instead of the actual
URL /quitserver
.
To fix, add /quitserver
to the URLS only
accessible to administrators:
_PROTECTED_URLS = [
"/quitserver",
"/reset"
]
Oops! This doesn't completely solve the problem.
The reset
URL is in the protected list. Can you figure
out how to access it?
Hint
Look carefully at the code that handles URLs and checks for protected ones.
Another Exploit and Fix
To exploit,
use https://google-gruyere.appspot.com/123/RESET
. The check for
protected urls is case sensitive. After doing that check, it
capitalizes the string to look up the implementation. This is a
classic check/use bug where the condition being checked does not match
the actual use. This vulnerability is worse than the previous one
because it exposes all the protected urls.
To fix, put the security check inside the dangerous
functions rather than outside them. That ensures that no matter how we
get there, the security check can't be skipped.
DoS - Overloading the Server
Find a way to overload the server when it processes a request.
Hint 1
You can upload a template that does this.
Hint 2
Every page includes
the menubar.gtl
template. Can you figure out how to make that template overload the
server?
Exploit and Fix
To exploit, create a file named menubar.gtl
containing:
[[include:menubar.gtl]]DoS[[/include:menubar.gtl]]
and upload it to the
resources
directory using a path traversal attack, e.g., creating a user named
../resources
.
To fix, implement the protections against path traversal and uploading templates discussed earlier.
NOTE: After performing the previous exploit, you'll need to
push the
reset button.
More on Denial of
Service
Unlike a well defined vulnerability like XSS or XSRF, denial of
service describes a wide class of attacks. This might mean bringing
your service down or flooding your inbox so you can't receive
legitimate mail. Some things to consider:
If you were evil and greedy, how quickly could you take down your
application or starve all of its resources? For example, is it
possible for a user to upload their hard drive to your application?
Entering the attacker's mindset can help identify DoS points in your
application. Additionally, think about where the computationally and
memory intensive tasks are in your application and put safeguards in
place. Do sanity checks on input values.
Put monitoring in place so you can detect when you are under
attack and enforce per user quotas and rate limiting to ensure that a
small subset of users cannot starve the rest. Abusive patterns could
include increased memory usage, higher latency, or more requests or
connections than usual.
Code Execution
If an attacker can execute arbitrary code remotely on your server,
it's usually game over. They may be able to take control over the
running program or potentially break out the process to open a new
shell on the computer. From here, it's usually not hard to compromise
the entire machine the server is running on.
Similar to information disclosure and denial of service, there
is no recipe or specific defense to prevent remote code execution. The
program must perform validation of all user input before handling it
and where possible, implement functions with least privilege
rights. This topic can't be done justice in just a short paragraph,
but know that this is likely the scariest results a security bug can
have and trumps any of the above attacks.
Code Execution Challenge
Find a code execution exploit.
Hint
You need to use two previous exploits.
Exploit and Fix
To exploit, make a copy
of gtl.py
(or sanitize.py
) and
add some exploit code. Now you can either upload a file
named ../gtl.py
or create a user named ..
and upload gtl.py
. Then, make the server quit by browsing
to https://google-gruyere.appspot.com/123/quitserver
. When the
server restarts, your code will run.
This attack was possible because Gruyere has permission to both
read and write files in the Gruyere directory. Applications should
run with the minimal privileges possible.
Why would you attack gtl.py
or sanitize.py
rather than gruyere.py
?
When an attacker has a choice, they would usually choose to attack the
infrastructure rather than the application itself. The infrastructure
is less likely to be updated and less likely to be noticed. When was
the last time you checked that no one had
replaced python.exe
with a trojan?
To fix, fix the two previous exploits.
More on Remote
Code Execution
Even though there is no single or simple defense to remote code
execution, here is a short list of some preventative measures:
Least Privilege: Always run your application with
the least privileges it needs.
Application Level Checks: Avoid passing user input
directly into commands that evaluate arbitrary code,
like eval()
or system()
. Instead, use the
user input as a switch to choose from a set of developer controlled
commands.
Bounds Checks: Implement proper bounds checks for
non-safe languages like
C++. Avoid unsafe string functions. Keep in mind that even safe
languages like Python and Java use native libraries.
Continue >>
© Google 2017 Terms of Service
The code portions of this codelab are licensed under the
Creative Commons Attribution-No Derivative Works 3.0 United States license
<https://creativecommons.org/licenses/by-nd/3.0/us>.
Brief excerpts of the code may be used for educational or
instructional purposes provided this notice is kept intact.
Except as otherwise noted the remainder of this codelab is licensed under the
Creative Commons Attribution 3.0 United States license
<https://creativecommons.org/licenses/by/3.0/us>.