mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-23 07:40:14 +00:00
Harden AuraUpdateParser against malformed packets
WotLK SMSG_AURA_UPDATE (3.3.5a) improvements: - Cap entry count to 512 (isAll) or 1 (single) to prevent unbounded loop DoS - Validate 5-byte minimum before each slot+spellId read - Validate 3-byte minimum before flags/level/charges read - Validate space before casterGuid packed GUID read - Validate 8-byte minimum before duration field reads - Validate 4-byte minimum before each effect amount read - Graceful truncation with field initialization and partial read support - Log all truncation events with entry index information Prevents DoS and undefined behavior from high-frequency aura update packets.
This commit is contained in:
parent
7034bc5f63
commit
68b3cef0fe
1 changed files with 51 additions and 10 deletions
|
|
@ -3288,34 +3288,71 @@ bool SpellGoParser::parse(network::Packet& packet, SpellGoData& data) {
|
|||
}
|
||||
|
||||
bool AuraUpdateParser::parse(network::Packet& packet, AuraUpdateData& data, bool isAll) {
|
||||
// Validation: packed GUID (1-8 bytes minimum for reading)
|
||||
if (packet.getSize() - packet.getReadPos() < 1) return false;
|
||||
|
||||
data.guid = UpdateObjectParser::readPackedGuid(packet);
|
||||
|
||||
while (packet.getReadPos() < packet.getSize()) {
|
||||
// Cap number of aura entries to prevent unbounded loop DoS
|
||||
uint32_t maxAuras = isAll ? 512 : 1;
|
||||
uint32_t auraCount = 0;
|
||||
|
||||
while (packet.getReadPos() < packet.getSize() && auraCount < maxAuras) {
|
||||
// Validate we can read slot (1) + spellId (4) = 5 bytes minimum
|
||||
if (packet.getSize() - packet.getReadPos() < 5) {
|
||||
LOG_DEBUG("Aura update: truncated entry at position ", auraCount);
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t slot = packet.readUInt8();
|
||||
uint32_t spellId = packet.readUInt32();
|
||||
auraCount++;
|
||||
|
||||
AuraSlot aura;
|
||||
if (spellId != 0) {
|
||||
aura.spellId = spellId;
|
||||
aura.flags = packet.readUInt8();
|
||||
aura.level = packet.readUInt8();
|
||||
aura.charges = packet.readUInt8();
|
||||
|
||||
if (!(aura.flags & 0x08)) { // NOT_CASTER flag
|
||||
aura.casterGuid = UpdateObjectParser::readPackedGuid(packet);
|
||||
// Validate flags + level + charges (3 bytes)
|
||||
if (packet.getSize() - packet.getReadPos() < 3) {
|
||||
LOG_WARNING("Aura update: truncated flags/level/charges at entry ", auraCount);
|
||||
aura.flags = 0;
|
||||
aura.level = 0;
|
||||
aura.charges = 0;
|
||||
} else {
|
||||
aura.flags = packet.readUInt8();
|
||||
aura.level = packet.readUInt8();
|
||||
aura.charges = packet.readUInt8();
|
||||
}
|
||||
|
||||
if (aura.flags & 0x20) { // DURATION
|
||||
aura.maxDurationMs = static_cast<int32_t>(packet.readUInt32());
|
||||
aura.durationMs = static_cast<int32_t>(packet.readUInt32());
|
||||
if (!(aura.flags & 0x08)) { // NOT_CASTER flag
|
||||
// Validate space for packed GUID read (minimum 1 byte)
|
||||
if (packet.getSize() - packet.getReadPos() < 1) {
|
||||
aura.casterGuid = 0;
|
||||
} else {
|
||||
aura.casterGuid = UpdateObjectParser::readPackedGuid(packet);
|
||||
}
|
||||
}
|
||||
|
||||
if (aura.flags & 0x20) { // DURATION - need 8 bytes (two uint32s)
|
||||
if (packet.getSize() - packet.getReadPos() < 8) {
|
||||
LOG_WARNING("Aura update: truncated duration fields at entry ", auraCount);
|
||||
aura.maxDurationMs = 0;
|
||||
aura.durationMs = 0;
|
||||
} else {
|
||||
aura.maxDurationMs = static_cast<int32_t>(packet.readUInt32());
|
||||
aura.durationMs = static_cast<int32_t>(packet.readUInt32());
|
||||
}
|
||||
}
|
||||
|
||||
if (aura.flags & 0x40) { // EFFECT_AMOUNTS
|
||||
// Only read amounts for active effect indices (flags 0x01, 0x02, 0x04)
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (aura.flags & (1 << i)) {
|
||||
if (packet.getReadPos() < packet.getSize()) {
|
||||
if (packet.getSize() - packet.getReadPos() >= 4) {
|
||||
packet.readUInt32();
|
||||
} else {
|
||||
LOG_WARNING("Aura update: truncated effect amount ", i, " at entry ", auraCount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3328,6 +3365,10 @@ bool AuraUpdateParser::parse(network::Packet& packet, AuraUpdateData& data, bool
|
|||
if (!isAll) break;
|
||||
}
|
||||
|
||||
if (auraCount >= maxAuras && packet.getReadPos() < packet.getSize()) {
|
||||
LOG_WARNING("Aura update: capped at ", maxAuras, " entries, remaining data ignored");
|
||||
}
|
||||
|
||||
LOG_DEBUG("Aura update for 0x", std::hex, data.guid, std::dec,
|
||||
": ", data.updates.size(), " slots");
|
||||
return true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue