Client-State Manipulation
When a user interacts with a web application, they do it indirectly through a browser. When the user clicks a button or submits a form, the browser sends a request back to the web server. Because the browser runs on a machine that can be controlled by an attacker, the application must not trust any data sent by the browser.It might seem that not trusting any user data would make it impossible to write a web application but that's not the case. If the user submits a form that says they wish to purchase an item, it's OK to trust that data. But if the submitted form also includes the price of the item, that's something that cannot be trusted.
Elevation of Privilege
Convert your account to an administrator account.Hint 1
Take a look at
the
editprofile.gtl
page that users and administrators use to edit profile settings. If you're not
an administrator, the page looks a bit different. Can you figure out
how to fool Gruyere into letting you use this page to update your account?
Hint 2
Can you figure out how to fool Gruyere into thinking you used this
page to update your account?
Exploit and Fixes
You can convert your account to being an administrator by issuing
either of the following requests:
The bug here is that there is no validation on the server side that the request is authorized. The only part of the code that restricts the changes that a user is allowed to make are in the template, hiding parts of the UI that they shouldn't have access to. The correct thing to do is to check for authorization on the server, at the time that the request is received.
-
http://google-gruyere.appspot.com/123/saveprofile?action=update&is_admin=True
-
http://google-gruyere.appspot.com/123/saveprofile?action=update&is_admin=True&uid=username
(which will make anyusername
into an an admin)
The bug here is that there is no validation on the server side that the request is authorized. The only part of the code that restricts the changes that a user is allowed to make are in the template, hiding parts of the UI that they shouldn't have access to. The correct thing to do is to check for authorization on the server, at the time that the request is received.
Cookie Manipulation
Because the HTTP protocol is stateless, there's no way a web server can automatically know that two requests are from the same user. For this reason, cookies were invented. When a web site includes a cookie (an arbitrary string) in a HTTP response, the browser automatically sends the cookie back to the browser on the next request. Web sites can use the cookie to save session state. Gruyere uses cookies to remember the identity of the logged in user. Since the cookie is stored on the client side, it's vulnerable to manipulation. Gruyere protects the cookies from manipulation by adding a hash to it. Notwithstanding the fact that this hash isn't very good protection, you don't need to break the hash to execute an attack. Get Gruyere to issue you a cookie for someone else's account.Hint 1
Hint 2
Exploit and Fix
Cross-Site Request Forgery (XSRF)
The previous section said "If the user submits a form that says they wish to purchase an item, it's OK to trust that data." That's true as long as it really was the user that submitted the form. If your site is vulnerable to XSS, then the attacker can fake any request as if it came from the user. But even if you've protected against XSS, there's another attack that you need to protect against: cross-site request forgery.When a browser makes requests to a site, it always sends along any cookies it has for that site, regardless of where the request comes from. Additionally, web servers generally cannot distinguish between a request initiated by a deliberate user action (e.g., user clicking on "Submit" button) versus a request made by the browser without user action (e.g., request for an embedded image in a page). Therefore, if a site receives a request to perform some action (like deleting a mail, changing contact address), it cannot know whether this action was knowingly initiated by the user — even if the request contains authentication cookies. An attacker can use this fact to fool the server into performing actions the user did not intend to perform.
More details
For example, suppose Blogger is vulnerable to XSRF attacks (it
isn't). And let us say Blogger has a Delete Blog button on the
dashboard that points to this URL:
http://www.blogger.com/deleteblog.do?blogId=BLOGIDBob, the attacker, embeds the following HTML on his web page on
http://www.evil.example.com
:
<img src="http://www.blogger.com/deleteblog.do?blogId=alice's-blog-id" style="display:none">If the victim, Alice, is logged in to
www.blogger.com
when
she views the above page, here is what happens:
- Her browser loads the page
from
http://www.evil.example.com
. The browser then tries to load all embedded objects in the page, including theimg
shown above. - The browser makes a request
to
http://www.blogger.com/deleteblog.do?blogId=alice's-blog-id
to load the image. Since Alice is logged into Blogger — that is, she has a Blogger cookie — the browser also sends that cookie in the request. - Blogger verifies the cookie is a valid session cookie for
Alice. It verifies that the blog referenced
by
alice's-blog-id
is owned by Alice. It deletes Alice's blog. - Alice has no idea what hit her.
XSRF Challenge
The goal here is to find a way to perform an account changing action on behalf of a logged in Gruyere user without their knowledge. Assume you can get them to visit a web page under your control.Find a way to get someone to delete one of their Gruyere snippets.
Hint
What is the URL used to delete a snippet? Look at the URL associated
with the "X" next to a snippet.
Exploit and Fix
To exploit, lure a user to visit a page that makes
the following request:
To fix, we should first change
However, note that changing to
When a request is processed, Gruyere should regenerate the token and compare it with the value supplied with the request. If the values are equal, then it should perform the action. Otherwise, it should reject it. The functions that generate and verify the tokens look like this:
http://google-gruyere.appspot.com/123/deletesnippet?index=0To be especially sneaky, you could set your Gruyere icon to this URL and the victim would be exploited when they visited the main page.
To fix, we should first change
/deletesnippet
to
work via a POST
request since this is a state changing
action. In the HTML form, change method='get'
to method='post'
. On the server side, GET
and POST
requests look the same except that they usually
call different handlers. For example, Gruyere uses Python's
BaseHTTPServer which calls do_GET
for GET
requests and do_POST
for POST
requests.
However, note that changing to
POST
is not enough
of a fix in itself! (Gruyere uses GET
requests
exclusively because it makes hacking it a bit
easier. POST
is not more secure than GET
but
it is more correct: browsers may re-issue GET
requests
which can result in an action getting executed more than once;
browsers won't reissue POST
requests without user
consent.) Then we need to pass a unique, unpredictable authorization
token to the user and require that it get sent back before performing
the action. For this authorization token, action_token
,
we can use a hash of the value of the user's cookie appended to a
current timestamp and include this token in all state-changing HTTP
requests as an additional HTTP parameter. The reason we
use POST
over GET
requests is that if we
pass action_token
as a URL parameter, it might leak via
HTTP Referer headers. The reason we include the timestamp in our hash
is so that we can expire old tokens, which mitigates the risk if it
leaks.
When a request is processed, Gruyere should regenerate the token and compare it with the value supplied with the request. If the values are equal, then it should perform the action. Otherwise, it should reject it. The functions that generate and verify the tokens look like this:
def _GenerateXsrfToken(self, cookie): """Generates a timestamp and XSRF token for all state changing actions.""" timestamp = time.time() return timestamp + "|" + (str(hash(cookie_secret + cookie + timestamp))) def _VerifyXsrfToken(self, cookie, action_token): """Verifies an XSRF token included in a request.""" # First, make sure that the token isn't more than a day old. (action_time, action_hash) = action_token.split("|", 1) now = time.time() if now - 86400 > float(action_time): return False # Second, regenerate it and check that it matches the user supplied value hash_to_verify = str(hash(cookie_secret + cookie + action_time) return action_hash == hash_to_verifyOops! There's several things wrong with these functions.
What's missing?
By including the time in the token, we prevent it from being used
forever, but if an attacker were to gain access to a copy of the
token, they could reuse it as many times as they wanted within that 24
hour period. The expiration time of a token should be set to a small
value that represents the reasonable length of time it will take the
user to make a request. This token also doesn't protect against an
attack where a token for one request is intercepted and then used for
a different request. As suggested by the
name
XSRF vulnerabilities exist because an attacker can easily script a series of requests to an application and than force a user to execute them by visiting some page. To prevent this type of attack, you need to introduce some value that can't be predicted or scripted by an attacker for every account changing request. Some application frameworks have XSRF protection built in: they automatically include a unique token in every response and verify it on every POST request. Other frameworks provide functions that you can use to do that. If neither of these cases apply, then you'll have to build your own. Be careful of things that don't work: using
action_token
, the token should be tied to the
specific state changing action being performed, such as the URL of the
page. A better signature for _GenerateXsrfToken
would
be (self, cookie, action)
. For very long actions, like
editing snippets, a script on the page could query the server to
update the token when the user hits submit. (But read the next section
about XSSI to make sure that an attacker won't be able to read that
new token.)XSRF vulnerabilities exist because an attacker can easily script a series of requests to an application and than force a user to execute them by visiting some page. To prevent this type of attack, you need to introduce some value that can't be predicted or scripted by an attacker for every account changing request. Some application frameworks have XSRF protection built in: they automatically include a unique token in every response and verify it on every POST request. Other frameworks provide functions that you can use to do that. If neither of these cases apply, then you'll have to build your own. Be careful of things that don't work: using
POST
instead of GET
is advisable
but not sufficient by itself, checking Referer headers is
insufficient, and copying cookies into hidden form fields can make
your cookies less secure.
Cross Site Script Inclusion (XSSI)
Browsers prevent pages of one domain from reading pages in other domains. But they do not prevent pages of a domain from referencing resources in other domains. In particular, they allow images to be rendered from other domains and scripts to be executed from other domains. An included script doesn't have its own security context. It runs in the security context of the page that included it. For example, ifwww.evil.example.com
includes a script hosted
on www.google.com
then that script runs in
the evil
context not in the google
context. So any user data in that script will "leak."
XSSI Challenge
Find a way to read someone else's private snippet using XSSI.That is, create a page on another web site and put something in that page that can read your private snippet. (You don't need to post it to a web site: you can just create a
.html
in your
home directory and double click on it to open in a browser.)
Hint 1
You can run a script from another domain by
adding
<SCRIPT src="http://google-gruyere.appspot.com/123/..."></SCRIPT>to your HTML file. What scripts does Gruyere have?
Hint 2
feed.gtl
is a
script. Given that, how can you get the private snippet out of the
script?
Exploit and Fix
To exploit, put this in an html file:
You might think that you can fix this by eliminating the function call and just having the bare expression. That way, when the script is executed by inclusion, the response will be evaluated and then discarded. That won't work because Javascript allows you to do things like redefine default constructors. So when the object is evaluated, the hosting page's constructors are invoked, which can do whatever they want with the values.
To fix, there are several changes you can make. Any one of these changes will prevent currently possible attacks, but if you add several layers of protection ("defense in depth") you protect against the possibility that you get one of the protections wrong and also against future browser vulnerabilities. First, use an XSRF token as discussed earlier to make sure that JSON results containing confidential data are only returned to your own pages. Second, your JSON response pages should only support
NOTE: Making the script not executable is more subtle than it seems. It's possible that what makes a script executable may change in the future if new scripting features or languages are introduced. Some people suggest that you can protect the script by making it a comment by surrounding it with
There's much more to XSSI than this. There's a variation of JSON called JSONP which you should avoid using because it allows script injection by design. And there's E4X (Ecmascript for XML) which can result in your HTML file being parsed as a script. Surprisingly, one way to protect against E4X attacks is to put some invalid XML in your files, like the
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
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.
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.
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.
articles/ default- logins- and- passwords- for- networked- devices.html
for a sample hacker resource.
Configuration vulnerabilities also include features that increase attack surface. A common example is a feature that is on by default but you are not using, so you didn't configure it and the default configuration is vulnerable. It also includes debug features like status pages or dumping stack traces on failures.
You should look through the Gruyere code looking for default configurations or debug features that don't belong there.
This attack isn't a a configuration vulnerability, just bad code.
Find a way to change the sign in link in the upper right corner to point to
(The attack should be triggered after clicking the refresh link and without using XSS or a script.)
If you'd like to share this codelab with others, please consider tweeting or buzzing about it or posting one of these badges on your blog or personal page:
<script> function _feed(s) { alert("Your private snippet is: " + s['private_snippet']); } </script> <script src="http://google-gruyere.appspot.com/123/feed.gtl"></script>When the script in
feed.gtl
is
executed, it runs in the context of the attacker's web page and uses
the _feed
function which can do whatever it wants with
the data, including sending it off to another web site.
You might think that you can fix this by eliminating the function call and just having the bare expression. That way, when the script is executed by inclusion, the response will be evaluated and then discarded. That won't work because Javascript allows you to do things like redefine default constructors. So when the object is evaluated, the hosting page's constructors are invoked, which can do whatever they want with the values.
To fix, there are several changes you can make. Any one of these changes will prevent currently possible attacks, but if you add several layers of protection ("defense in depth") you protect against the possibility that you get one of the protections wrong and also against future browser vulnerabilities. First, use an XSRF token as discussed earlier to make sure that JSON results containing confidential data are only returned to your own pages. Second, your JSON response pages should only support
POST
requests, which prevents the script from
being loaded via a script tag. Third, you should make sure that the
script is not executable. The standard way of doing this is to append
some non-executable prefix to it,
like ])}while(1);</x>
. A script running in the same
domain can read the contents of the response and strip out the prefix,
but scripts running in other domains can't.
NOTE: Making the script not executable is more subtle than it seems. It's possible that what makes a script executable may change in the future if new scripting features or languages are introduced. Some people suggest that you can protect the script by making it a comment by surrounding it with
/*
and */
, but that's
not as simple as it might seem. (Hint: what if someone
included */
in one of their snippets?)
There's much more to XSSI than this. There's a variation of JSON called JSONP which you should avoid using because it allows script injection by design. And there's E4X (Ecmascript for XML) which can result in your HTML file being parsed as a script. Surprisingly, one way to protect against E4X attacks is to put some invalid XML in your files, like the
</x>
above.
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:
http://www.picasa.com/../../../../../../../etc/passwd
Information disclosure via path traversal
Find a way to readsecret.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
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.
secret.txt
via
this URL:
http://google-gruyere.appspot.com/123/../secret.txtSome 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 replacesecret.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
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
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?
..
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
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
../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
This is another example of a common bug. The server protects against non-administrators accessing certain URLs but the list includes
To fix, add
http://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
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.
http://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
NOTE: After performing the previous exploit, you'll need to
push the reset button.
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.
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
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
To fix, fix the two previous exploits.
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 http://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()
orsystem()
. 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.
Configuration Vulnerabilities
Applications are often installed with default settings that attackers can use to attack them. This is particularly an issue with third party software where an attacker has easy access to a copy of the same application or framework you are running. Hackers know the default account names and passwords. For example, looking at the contents ofdata.py
you know that
there's a default administrator account named 'admin' with the
password
'secret'. See http://www.governmentsecurity.org/Configuration vulnerabilities also include features that increase attack surface. A common example is a feature that is on by default but you are not using, so you didn't configure it and the default configuration is vulnerable. It also includes debug features like status pages or dumping stack traces on failures.
Information disclosure #1
Read the contents of the database off of a running server by exploiting a configuration vulnerability.You should look through the Gruyere code looking for default configurations or debug features that don't belong there.
Hint 1
Look at all the files installed with Gruyere. Are there any files
that shouldn't be there?
Hint 2
Look for a
.gtl
file that isn't referenced anywhere.
Exploit and Fixes
To exploit, you can use the debug dump
page
This exploit exposes the users' passwords. Passwords should never be stored in cleartext. Instead, you should use password hashing. The idea is that to authenticate a user, you don't need to know their password, only be convinced that the user knows it. When the user sets their password, you store only a cryptographic hash of the password and a salt value. When the user re-enters their password later, you recompute the hash and if it matches you conclude the password is correct. If an attacker obtains the hash value, it's very difficult for them to reverse that to find the original password. (Which is a good thing, since despite lots of advice to the contrary, users frequently use the same weak passwords for multiple sites.)
dump.gtl
to display the contents of the database via the following URL:
http://google-gruyere.appspot.com/123/dump.gtlTo fix, always make sure debug features are not installed. In this case, delete
dump.gtl
. This is an
example of the kind of debug feature that might be left in an
application by mistake. If a debug feature like this is necessary,
then it needs to be carefully locked down: only admin users should
have access and only requests from debug IP addresses should be
accepted.
This exploit exposes the users' passwords. Passwords should never be stored in cleartext. Instead, you should use password hashing. The idea is that to authenticate a user, you don't need to know their password, only be convinced that the user knows it. When the user sets their password, you store only a cryptographic hash of the password and a salt value. When the user re-enters their password later, you recompute the hash and if it matches you conclude the password is correct. If an attacker obtains the hash value, it's very difficult for them to reverse that to find the original password. (Which is a good thing, since despite lots of advice to the contrary, users frequently use the same weak passwords for multiple sites.)
Information disclosure #2
Even after implementing the fix described above, an attacker can undo it and execute the attack! How can that be?Hint
You can upload a file of any type.
Exploit and Fixes
To exploit, Gruyere allows the user to upload files of any
type, including
To fix, we should do several things:
.gtl
files. So the attacker can simply
upload their own copy
of dump.gtl
or a
similar file and than access it. In fact, as noted earlier, hosting
arbitrary content on the server is a major security risk whether it's
HTML, JavaScript, Flash or something else. Allowing a file with an
unknown file type may lead to a security hole in the future.
To fix, we should do several things:
- Only files that are part of Gruyere should be treated as templates.
- Don't store user uploaded files in the same place as application files.
- Consider limiting the types of files that can be uploaded (via a whitelist).
Information disclosure #3
Even after implementing the fixes described above, a similar attack is still possible through a different attack vector. Can you find it?This attack isn't a a configuration vulnerability, just bad code.
Hint 1
You can insert something in your private snippet which will display the contents of the database.
Hint 2
This attack is closely related to the previous ones. There is a bug
in the code that expands templates that you can exploit.
Exploit and Fixes
There is a defect in Gruyere's template expansion code that reparses
expanded variables. Specifically, when expanding a block it expands
variables in the block. Then it parses the block as a template and
expands variables again,
To exploit, add this to your private snippet:
This exploit is possible because the template language allows arbitrary database access. It would be safer if the templates were only allowed to access data specifically provided to them. For example, a template could have an associated database query and only the data matched by that query would be passed to the template. This would limit the scope of a bug like this to data that the user was already allowed to access.
To exploit, add this to your private snippet:
{{_db:pprint}}To fix, modify the template code so it never reparses inserted variable values. The defect in the code is due to the fact that
ExpandTemplate
calls _ExpandBlocks
followed by _ExpandVariables
,
but _ExpandBlocks
calls ExpandTemplate
on
nested blocks. So if a variable is expanded inside a nested block and
contains something that looks like a variable template, it will get
expanded a second time. That sounds complicated because it is
complicated. Parsing blocks and variables separately is a fundamental
flaw in the design of the expander, so the fix is non-trivial.
This exploit is possible because the template language allows arbitrary database access. It would be safer if the templates were only allowed to access data specifically provided to them. For example, a template could have an associated database query and only the data matched by that query would be passed to the template. This would limit the scope of a bug like this to data that the user was already allowed to access.
AJAX vulnerabilities
Bad AJAX code allows attackers to modify parts of your application in ways that you might not expect. In traditional client development, there is a clear separation between the application and the data it displays. That's not true in web applications as the next two attacks will make clear.DoS via AJAX
Find an attack that prevents users from seeing their private snippets on the home page. (The attack should be triggered after clicking the refresh link and without using XSS.)Hint 1
Can you figure out how to change the value of the private snippet in
the AJAX response?
Hint 2
What happens if a JSON object has a duplicate key value?
Exploit and Fix
To exploit, create a user
named
To fix, the AJAX code needs to make sure that the data only goes where it's supposed to go. The flaw here is that the JSON structure is not robust. A better structure would be
private_snippet
and create at least one
snippet. The JSON response will then be {'private_snippet' :
<user's private snippet>, ..., 'private_snippet' :
<attacker's snippet>}
and the attacker's snippet replaces
the user's.
To fix, the AJAX code needs to make sure that the data only goes where it's supposed to go. The flaw here is that the JSON structure is not robust. A better structure would be
[<private_snippet>, {<user> :
<snippet>,...}]
.
Phishing via AJAX
While the previous attack may seem like a minor inconvenience, careless DOM manipulation can lead to much more serious problems.Find a way to change the sign in link in the upper right corner to point to
http://evil.example.com
.
(The attack should be triggered after clicking the refresh link and without using XSS or a script.)
Hint 1
Look at what the script does to replace the snippets on the page. Can
you get it to replace the sign in link?
Hint 2
Look at the AJAX code to see how it replaces each snippet, and then
look at the structure of the home page and see if you can see what
else you might be able to replace. (You can't just replace the sign in
link. You'll have to replace a bit more.)
Exploit and Fix
To exploit, create a user
named
To fix, the process of modifying the DOM needs to be made more robust. When user values are used in as DOM element identifiers, you should ensure that there can't be a conflict as there is here, for example, applying a prefix to user values like
This spoofing attack is easily detected when the user clicks Sign in and ends up at
menu-right
and publish a snippet that looks exactly
like the right side of the menu bar.
<a href='http://evil.example.com/login'>Sign in</a> | <a href='http://evil.example.com/newaccount.gtl'>Sign up</a>If the user is already logged in, the menu bar will look wrong. But that's ok, since there's a good chance the user will just think they somehow accidentally got logged out of the web site and log in again.
To fix, the process of modifying the DOM needs to be made more robust. When user values are used in as DOM element identifiers, you should ensure that there can't be a conflict as there is here, for example, applying a prefix to user values like
id="user_"
. Even better, use your own
identifiers rather than user values.
This spoofing attack is easily detected when the user clicks Sign in and ends up at
evil.example.com
. A clever attacker could
do something harder to detect, like replacing the Sign in link with a
script that renders the sign in form on the current page with the form
submission going to their server.
Other Vulnerabilities
Buffer Overflow and Integer Overflow
A buffer overflow vulnerability exists when an
application does not properly guard its buffers and allow user data to
write past the end of a buffer. This excess data can modify other
variables, including pointers and function return addresses, leading
to arbitrary code execution. Historically, buffer overflow
vulnerabilities have been responsible for some of the most widespread
internet attacks
including SQL
Slammer, Blaster
and Code
Red computer worms. The PS2, Xbox and Wii have all been hacked
using buffer overflow exploits.
While not as well known, integer overflow vulnerabilities can be just as dangerous. Any time an integer computation silently returns an incorrect result, the application will operate incorrectly. In the best case, the application fails. In the worst case, there is a security bug. For example, if an application checks that
This codelab doesn't cover overflow vulnerabilities because Gruyere is written in Python, and therefore not vulnerable to typical buffer and integer overflow problems. Python won't allow you to read or write outside the bounds of an array and integers can't overflow. While C and C++ programs are most commonly known to expose these vulnerabilities, other languages are not immune. For example, while Java was designed to prevent buffer overflows, it silently ignores integer overflow.
Like all applications, Gruyere is vulnerable to platform vulnerabilities. That is, if there are security bugs in the platforms that Gruyere is built on top of, then those bugs would also apply to Gruyere. Gruyere's platform includes: the Python runtime system and libraries, AppEngine, the operating system that Gruyere runs on and the client side software (including the web browser) that users use to run Gruyere. While platform vulnerabilities are important, they are outside the scope of this codelab as you generally can't fix platform vulnerabilities by making changes to your application. Fixing platform vulnerabilities yourself is also not practical for many people, but you can mitigate your risks by making sure that you are diligent in applying security updates as they are released by platform vendors.
While not as well known, integer overflow vulnerabilities can be just as dangerous. Any time an integer computation silently returns an incorrect result, the application will operate incorrectly. In the best case, the application fails. In the worst case, there is a security bug. For example, if an application checks that
length + 1 < limit
then this
will succeed if length
is the largest positive integer
value, which can then expose a buffer overflow vulnerability.
This codelab doesn't cover overflow vulnerabilities because Gruyere is written in Python, and therefore not vulnerable to typical buffer and integer overflow problems. Python won't allow you to read or write outside the bounds of an array and integers can't overflow. While C and C++ programs are most commonly known to expose these vulnerabilities, other languages are not immune. For example, while Java was designed to prevent buffer overflows, it silently ignores integer overflow.
Like all applications, Gruyere is vulnerable to platform vulnerabilities. That is, if there are security bugs in the platforms that Gruyere is built on top of, then those bugs would also apply to Gruyere. Gruyere's platform includes: the Python runtime system and libraries, AppEngine, the operating system that Gruyere runs on and the client side software (including the web browser) that users use to run Gruyere. While platform vulnerabilities are important, they are outside the scope of this codelab as you generally can't fix platform vulnerabilities by making changes to your application. Fixing platform vulnerabilities yourself is also not practical for many people, but you can mitigate your risks by making sure that you are diligent in applying security updates as they are released by platform vendors.
SQL Injection
Just as XSS vulnerabilities allow attackers to inject script into
web pages, SQL
injection vulnerabilities allow attackers to inject arbitrary
scripts into SQL queries. When a SQL query is executed it can either
read or write data, so an attacker can use SQL injection to read your
entire database as well as overwrite it, as described in the classic
Bobby Tables XKCD comic. If you use
SQL, the most important advice is to avoid building queries by string
concatenation: use API calls instead. This codelab doesn't cover SQL
injection because Gruyere doesn't use SQL.
After the Codelab
We hope that you found this codelab instructive. If you want more practice, there are many more security bugs in Gruyere than the ones described above. You should attack your own application using what you've learned and write unit tests to verify that these bugs are not present and won't get introduced in the future. You should also consider using fuzz testing tools. For more information about security at Google, please visit our blog or our corporate security page. And check out Google Code University for more educational resources on a variety of other topics.If you'd like to share this codelab with others, please consider tweeting or buzzing about it or posting one of these badges on your blog or personal page:
Cara hack akun fb
ReplyDelete