おいも貴婦人ブログ

生物系博士課程満期退学をしたAIエンジニアのブログ。

第4回:Pythonでネットワークプログラミング(Netcat的なものを実装)

そもそも、Netcaってなんなの?ということで、Wikipediaへ。どうやら、TCPUDPのパケットを読み書きできるコマンドラインツールらしい...。とりあえず、本で紹介されているので実装してみましょう。紹介したプログラムは、ファイルのアップロード、コマンドの実行をすることができます。sshとscpの非常に簡単版です。もちろん暗号化されていないのでお遊びだと考えてください。参考としている本とは、多少コードが違いますので、元ネタを知りたい方は参考文献へ。ここで力尽きました...。残っているタイトルは後日作成します。

Black Hat Python: Python Programming for Hackers and Pentesters

Black Hat Python: Python Programming for Hackers and Pentesters

Netcat的なものを実装

#! /usr/bin/env python
# coding:utf-8
# netcat.py

import sys
import socket
from optparse import OptionParser
import threading
import subprocess


listen = False
command = False
upload = False
execute = ''
target = ''
upload_destination = ''
port = 0

def usage():
    """オプションの解析"""
    """サーバー側での実行例(コマンドの受付):netcat.py -l -p 5555 -c """
    """クライアント側での実行例(コマンドの受け渡し):netcat.py -t 0.0.0.0 -p 5555"""
    """Fileのアップロード,-u"""

    description="Examples:\n\r\
    netcat.py -t 192.168.0.1 -p 5555 -l -c\n\
    netcat.py -t 192.168.0.1 -p 5555 -l -c -u=c:\\target.ext\n\
    netcat.py -t 192.168.0.1 -p 5555 -l -c -e=\"cat /etc/passwd\"\n\
    echo 'ABCDEFGHI' | netcat.py -t 192.168.0.1 -p 135\n\
    "

    parser=OptionParser(usage='%prog [-c] [-l] [-u] [-e] [-t] [-p]',epilog=description)
    parser.add_option('-c','--commandshell',help='initialize a command shell',default=False,action='store_true')
    parser.add_option('-u','--upload',help='upon receiving connection upload a file and write to [destination]',default='')
    parser.add_option('-l','--listen',help='listen on [host]:[port] for incoming connections',default=False,action='store_true')
    parser.add_option('-e','--execute',help='ececute the fiven file upon receiving a command shell',default='')
    parser.add_option('-t','--target',help='',default='')
    parser.add_option('-p','--port',help='',type=int)
    
    opt,args=parser.parse_args()
    
    global listen
    global port 
    global execute
    global command
    global upload_destination
    global target

    listen = opt.listen
    command = opt.commandshell
    upload = opt.upload
    execute = opt.execute
    target = opt.target
    upload_destination = opt.upload
    port = opt.port
    

def main():
    global listen
    global port 
    global execute
    global command
    global upload_destination
    global target
    
    usage()

    if not listen and len(target) and port > 0:
        print ":Client mode"
        buffer = sys.stdin.readline()
        client_sender(buffer)

    if listen:
        print ":Server mode"
        server_loop()

        
def client_sender(buffer):
    client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    try:
        client.connect((target,port))
        #コネクションの確率

        if len(buffer):
            client.send(buffer)
            
        while True:
            recv_len = 1
            response = ''

            while recv_len:
                buf_size = 4096
                data = client.recv(buf_size)
                recv_len = len(data)
                response += data

                if recv_len < buf_size:
                    break

            print response,
            #クライアント側で実行した結果を受け取り、表示する。
            
            buffer = raw_input('')
            #クライアントの要求の受付を継続する。
            buffer += '\n'
            client.send(buffer)

    except:
        print '[*] Exception! Exiting.'
        client.close()


def server_loop():
    global target
    global port
    
    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()
        print addr
        client_thread = threading.Thread(target=client_handler,args=(client_socket,))
        #threadingに関しては過去の記事を参照してください。
        client_thread.start()


def run_command(command):
    command = command.rstrip()
    #改行の削除
    try:
        output = subprocess.check_output(command,stderr=subprocess.STDOUT,shell=True)
        #コマンドの実行を結果をoutputに保存する。
        #subprocessはpythonの標準ライブラリなので、勉強する価値はあります。公式のドキュメントが分かりやすいです。
    except:
        output = 'Failed to execute command.\n\r'
    return output


def client_handler(client_socket):
    global upload
    global execute
    global command
    
    if len(upload_destination):
        file_buffe = ''

        while True:
            buf_size = 1024
            data = client_socket.recv(buf_size)
            
            if not data:
                break
            else:
                file_buffer += data
        try:
            file_descriptor = open(upload_destination,'wb')
            file_descriptor.write(file_buffer)
            file_descriptor.close()

            client_socket.send('Successfully saved file file to %s\r\n' % upload_destination)
        except:
            client_socket.send('Failed to save file file to %s\r\n' % upload_destination)
            
    if len(execute):
        output = run_command(execute)
        client_socket.send(output)
        
    if command:
        #flag -c が設定されているときにcomandが実行される。
        while True:
            client_socket.send('<BF?:#>')

            cmd_buffer = ''
            while '\n' not in cmd_buffer:
                cmd_buffer += client_socket.recv(1024)
            response = run_command(cmd_buffer)

            client_socket.send(response)
            
main()