-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathNLAdetection.py
More file actions
252 lines (222 loc) · 9.84 KB
/
NLAdetection.py
File metadata and controls
252 lines (222 loc) · 9.84 KB
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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
import os
import signal
import socket
import subprocess
import cv2
import psutil
import pyautogui
import time
# 抓取当前屏幕截图并保存
def capture_screenshot():
screenshot = pyautogui.screenshot()
screenshot.save('screenshot.png')
# 在截图中找到目标图像的位置
def find_image_on_screen(target_image_path, threshold=0.8):
# 抓取当前屏幕截图
capture_screenshot()
# 读取屏幕截图和目标图像
screenshot = cv2.imread('screenshot.png')
target_image = cv2.imread(target_image_path)
# 将两张图像转换为灰度图
screenshot_gray = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)
target_image_gray = cv2.cvtColor(target_image, cv2.COLOR_BGR2GRAY)
# 执行模板匹配
result = cv2.matchTemplate(screenshot_gray, target_image_gray, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
# 如果匹配程度超过设定的阈值,那么获取匹配位置的中心点
if max_val >= threshold:
target_w, target_h = target_image_gray.shape[::-1]
center_x = max_loc[0] + target_w // 2
center_y = max_loc[1] + target_h // 2
return center_x, center_y
else:
return None
# 自动点击指定位置
def click_position(position):
x, y = position
pyautogui.moveTo(x, y)
pyautogui.click()
def check_port(rdpaddress, timeout=1):
"""
检查指定主机的端口是否开启
:param host: 主机地址(IP 地址或域名)
:param port: 端口号
:param timeout: 连接超时时间(秒),默认为1秒
:return: 是否开启 (True: 开启, False: 未开启)
"""
res = rdpaddress.split(":")
if len(res) == 1:
host = res[0]
port = 3389
else:
host, port = rdpaddress.split(":")
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
try:
sock.connect((host, int(port)))
except (socket.timeout, socket.error):
return False
finally:
sock.close()
return True
Default = open("Default.rdp", "r", encoding="utf-8").read()
def AutoCheck():
file = open("RDPList.txt", "r", encoding="utf-8")
result = open("result.txt", "w", encoding="utf-8")
result.write("\n")
while (line := file.readline()):
if line.endswith("\n"):
rdpaddress = line[:-1]
else:
rdpaddress = line
if not check_port(rdpaddress):
print(f"端口未开放连接: {rdpaddress}")
continue
open("NLA.rdp", "w", encoding="utf-8").write(Default.replace("47.118.52.141:3389", rdpaddress))
process = subprocess.Popen(["mstsc", "NLA.rdp"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
time.sleep(0.8)
target_image_path = 'confirmConnection.png' # 目标图像路径
position = find_image_on_screen(target_image_path) # 图像匹配到屏幕上所在图片的中心位置
if position:
x, y = position
# 确认按钮与图像匹配中心偏移量,该偏移量为1080P win11版测试可用,其他分辨率需要自行调整
position = (x + 894 - 755, y + 563 - 455)
print(position) # 确认按钮位置
print(f"确认连接: {rdpaddress}")
click_position(position)
else:
print(f"未找到确认连接按钮: {rdpaddress}")
if process.poll() is None: # 检查进程是否还在运行
# parent = psutil.Process(process.pid)
# children = parent.children(recursive=True)
# for child in children:
# print(child.pid, child.name())
# os.kill(child.pid, signal.SIGTERM) # 使用SIGKILL信号终止子进程
os.kill(process.pid, signal.SIGTERM) # 使用SIGKILL信号终止父进程
print(f"Terminated process with PID: {process.pid}")
result.write(rdpaddress+"\n")
continue
time.sleep(0.8)
target_image_path = 'connectionFailed.png' # 目标图像路径
position = find_image_on_screen(target_image_path)
if position:
x, y = position
# 确认按钮与图像匹配中心偏移量,该偏移量为1080P win11版测试可用,其他分辨率需要自行调整
position = (x + 980 - 841, y + 460 - 352)
print(position)
print(f"连接失败: {rdpaddress},原因:开启了NLA")
click_position(position)
else:
print(f"未找到连接失败按钮: {rdpaddress}, 需要人工复查")
result.write(line)
if process.poll() is None: # 检查进程是否还在运行
# parent = psutil.Process(process.pid)
# children = parent.children(recursive=True)
# for child in children:
# print(child.pid, child.name())
# os.kill(child.pid, signal.SIGTERM) # 使用SIGKILL信号终止子进程
os.kill(process.pid, signal.SIGTERM) # 使用SIGKILL信号终止父进程
print(f"Terminated process with PID: {process.pid}")
def ManualCheck():
result = open("result.txt", "r", encoding="utf-8")
lines = result.readlines()
for i in range(len(lines)):
line = lines[i+1]
if line.endswith("\n"):
rdpaddress = line[:-1]
else:
rdpaddress = line
if not check_port(rdpaddress):
print(f"端口未开放连接: {rdpaddress}")
continue
open("NLA.rdp", "w", encoding="utf-8").write(Default.replace("47.118.52.141:3389", rdpaddress))
process = subprocess.Popen(["mstsc", "NLA.rdp"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
time.sleep(0.8)
target_image_path = 'confirmConnection.png' # 目标图像路径
position = find_image_on_screen(target_image_path)
if position:
x, y = position
# 确认按钮与图像匹配中心偏移量,该偏移量为1080P win11版测试可用,其他分辨率需要自行调整
position = (x + 894 - 755, y + 563 - 455)
print(position)
print(f"确认连接: {rdpaddress}")
click_position(position)
else:
print(f"未找到确认连接按钮: {rdpaddress}")
exit(0)
time.sleep(0.8)
target_image_path = 'oldVersionConfirm.png' # 目标图像路径
position = find_image_on_screen(target_image_path)
if position:
x, y = position
# 确认按钮与图像匹配中心偏移量,该偏移量为1080P win11版测试可用,其他分辨率需要自行调整
position = (x + 830 - 756, y + 545 - 459)
print(position)
print(f"老版本连接,二次确认: {rdpaddress}")
click_position(position)
time.sleep(0.8)
else:
print(f"非老版本: {rdpaddress}")
target_image_path = 'certConfirm.png' # 目标图像路径
position = find_image_on_screen(target_image_path)
if position:
x, y = position
# 确认按钮与图像匹配中心偏移量,该偏移量为1080P win11版测试可用,其他分辨率需要自行调整
position = (x + 828 - 754, y + 710 - 458)
print(position)
print(f"连接证书不可信确认,自动确认: {rdpaddress}")
click_position(position)
time.sleep(0.8)
else:
print(f"非证书可信认证页面: {rdpaddress}")
target_image_path = 'connectionFailed.png' # 目标图像路径
position = find_image_on_screen(target_image_path)
if position:
x, y = position
# 确认按钮与图像匹配中心偏移量,该偏移量为1080P win11版测试可用,其他分辨率需要自行调整
position = (x + 980 - 841, y + 460 - 352)
print(position)
print(f"连接失败: {rdpaddress},原因:开启了NLA")
click_position(position)
continue
else:
print(f"未找到连接失败按钮: {rdpaddress}")
# print(lines[i+1:])
open("result.txt", "w", encoding="utf-8").writelines(lines[i+1:])
break
def closeOtherRDPClient():
python_processes = []
for process in psutil.process_iter():
try:
cmdlines = process.cmdline()
if 'mstsc' in cmdlines[0] and cmdlines[1] == "NLA.rdp":
python_processes.append({
'pid': process.pid,
'params': cmdlines[1]
})
except Exception:
pass
for i in python_processes:
print(i)
os.kill(i["pid"], signal.SIGTERM)
def main():
print("请选择一个功能:")
print("1: 自动对RDPList.txt中的RDP地址进行NLA关闭检查(非1080p win11 请按说明修改代码适配),启动后请勿移动鼠标,")
print(" 结果将保存在result.txt中")
print("2: 将对result.txt中的RDP地址进行手动复查,即将从第二行开始检查,每次检查将从result.txt中删除上一次的检查的RDP地址,")
print(" 若可利用攻击,请及时保存RDP地址,上一次运行功能2连接的RDP地址位于result.txt的第一行,下次运行功能2将删除本次RDP连接的地址")
print("3: 一键关闭本程序启动的mstsc.exe,手动检查功能发现存在前台已关闭,后台程序继续运行的情况,建议尝试一定连接次数后执行一下")
print("直接按Enter键默认选择功能2")
while True:
choice = input("请输入你的选择: ")
if choice == '1':
AutoCheck()
print("检查完成,可以开始手动检查")
elif choice == '2':
ManualCheck()
elif choice == '3':
closeOtherRDPClient()
else:
ManualCheck()
if __name__ == "__main__":
main()