Header-Bar

March 16, 2014

Build Your First Scanning Tool - Simple intro to Python & Sublime Editor

Intro

Hi,
In today's lab we will learn how to make a tiny scanning tool that will help us understand a little bit more about how the network works and how an attacker can utilize in-the-wild resources in order to gain useful information.
Before we start coding, let's remember that this usage is malicious and it is strictly forbidden outside the lab (not including homework testing).

What are we going to do?

Ok, so a hacker can gain information from the network by simply querying it. But what does querying means?







 



So as we can see, opening a socket is just like opening a phone call with a friend. One difference is that we're not noticing the amount of data that is being transferred while being concentrated on talking to each other.
For use humans its only 'chit-chat'. For the wire-hacker it is a chunk of useful information J

What is being streamed over the line?
We'll divide it into 2 main categories:
1.     Header
2.     Body or Message

The Header is every piece of information that is not being transferred as message, while message is… well… message is the content that both humans were interested in, before they picked up the phone.
Header information: Phone number for caller, Phone number on receiver, Service name (Service Provider), Language, Is the conversation still on, Hang-up method etc.
Message information: John: "Hello Gil, How are you?", Gil: "Hi John! I'm great. Thank you for asking."
By the way: when calling a friend, we as entities are also in charge of some Header values.
Example: Gil can end the call whenever she wants, by pressing the END button.

Now that we know we would like to start a conversation in order to get information, think of a situation where John doesn’t want to talk to Gil, but still knowing she's at home.
Trying to call, hearing her voice and immediately hang-up is one way. Can you think of other ways?
What if John wants to know if there are other phones in Gil's house?
What if through the phone, John could somehow call Gil's fax machine, or even her computer?
In order to get that information we have to query, remember?
We want to call and get the Header. Or we can look in the white-pages for more phone numbers related to Gil and start calling them, just to check if its ringing or not (just like a Ping).

ToolKit

First we will need to find a language that we can write our code in. 
I know that .NET and Java are very comfortable and can autocomplete stuff, so we're going to use Python.


Not just that. We're going to make it a little more interesting by using another open source tool.
Why? So we can write our Python code in it. Yes, we can use the Python Idle, but let's start with this one.
This tool is a Text Editor with abilities to read/write and execute scripts. Compiler is not an option for this lab.
Please download a very close friend of mine: SublimeText


That’s it. You're ready for action. J

Instructions

1.     Open Sublime Text
2.     Open a new label by going to File >> New File or simply hit Ctrl+N


3.     Write import socket (grey color)
4.     Save it as .py file (Python extension). It supposed to change the string to import socket
***if it doesn't work - download SublimeREPLit is an addon to get a Python Shell. (and a lot more!)

Goals

We are building a scanning tool, so we would like it to have the following abilities:
1.     Ping Sweep – scanning multiple remote machines using the "Ping" software.
2.     Port Scanner – Scanning a target for open ports.
3.     Banner Grabbing – Grabbing a banner (Header) from the conversation and investigating its content.
Let's see an example shall we?
Ping Sweep:
Scanning 1.1.1.1 should return:
1.1.1.0     Is UP!
1.1.1.1     Returned time out (means it is not answering, but could be open)
1.1.1.2     Is UP!
1.1.1.255 is UP!
Port Scanner:
Scanning 1.1.1.1 for ports [21, 22, 25, 80, 443, 3306] should return:
Port 21 (FTP) is open
Port 22 (SSH) is open
Port 25 (SMTP) is closed
Port 80 (HTTP) is open
Port 443 (HTTPS) is closed (no SSL connection, what an attacker will think about it?)
Port 3306 (MySQL) is open (juicy information)
Banner Grabbing:
Scanning 1.1.1.1 on port 80 with (GET / HTTP/1.1) should return:
HTTP/1.1 200 OK
Host: 1.1.1.1
Server: Apache/2.2.3
X-Powered-By: PHP/5.3.27
….
 ** 1.1.1.1 is not a real address. Use a Wi-Fi address at home and connect other devices to it.
You - 10.0.0.3
Rauter - 10.0.0.1
Printer - 10.0.0.2
Mobile - 10.0.0.4

Now that we know what we want to do. Let's start working.

Coding


Import the Socket and Subprocess modules:
import socket
import subprocess

Socket is a built-in module for easy creation and connection to TCP/UDP and other sockets.
This module provides access to the BSD socket interface. It is available on all modern Unix systems, Windows, Mac OS X, BeOS, OS/2, and probably additional platforms.
Subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes.example - CMD
Now let's write the first function, follow my lead:
Ping Sweep
First line is the function. 
Blue for definition of public function,
Green for function name, Orange for stored variable and function variables and Yellow for strings.
To get the ping communication we have to use the Subprocess module. Subprocess has a common function called Popen() which receives 3 arguments: 1st is an array with command and host and the other two is for piping the information from the process to 2 other arguments stdout, stderr
One takes the message and the other takes the error.
You can see the payload from subprocess.Popen is being imported into ping variable. ping will than receive an "extensions power-up" (i.e. inherit functions from subprocess) and will be able to use a function called communicate(). This function returns 2 values in correlation to the 2 arguments we set in Popen().
The out variable will return from the function, but not before we will parse some information from this big payload. We don't need all the information, so we will look for a pattern like IP:
[+] m = re.search | re stands for Regular Expressions and search is simply a search in content.
What is the content you ask? search receives 2 arguments: 1 is what to look for and 2 is the content. As for this example: 2 is out which is our ping payload, for example–
C:\>ping 1.1.1.1
Pinging 1.1.1.1 with 32 bytes of data:
Request timed out.
Request timed out.

So if we want the function to work, we need to add:
import re
Right under the other imports.
But what is this:
(\d+\.\d+\.\d+\.\d+)
Well [\d] is a digit placeholder in Regular Expression language. [\.] Is simply [.], because [.] means "every character".
Adding a [+] sign means we are looking for more than 1 digit. 1 or more to be exact.
So we have [\d+] (digits) [\.] (dot) repeated 3 times and ends with [\d+] (digits) – IPv4 representation!
*** 1234.1234.1234.1234 is also a valid output... Can you fix the Regex to receive only IPv4?

That’s it! We have a Ping command. Later we will create a loop to create the Ping Sweep

Moving forward:
Port Scanner



So what do we have here? 
First we have the function and name, but that you already know. The function takes 3 arguments.
We can't be sure that the protocol value will be in the same case (lower, upper) so we use the upper() function which will turn this "tcp" into this "TCP", because Python is case sensitive.
Then we will use the Socket module (import socket) as followed:
We've created a variable called "tcp" that receives socket with AF_INET (which means – I'm using IPv4) and the SOCK_STREAM (which means – I'm using TCP).
How can we represent IPv6? And UDP? Find out!

The socket.connect() function will create a TCP handshake using the tuple of 2 arguments (host, port) and internal variables which are being automatically loaded by the socket module.
Then, if the port is not 80, we will use a general "Hello" string and if it is 80, we will generate an HTTP request (GET/POST/HEAD…)
***Yes, other socket methods such as SSH, FTP over TCP has conventions and syntax, but I'll leave it to you to find out.

Finally we need to somehow capture the response from the communication we've created with the remote server. Using recv() with size of payload (200) (i.e. approximately the size of a header) we can capture the right information we need to return the header data.
If you want more data simply increase the value of recv().

That’s it! Port Scanner is done. Easy right J

Banner Grabbing
Hold on. Banner grabber is our longest function.

Ok, so we have a bit more code here. 
Let's dig it up.
First of all we have the same function declaration. This time the function name is bannerGrabbing.
Than we have a variable called header which will receive data coming from the portScanner() function.
Why, you ask? Because we need to open a TCP socket anyways, so instead of implementing the same code twice, we will just use our function.
Header will receive payload such as:

SSH-2.0-OpenSSH_5.3p1 Debian-3ubuntu7

HTTP/1.0 200 OK 
Content-type: text/html 
Date: Wed, 12 Mar 2014 20:29:52 GMT 
Server: Apache/2.2.3
Connection: close 
X-Powered-By: PHP/5.3.27
Cache-Control: no-store 

220 FTP version 1.0 ready at Wed Mar 12 19:52:27 2014 
530 User anonymous cannot log in. 
Login failed.

And more.
What we need is to parse those banners and identify if we can extract valuable information.
Continuing with the code, if header has data in it, we will try to look for information.
If the port is 80, means HTTP, we're looking for the Server: banner using the Regular Expression re.search. This will give us information about the operating system. For instance – IIS is installed only on Microsoft Windows machines. Nginx and Apache could be a Linux web servers, but can also be installed on a Windows machine (not so common).
Plus, SSH utility is only supported on Linux, So we can gather information using multiple ports.
If port 80 has an Nginx server and port 22 is open (SSH), that means it's a Linux server, right?
We can also see it in the example above: Debian-3ubuntu7
We are also searching for X-Powered-By header which maybe result in disclosing the back-end language and its version.
Then we're simply looking for SSH, FTP and MySQL. We can extend it to look for more banners, but its enough for now.
service_name = re.search(re.compile('SSH', re.I|re.M), header)
As for lines like the above: when using re.compile we need to supply another argument along with the string we're looking for.
This argument re.I and re.M stands for Ignore case (case sensitivity) and Multi-line for multi-lined payload parse.
Service_name will not return as string so we are using group(0) to get the string representation.

Moving forward to our next block of code:
**notice that the if __name__=='__main__': line indicates the interpreter that it starts the script execution from that line down.
It means that the above lines are class/func/... and other pieces of code which are callable.
Help manual

This is very self-explanatory once you look at the menu: 
C:\proj>python portScanner.py
Usage: portScanner.py [options]

Options:
  -h, --help          show this help message and exit
  -t www.exemple.com  Enter target name or ip
  -i TIME_INTERVAL    Time interval between each scan in milliseconds
  -p [TCP/ICMP]       Returns the type of scan.
  -b BANNER           Set to 1 for Banner Grabbing

C:\proj>

The only thing that is not in the menu is dest, which stores the value of the argument.
If dest="banner" and the user supplied –b something
Then now options.banner = "something". The type is optional, but it is very good for input validation.

Ok so we have the manual. Now we need to write an else statement to that last if.
The last if states that if the user did not supply a targethost and/or a protocol (-t or -p), than the menu will pop again and the program won't start.


In the else statement we first like to make the options clearer, so it is recommended to transfer the values into shorter variables. 

From here on out, you're on your own!

Coding yourself

1.     For c:\>python Scanner.py –t example.com –p ICMP
a.     Call pingSweep with loop.
[Hint – if example.com translated to 12.15.75.53 you need to grab 12.15.75. and start appending range(1,254)]
b.     Use Regular Expression module to slice the IP string.
[Hintparsed_ip = re.search(r'HERE_COMES_YOUR_RE', ip)
To switch from host to IP use: ip=socket.gethostbyname(host)]
c.     Figure out how to return if the host is UP or not. If UP return – [IP number] is UP!
Else: return the ICMP replay (time out, destination unreachable).
2.     For c:\>python Scanner.py –t example.com –p TCP
a.     Return portScanner for the list of ports in the above code snippet
b.     If port is open return "port %s is open" % (port)
Else: "port %s is closed" % (port)
**the % after the string is a reference for the %s place holder.
3.     For c:\>python Scanner.py –t example.com –p TCP –b 1
a.     Return bannerGrabbing + portScanner
[Hint – create a loop of port numbers from ports array that returns the banner payload]
b.     Use try: and except: to capture errors. Return "Error" on except
4.     For c:\>python Scanner.py –t localhost –p UDP
a.     Create a client in our code, where the if UDP comment is, that simulates a UDP client (sends data through UDP to a fixed port (say 5454)).
b.     Create another python file called server.py that will listen to the same port (on localhost).
[Hint – UDP does not use connect(), it uses bind() from socket module.]

*To send and receive data through UDP, both files should run simultaneously.


                


Good Luck!


No comments:

Post a Comment