Simple port scanner with Python

If you like Python and NMap … there is a very good wrapper from Alexandre Norman! This tutorial show a very simple example for usage.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import nmap


def port_scan(target, ports):
    """
    Simple NMap port scanner example

    @param target: host for scan
    @type target: string
    @param ports: ports for scan
    @type ports: string
    """

    nmap_scan = nmap.PortScanner()
    nmap_scan.scan(str(target), str(ports))

    for host in nmap_scan.all_hosts():
        print '=' * 80
        print 'Host:\t%s' % host
        print 'State:\t%s\n' % nmap_scan[host].state()

        for protocol in nmap_scan[host].all_protocols():
            print 'Protocol(s): %s' % protocol

            port_list = list(nmap_scan[host][protocol].keys())
            port_list.sort()

            for port in port_list:
                print '\n[+] Port: %s' % port
                print '[+] State: %s' % nmap_scan[host][protocol][port]


if __name__ == '__main__':
    port_scan('192.168.192.1', '1-1000')

For running see following lines:

# change execution
$ chmod u+x example.py

# start script
$ python -B ./example.py

 

Collecting Skype information with own python package

This time i will present 2 tutorials in one. One part describe how to create a simple Python package. The other part gives security testers a hint for sensible data. It is recommended to work with python virtualenv!

Preconditions

  • Python 2.7.x
  • pip, virtualenv, setuptools
  • Skype

Background

Skype stores sensible data, unencrypted, in a simple sqlite database (main.db). You would be surprised what information can be found there!

Example Locations

  • Mac OS – /Users/Library/Application Support/Skype/main.db
  • Windows – C:\Documents and Settings\Application Data\Skype\main.db

Python Package

.
├── MANIFEST.in
├── README.rst
├── SkypeSpy
│   └── __init__.py
└── setup.py
# -*- coding: utf-8 -*-
from setuptools import setup


def readme():
    with open('README.rst') as f:
        return f.read()

setup(
    name='SkypeSpy',
    version='1.0.0',
    description='Read values from Skype sqlite',
    long_description=readme(),
    url='<domain>',
    author='<author>',
    author_email='<email>',
    license='<license>',
    packages=['SkypeSpy'],
    include_package_data=True
)
SkypeSpy
--------

To use (with caution), simply do::

    >>> from SkypeSpy import SkypeInformation
    >>> SkypeInformation.set_db_path('path')
    >>> print SkypeInformation.get_accounts()
    >>> print SkypeInformation.get_contacts()
include README.rst
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sqlite3


class SkypeInformation(object):

    __DATABASE_PATH = str()

    @staticmethod
    def set_db_path(db_path):

        SkypeInformation.__DATABASE_PATH = str(db_path)

    @staticmethod
    def __read_from_db(sql_statement):
        """
        Read testsuite from sqlite file

        @type sql_statement: string
        @param sql_statement: sqlite select statement
        @return: list
        """

        db = sqlite3.connect(SkypeInformation.__DATABASE_PATH)
        statement = str(sql_statement)

        try:
            cursor = db.cursor()
            cursor.execute(statement)
            values = cursor.fetchall()
        except sqlite3.Error:
            values = list()
        finally:
            db.close()

        return values

    @staticmethod
    def get_accounts():

        statement = """SELECT DISTINCT
                       liveid_membername, skypename, fullname, gender,
                       languages, country, province, city, phone_home,
                       phone_office, phone_mobile, emails, homepage
                       FROM Accounts;"""

        return SkypeInformation.__read_from_db(statement)

    @staticmethod
    def get_contacts():

        statement = """SELECT DISTINCT
                       skypename, fullname, gender, languages, country,
                       province, city, phone_home, phone_office, phone_mobile,
                       emails, homepage
                       FROM Contacts;"""

        return SkypeInformation.__read_from_db(statement)

Install and execute

You can now create another environment (with virtualenv) and install the package.

# install via pip
$ pip install file:///path/to/SkypeSpy
#!/usr/bin/env python
import os
from SkypeSpy import SkypeInformation


def run():
    my_path = '/path/to/main.db'
    if os.path.exists(my_path):
        SkypeInformation.set_db_path(my_path)
        print SkypeInformation.get_contacts()
        print SkypeInformation.get_accounts()

if __name__ == '__main__':
    run()

More

There are other tables with information! Expand the package as desired.

Find out subdomains

One way of finding out subdomains are wordlists. Knockpy offers exactly this possibility! It is written in Python, easy to install and to use. The usage of own wordlists is possible, too. The output displayed in the terminal and saved in CSV file.

Precondition

  • Python installed

Installation

# install with pip
$ sudo pip install https://github.com/guelfoweb/knock/archive/knock3.zip

Usage

# usage with internal wordlist
$ knockpy domain.com

# usage with own wordlist
$ knockpy domain.com -w wordlist.txt

# resolve domain name
$ knockpy -r domain.com

# check zone transfer
$ knockpy -r domain.com

FTP Brute-force attack

As a penetration tester you may need to check your FTP Server(s). One possibilty is brute-force passwords to auditing. This tutorial show you how easy you can use Python to create such a tool.

Precondition

  • Python installed
  • Crunch installed (Tutorial)

Create Python Script

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import argparse
import ftplib
import socket
import sys
from datetime import datetime


class FtpCrack(object):

    def __init__(self, host, username='', password=''):
        if not host:
            print "[*] Error: no host given"
            sys.exit(2)
        else:
            self.start = datetime.now()
            self.host = host
            self.username = username
            self.password = password
            self.ftp = None

    def _close_ftp_connection(self):
        self.ftp.quit()
        print "[*] Close FTP connection after ", datetime.now() - self.start

    def _list_ftp_directory(self):
        try:
            print "[*] List FTP directory content"
            self.ftp.dir()
        except ftplib.all_errors:
            print "[*] ERROR: Cannot list content"
        self._close_ftp_connection()

    def ftp_connect(self):
        try:
            self.ftp = ftplib.FTP(self.host)
        except (socket.error, socket.gaierror) as err:
            print "[*] Cannot connect to %s" % self.host
            print "[*] Error %s" % err
            sys.exit(2)

        print "[*] Connected to %s" % self.host

    def _ftp_anonymous_login(self):
        try:
            self.ftp.login()
        except ftplib.error_perm:
            print "[*] ERROR: cannot login anonymously"
            self._close_ftp_connection()
            sys.exit(2)

        print "[*] Anonymous login"
        self._list_ftp_directory()

    def _ftp_credential_login(self):
        print "[*] User: %s - Password: %s" % (self.username, self.password)
        try:
            self.ftp.login(self.username, self.password)
        except ftplib.error_perm:
            print "[*] ERROR: wrong credentials"
            self._close_ftp_connection()
            sys.exit(2)

        print "[*] Login with credentials"
        self._list_ftp_directory()

    def ftp_login(self):
        if not self.username or not self.password:
            self._ftp_anonymous_login()
        else:
            self._ftp_credential_login()


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Brute-force FTP')
    parser.add_argument('host', help='target host or ip')
    parser.add_argument('-u', '--usr', help='login user name')
    parser.add_argument('-p', '--pwd', help='login password')
    args = parser.parse_args()

    RUN = FtpCrack(args.host, args.usr, args.pwd)
    RUN.ftp_connect()
    RUN.ftp_login()

The code should be clear and self-explanatory.

Usage examples

# show help
$ ./FtpCrack.py -h

# example anonymous ftp
$ ./FtpCrack.py <host>

# example with credentials
$ ./FtpCrack.py <host> -u <user> -p <password>

# example crunch (pipe to password)
$ ./crunch 3 3 abc | xargs -I password ./FtpCrack.py <host> -u <user> -p password

You can extend the code, for example to read the content from wordlists.

Create information gathering test application

It is time again for an extensive tutorial. This time, a tiny test application for passive and active information gathering. After the instruction you are welcome to improve the application with more features! Okay let’s start…

What should it do?

The security tester selects a information gathering method first. As second step the testers insert the URL or IP in a testfield and press a button. The result should printed out in a text area. The GUI should look like this:

Sensei Mockup

How it is implemented?

The prefered language is Python 2.7. So it is portable to different OS and for the most of methods are already packages available. The GUI is done with Tkinter. Tkinter provides all objects which are needed as widgets and ranges for this scope out completely. The file and folder structure look like:

├── essential
│   ├── __init__.py
│   └── timestop.py
├── gathering
│   ├── __init__.py
│   ├── geolocation.py
│   ├── icmpping.py
│   ├── information.py
│   ├── wappalyzer.py
│   └── whoisgathering.py
├── requirements.txt
└── sensei.py

File content

Files in root directory:

requests
python-Wappalyzer
python-whois
#!/usr/bin/env python
#  -*- coding: utf-8 -*-
from urlparse import urlparse
from gathering import IcmpPing, WhoisGathering, GeoLocation, WappAlyzer
from Tkinter import (Tk, Frame, StringVar, OptionMenu, Entry, Button, Text,
                     W, E, END, FALSE)


class Sensei(object):

    def __init__(self):
        self.root = Tk()
        self.root.title('Sensei')
        self.root.resizable(width=FALSE, height=FALSE)
        self.select = [
            'ICMP Ping', 'Whois', 'GeoLocation', 'Wappalyzer'
        ]
        self.option = StringVar(self.root)
        self.option.set(self.select[0])
        self.method = None
        self.url = None
        self.result = None

    def create_gui(self):
        self._top_frame()
        self._output_frame()
        self.root.mainloop()

    def quite_app(self):
        self.root.quit()

    def _start_request(self):
        self.result.delete(1.0, END)
        action = None
        target = self.url.get()
        method = self.option.get()
        if method == 'ICMP Ping':
            action = IcmpPing()
        elif method == 'Whois':
            action = WhoisGathering()
        elif method == 'GeoLocation':
            action = GeoLocation()
        elif method == 'Wappalyzer':
            action = WappAlyzer()
        if target:
            action.set_target(target)
            action.do_request()
            value = action.get_result()
        else:
            value = 'Internal Error'
        self.result.insert(END, value)

    def check_protocol(self, value):
        target = self.url.get()
        if value == 'Wappalyzer':
            if 'http' not in target:
                self.url.insert(0, 'http://')
        else:
            if 'http' in target:
                new_target = urlparse(target)
                self.url.delete(0, END)
                self.url.insert(0, new_target[1])

    def _top_frame(self):
        top_frame = Frame(self.root)
        top_frame.grid(column=0, row=0, sticky=W+E)
        self.method = OptionMenu(
            top_frame, self.option, *self.select, command=self.check_protocol
        )
        self.method.config(width=15)
        self.method.grid(column=0, row=0)
        self.url = Entry(top_frame, width=50)
        self.url.grid(column=1, row=0)
        Button(top_frame, text='Request', command=self._start_request).grid(
            column=2, row=0)
        Button(top_frame, text='Close', command=self.quite_app).grid(
            column=3, row=0)

    def _output_frame(self):
        output_frame = Frame(self.root)
        output_frame.grid(column=0, row=2, sticky=W+E)
        self.result = Text(output_frame, height=15)
        self.result.grid(column=0, row=0)


if __name__ == '__main__':
    RUN = Sensei()
    RUN.create_gui()

Files in essential:

#!/usr/bin/env python
#  -*- coding: utf-8 -*-
from essential.timestop import TimeStop
#!/usr/bin/env python
#  -*- coding: utf-8 -*-
from datetime import datetime


class TimeStop(object):
    """missing docstring"""

    __start = None

    @classmethod
    def start_measure(cls):
        cls.__start = datetime.now()

    @classmethod
    def stop_measure(cls):
        stop = datetime.now()
        total = stop - cls.__start
        return ">>>> request complete in " + str(total)

Files in gathering:

#!/usr/bin/env python
#  -*- coding: utf-8 -*-

from gathering.information import InformationGathering
from gathering.icmpping import IcmpPing
from gathering.whoisgathering import WhoisGathering
from gathering.geolocation import GeoLocation
from gathering.wappalyzer import WappAlyzer
#!/usr/bin/env python
#  -*- coding: utf-8 -*-


class InformationGathering(object):

    def __init__(self):
        self.errors = 0
        self.target = ''
        self.result = ''

    def set_target(self, target):
        victim = target.strip(' \t\n\r')
        if not victim:
            self.errors += 1
            self.result = 'No target given!'
        else:
            self.target = target

    def get_result(self):
        return self.result
#!/usr/bin/env python
#  -*- coding: utf-8 -*-
from gathering.information import InformationGathering
from essential.timestop import TimeStop
import os
import platform


class IcmpPing(InformationGathering):

    COMMAND = ''

    def __create_command(self):
        operation_system = platform.system()
        if operation_system == "Windows":
            self.COMMAND = "ping -n 1 "
        elif operation_system == "Linux":
            self.COMMAND = "ping -c 1 "
        else:
            self.COMMAND = "ping -c 1 "

    def do_request(self):
        if self.errors == 0:
            self.__create_command()
            command = self.COMMAND + self.target
            TimeStop.start_measure()
            response = os.popen(command)
            for line in response.readlines():
                self.result += line
            self.result += TimeStop.stop_measure()
#!/usr/bin/env python
#  -*- coding: utf-8 -*-
from gathering.information import InformationGathering
from essential.timestop import TimeStop
import whois


class WhoisGathering(InformationGathering):

    def do_request(self):
        if self.errors == 0:
            TimeStop.start_measure()
            result = whois.whois(self.target)
            self.result += result.text
            self.result += TimeStop.stop_measure()
#!/usr/bin/env python
#  -*- coding: utf-8 -*-
from gathering.information import InformationGathering
from essential.timestop import TimeStop
import requests


class GeoLocation(InformationGathering):

    API = 'http://ip-api.com/json/'

    def do_request(self):
        if self.errors == 0:
            target = self.API + self.target
            TimeStop.start_measure()
            response = requests.get(target)
            output = response.json()
            for key, val in output.items():
                if val:
                    self.result += str(key) + " => " + str(val) + "\n"
            self.result += TimeStop.stop_measure()
#!/usr/bin/env python
#  -*- coding: utf-8 -*-
from gathering.information import InformationGathering
from essential.timestop import TimeStop
from Wappalyzer import Wappalyzer, WebPage


class WappAlyzer(InformationGathering):

    def do_request(self):
        if self.errors == 0:
            TimeStop.start_measure()
            wappalyzer = Wappalyzer.latest()
            website = WebPage.new_from_url(self.target)
            output = wappalyzer.analyze(website)
            for val in output:
                self.result += " => " + str(val) + "\n"
            self.result += TimeStop.stop_measure()

That was it. The result looks like this:

Sensei

Improve it with your ideas!

Scan Wifi from Terminal

There is a command line tool that allows you to work with the wireless connection on your Mac. The tool is very useful but by default hidden and not well documented.

airport

# show airport help
$ /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport --help

networksetup

# find device names
$ networksetup -listallhardwareports

Turn on/off and join

# turn it off
$ networksetup -setairportpower en0 off

# turn it on
$ networksetup -setairportpower en0 on

# join a network
$ networksetup -setairportnetwork en0 <SSID> <Password>

Let`s start a wifi scan and get some information

# scan with interface en0
$ /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport en0 --scan

# show information of en0
$ /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport en0 --getinfo

Note: If do not specify the interface, airport will use the first wifi interface on the system.

Easy way

# create a symbolic link to the command
$ sudo ln -s /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport /usr/sbin/airport

# after link created start the scan
$ airport en0 --scan

Sniff

# find WEP
$ airport en0 scan | grep WEP

# start sniff on channel
$ airport en0 sniff 6

The captured packets you will find as “/tmp/airportSniffXXXXXX.cap”.

Simple ssh brute-force attack with Hydra

With Hydra you can recover your SSH credentials. Here a tiny tutorial how it works.

Installation

I do install via ports but also different other possibilities are available.

# update macports (optional)
$ sudo port selfupdate

# search port (optional)
$ port search hydra

# check dependencies (optional)
$ port rdeps hydra

# install port
$ sudo port install hydra

Test preparation

Now create two files (or download anywhere)

# create password file
$ vim passwords.txt

# create users file
$ vim users.txt

Create some content (by line) and start the ssh brute-force with Hydra.

Run SSH password recover

# use password.txt only
$ hydra -l root -P passwords.txt <target> ssh

# use user.txt only
$ hydra -L users.txt -p 12345 <target> ssh

# use user and password files
$ hydra -L users.txt -P passwords.txt <target> ssh

If Hydra found something, the message looks like:

[22][ssh] host: <target> login: <user> password: <password>

Note: for legal purposes only!

Wordlists with crunch

Crunch is very nice, fast and and well configurable wordlist generator. You can specify character sets and generate wordlists in all possible combinations.

Conditions

Linux/Mac OS X with C compiler and make

For Mac OS X users, just install the Command Line Tools.

Steps

Download the latest source from SourceForge.net, unzip and compile.

# unzip
$ tar -zxvf crunch-3.6-2.tgz

# go into folder
$ cd crunch-x.x

# compile
$ make -f Makefile

After create the crunch executable you can start to create wordlist files.

Examples

The first example create the wordlist direct in terminal. All words contain 5 letters with chars “a”, “b” and “c”.

$ ./crunch 5 5 abc

The next example create the wordlist into the file (mylist.txt) with 5 numbers of 0 to 9.

$ ./crunch 5 5 0123456789 -o myfile.txt

Now it should create words with different length from 1 to 3 and mix of chars (A,B,C) and numbers (1,2,3).

$ ./crunch 1 3 ABC123 -o myfile.txt

There is more, crunch include permutation and defined charsets.

# example permutation
# the numbers aren't processed but are needed
$ ./crunch 4 5 -p peter tom susi

# example charset numeric (0-9)
$ ./crunch 5 5 -f ./charset.lst numeric -o myfile.txt

# example invert
$ ./crunch 5 5 -i -f ./charset.lst numeric -o myfile.txt

It is possible to use placeholder (like: @ , % and ^), to define the target size of files and compression. You can create wordlists for IBAN, telephone numbers, e-mails and many more. Read the man page of crunch!!!

# example
$ ./crunch 8 8 -t %%%%%%%%% -u | aircrack-ng -e [SSID] -w [*.cap]
  • @ will insert lower case characters
  • , will insert upper case characters
  • % will insert numbers
  • ^ will insert symbols

Last comment

Please be carefully with generated file size!!!