mirror of
https://github.com/rehlds/rehlds.git
synced 2024-12-27 07:05:43 +03:00
Implemented reduction of impact caused by zip-bomb exploit (#994)
* Implemented reduction of impact caused by zip-bomb exploit Added network security CVars: - sv_net_incoming_decompression (0-1) Enables or disables incoming data decompression - sv_net_incoming_decompression_max_ratio (0.0 - 100.0) Sets max allowed ratio between compressed and decompressed data. (A ratio close to 90 indicates large uncompressed data with low entropy) - sv_net_incoming_decompression_max_size (16-65536) Adjusts max size of output data after decompression. Added CVar sv_net_incoming_decompression_punish for ban * Fix missing reg CVar sv_net_incoming_decompression_punish
This commit is contained in:
parent
61ee4f9269
commit
0d1bdbab67
@ -63,6 +63,10 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
|
|||||||
<li>sv_rehlds_local_gametime <1|0> // A feature of local gametime which decrease "lags" if you run same map for a long time. Default: 0
|
<li>sv_rehlds_local_gametime <1|0> // A feature of local gametime which decrease "lags" if you run same map for a long time. Default: 0
|
||||||
<li>sv_use_entity_file // Use custom entity file for a map. Path to an entity file will be "maps/[map name].ent". 0 - use original entities. 1 - use .ent files from maps directory. 2 - use .ent files from maps directory and create new .ent file if not exist.
|
<li>sv_use_entity_file // Use custom entity file for a map. Path to an entity file will be "maps/[map name].ent". 0 - use original entities. 1 - use .ent files from maps directory. 2 - use .ent files from maps directory and create new .ent file if not exist.
|
||||||
<li>sv_usercmd_custom_random_seed // When enabled server will populate an additional random seed independent of the client. Default: 0
|
<li>sv_usercmd_custom_random_seed // When enabled server will populate an additional random seed independent of the client. Default: 0
|
||||||
|
<li>sv_net_incoming_decompression <1|0> // When enabled server will decompress of incoming compressed file transfer payloads. Default: 1
|
||||||
|
<li>sv_net_incoming_decompression_max_ratio <0|100> // Sets the max allowed ratio between compressed and uncompressed data for file transfer. (A ratio close to 90 indicates large uncompressed data with low entropy) Default: 80.0
|
||||||
|
<li>sv_net_incoming_decompression_max_size <16|65536> // Sets the max allowed size for decompressed file transfer data. Default: 65536 bytes
|
||||||
|
<li>sv_net_incoming_decompression_punish // Time in minutes for which the player will be banned for malformed/abnormal bzip2 fragments (0 - Permanent, use a negative number for a kick). Default: -1
|
||||||
<li>sv_tags <comma-delimited string list of tags> // Sets a string defining the "gametags" for this server, this is optional, but if it is set it allows users/scripts to filter in the matchmaking/server-browser interfaces based on the value. Default: ""
|
<li>sv_tags <comma-delimited string list of tags> // Sets a string defining the "gametags" for this server, this is optional, but if it is set it allows users/scripts to filter in the matchmaking/server-browser interfaces based on the value. Default: ""
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
|
@ -36,6 +36,12 @@ cvar_t net_showpackets = { "net_showpackets", "0", 0, 0.0f, nullptr};
|
|||||||
cvar_t net_showdrop = { "net_showdrop", "0", 0, 0.0f, nullptr};
|
cvar_t net_showdrop = { "net_showdrop", "0", 0, 0.0f, nullptr};
|
||||||
cvar_t net_drawslider = { "net_drawslider", "0", 0, 0.0f, nullptr};
|
cvar_t net_drawslider = { "net_drawslider", "0", 0, 0.0f, nullptr};
|
||||||
cvar_t net_chokeloopback = { "net_chokeloop", "0", 0, 0.0f, nullptr};
|
cvar_t net_chokeloopback = { "net_chokeloop", "0", 0, 0.0f, nullptr};
|
||||||
|
|
||||||
|
cvar_t sv_net_incoming_decompression = { "sv_net_incoming_decompression", "1", 0, 1.0f, nullptr };
|
||||||
|
cvar_t sv_net_incoming_decompression_max_ratio = { "sv_net_incoming_decompression_max_ratio", "75.0", 0, 75.0f, nullptr };
|
||||||
|
cvar_t sv_net_incoming_decompression_max_size = { "sv_net_incoming_decompression_max_size", "65536", 0, 65536.0f, nullptr };
|
||||||
|
cvar_t sv_net_incoming_decompression_punish = { "sv_net_incoming_decompression_punish", "-1", 0, -1.0f, NULL };
|
||||||
|
|
||||||
cvar_t sv_filetransfercompression = { "sv_filetransfercompression", "1", 0, 0.0f, nullptr};
|
cvar_t sv_filetransfercompression = { "sv_filetransfercompression", "1", 0, 0.0f, nullptr};
|
||||||
cvar_t sv_filetransfermaxsize = { "sv_filetransfermaxsize", "10485760", 0, 0.0f, nullptr};
|
cvar_t sv_filetransfermaxsize = { "sv_filetransfermaxsize", "10485760", 0, 0.0f, nullptr};
|
||||||
|
|
||||||
@ -1433,6 +1439,9 @@ qboolean Netchan_CopyNormalFragments(netchan_t *chan)
|
|||||||
|
|
||||||
p = chan->incomingbufs[FRAG_NORMAL_STREAM];
|
p = chan->incomingbufs[FRAG_NORMAL_STREAM];
|
||||||
|
|
||||||
|
chan->incomingbufs[FRAG_NORMAL_STREAM] = nullptr;
|
||||||
|
chan->incomingready[FRAG_NORMAL_STREAM] = FALSE;
|
||||||
|
|
||||||
SZ_Clear(&net_message);
|
SZ_Clear(&net_message);
|
||||||
MSG_BeginReading();
|
MSG_BeginReading();
|
||||||
|
|
||||||
@ -1470,27 +1479,87 @@ qboolean Netchan_CopyNormalFragments(netchan_t *chan)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SZ_Clear(&net_message);
|
SZ_Clear(&net_message);
|
||||||
|
|
||||||
chan->incomingbufs[FRAG_NORMAL_STREAM] = nullptr;
|
|
||||||
chan->incomingready[FRAG_NORMAL_STREAM] = FALSE;
|
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
#endif // REHLDS_FIXES
|
#endif // REHLDS_FIXES
|
||||||
|
|
||||||
|
qboolean success = TRUE;
|
||||||
|
|
||||||
if (*(uint32 *)net_message.data == MAKEID('B', 'Z', '2', '\0'))
|
if (*(uint32 *)net_message.data == MAKEID('B', 'Z', '2', '\0'))
|
||||||
{
|
{
|
||||||
|
// Determine whether decompression of compressed data is allowed
|
||||||
|
#ifdef REHLDS_FIXES
|
||||||
|
if (!sv_net_incoming_decompression.value)
|
||||||
|
{
|
||||||
|
if (chan->player_slot == 0)
|
||||||
|
{
|
||||||
|
Con_DPrintf("Incoming compressed data disallowed from\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
// compressed data is expected only after requesting resource list
|
||||||
|
else if (host_client->m_sendrescount == 0)
|
||||||
|
{
|
||||||
|
Con_DPrintf("%s:Incoming compressed data disallowed from %s\n", NET_AdrToString(chan->remote_address), host_client->name);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
char uncompressed[65536];
|
char uncompressed[65536];
|
||||||
unsigned int uncompressedSize = 65536;
|
unsigned int uncompressedSize = clamp((int)sv_net_incoming_decompression_max_size.value, 16, 65536); // valid range (16 - 65536) bytes
|
||||||
BZ2_bzBuffToBuffDecompress(uncompressed, &uncompressedSize, (char*)net_message.data + 4, net_message.cursize - 4, 1, 0);
|
unsigned int compressedSize = net_message.cursize - 4;
|
||||||
Q_memcpy(net_message.data, uncompressed, uncompressedSize);
|
|
||||||
net_message.cursize = uncompressedSize;
|
// Decompress net buffer data
|
||||||
|
if (success && (BZ2_bzBuffToBuffDecompress(uncompressed, &uncompressedSize, (char *)net_message.data + 4, compressedSize, 1, 0) == BZ_OK))
|
||||||
|
{
|
||||||
|
#ifdef REHLDS_FIXES
|
||||||
|
// Check for an abnormal size ratio between compressed and uncompressed data
|
||||||
|
if (sv_net_incoming_decompression_max_ratio.value > 0 && compressedSize < uncompressedSize)
|
||||||
|
{
|
||||||
|
float ratio = ((float)(uncompressedSize - compressedSize) / uncompressedSize) * 100.0f;
|
||||||
|
if (ratio >= sv_net_incoming_decompression_max_ratio.value)
|
||||||
|
{
|
||||||
|
if (chan->player_slot == 0)
|
||||||
|
Con_DPrintf("Incoming abnormal uncompressed size with ratio %.2f\n", ratio);
|
||||||
|
else
|
||||||
|
Con_DPrintf("%s:Incoming abnormal uncompressed size with ratio %.2f from %s\n", NET_AdrToString(chan->remote_address), ratio, host_client->name);
|
||||||
|
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Copy uncompressed data back to the net buffer
|
||||||
|
Q_memcpy(net_message.data, uncompressed, uncompressedSize);
|
||||||
|
net_message.cursize = uncompressedSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// malformed data or compressed data exceeding sv_net_incoming_decompression_max_size
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop client if decompression was unsuccessful
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
if ((chan->player_slot - 1) == host_client - g_psvs.clients)
|
||||||
|
{
|
||||||
|
#ifdef REHLDS_FIXES
|
||||||
|
if (sv_net_incoming_decompression_punish.value >= 0)
|
||||||
|
{
|
||||||
|
Con_DPrintf("%s:Banned for malformed/abnormal bzip2 fragments from %s\n", NET_AdrToString(chan->remote_address), host_client->name);
|
||||||
|
Cbuf_AddText(va("addip %.1f %s\n", sv_net_incoming_decompression_punish.value, NET_BaseAdrToString(chan->remote_address)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SV_DropClient(host_client, FALSE, "Malformed/abnormal compressed data");
|
||||||
|
}
|
||||||
|
|
||||||
|
SZ_Clear(&net_message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chan->incomingbufs[FRAG_NORMAL_STREAM] = nullptr;
|
return success;
|
||||||
chan->incomingready[FRAG_NORMAL_STREAM] = FALSE;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qboolean Netchan_CopyFileFragments(netchan_t *chan)
|
qboolean Netchan_CopyFileFragments(netchan_t *chan)
|
||||||
@ -1826,6 +1895,12 @@ void Netchan_Init(void)
|
|||||||
Cvar_RegisterVariable(&net_chokeloopback);
|
Cvar_RegisterVariable(&net_chokeloopback);
|
||||||
Cvar_RegisterVariable(&net_drawslider);
|
Cvar_RegisterVariable(&net_drawslider);
|
||||||
Cvar_RegisterVariable(&sv_filetransfercompression);
|
Cvar_RegisterVariable(&sv_filetransfercompression);
|
||||||
|
#ifdef REHLDS_FIXES
|
||||||
|
Cvar_RegisterVariable(&sv_net_incoming_decompression);
|
||||||
|
Cvar_RegisterVariable(&sv_net_incoming_decompression_max_ratio);
|
||||||
|
Cvar_RegisterVariable(&sv_net_incoming_decompression_max_size);
|
||||||
|
Cvar_RegisterVariable(&sv_net_incoming_decompression_punish);
|
||||||
|
#endif
|
||||||
Cvar_RegisterVariable(&sv_filetransfermaxsize);
|
Cvar_RegisterVariable(&sv_filetransfermaxsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user