大概耗时一天时间,我完成了netcat的简单实现,这个netcat能够完成的功能是在客户端进行简单的命令(如ls,pwd,遗憾的是不能进行cd操作,受限于subprocess的功能),进行文件内容输入。
大致的代码和书上的一样,不过书上的代码有点问题。我折腾了很久,在client_handler的if len(upload_destination)函数中如果使用书上的代码,会发现它停留在while循环里面出不来了,所以我稍微改了下。但是遗憾的是,这个自制的netcat不能传文件,而且那个传输command的命令我也觉得很鸡肋,都能在服务器运行这个py文件了,干嘛还用在客户端输入command传过去。不过这个训练对我来说,倒是锻炼了我对TCP,Netcat等的认识,受益匪浅!
import sys
import socket
import getopt
import threading
import subprocesslisten = False
command = False
upload = False
execute = ''
target = ''
upload_destination = ''
port = 0#提示信息
def usage():print('BHP Net Tool')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 a command shell')print('-u --upload=destination - upon receiving connection upload a file and write to [destination]')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")sys.exit(0)#监听状态下操作,设置一个服务器
def server_loop():global target,port#下面这句不知道什么意思,没有target设置一个target?if not len(target):target = '192.168.158.129'server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)server.bind((target,port))server.listen(5)while True:client_socket,addr = server.accept()#开始一个处理客户端的线程client_thread = threading.Thread(target = client_handler, args = (client_socket,))client_thread.start()def run_command(command):#删除command后面的空格command = command.rstrip()#在shell内运行并返回结果try:output = subprocess.check_output(command,stderr = subprocess.STDOUT,shell = True)#若用subprocess.call那么这里的output就是0而不是命令执行结果except:output = 'Failed to execute command.\r\n'return output#实现文件上传、命令执行和shell命令
def client_handler(client_socket):global upload_destination,execute,command#检测上传文件,upload_destination不空说明是上传文件if len(upload_destination):while True:file_buffer = client_socket.recv(1024)#把接收到的数据写入try:print('opening')file_descriptor = open(upload_destination,'a')file_descriptor.write(file_buffer)print('written')file_descriptor.close()#向客户端报信已经成功写入了client_socket.send('Successfully saved file to %s\r\n'%upload_destination)except:client_socket.send('Failed to write save file to %s\r\n'%upload_destination)#excute不空说明执行commandif len(execute):output = run_command(execute)client_socket.send(output)#开命令行shell,和上面的有什么区别?if command:while True:client_socket.send('<BHP:#>')#接收文件直到发现换行符cmd_buffer = ''while '\n' not in cmd_buffer:cmd_buffer += client_socket.recv(1024)response = run_command(cmd_buffer)#返回响应数据client_socket.send(response)#非监听状态下的发送数据
def client_sender(buffer):global target,portclient = socket.socket(socket.AF_INET,socket.SOCK_STREAM)try:#连接到主机print('start connecting...')client.connect((target,port))print('connected!')if len(buffer):client.send(buffer)print('successfully sent out')while True:#现在等待数据传回来recv_len = 1response = ''print('waiting response')while recv_len:data = client.recv(4096)recv_len = len(data)response += dataif recv_len < 4096:breakprint(response)#等待更多输入buffer = raw_input('') #kali上是python2.7buffer += '\n'#发送出去client.send(buffer)print('successfully sent out')except:print('[*] Exception! Exiting')client.close()def main():global listen,port,execute,command,upload_destination,target#如果终端中运行时python **.py 后面没有参数则会提示正确的使用方法if not len(sys.argv[1:]):usage() #读取命令行选项try:opts,args = getopt.getopt(sys.argv[1:],'hle:t:p:cu:',['help','listen','execute','target','port','command','upload'])#此处'hle:'为识别'-h'这样的短选项,相对比下h默认后面不带参数,e后面带有:则是说明它会带有参数,后面[]则是'--'的长选项#而args中包含那些不含'-','--'的项except getopt.GetoptError as err:#如果没有要匹配的参数,打印出error,然后给出提示print(str(err))usage()for o,a in opts:if o in ('-h','--help'):usage()elif o in ('-l','--listen'):listen = Trueelif o in ('-e','--execute'):execute = aelif o in ('-c','--command'):command = Trueelif o in ('-u','--upload'):upload_destination = aelif o in ('-t','--target'):target = aelif o in ('-p','--port'):port = int(a)else:assert False,'unhandled option'#判断进行监听还是单单发送数据if (not listen) and (len(target)>0) and (port > 0):#从cmd中读取内存数据#停止输入时按CTRL-Dbuffer = raw_input()#发送数据client_sender(buffer)#开始监听并准备上传文件、执行命令#放置一个反弹shell?if listen:print('The server is listening on %s:%d'%(target,port))server_loop()main()