1
0
mirror of https://github.com/nmap/nmap.git synced 2026-02-06 13:36:36 +00:00

Avoid recursion in DNS parsing; check label/name lengths

This commit is contained in:
dmiller
2023-05-19 01:43:17 +00:00
parent 0bc88ba519
commit e633a21b5f
2 changed files with 49 additions and 18 deletions

View File

@@ -1519,40 +1519,69 @@ size_t DNS::Factory::parseUnsignedInt(u32 &num, const u8 *buf, size_t offset, si
size_t DNS::Factory::parseDomainName(std::string &name, const u8 *buf, size_t offset, size_t maxlen)
{
size_t tmp, ret = 0;
size_t tmp = 0;
size_t max_offset = offset;
size_t curr_offset = offset;
name.clear();
while(u8 label_length = buf[offset+ret++]) // Postincrement important here
while(u8 label_length = buf[curr_offset])
{
if((label_length & COMPRESSED_NAME) == COMPRESSED_NAME)
{
--ret; // The byte it's part of the pointer, wasn't really consumed yet
u16 real_offset;
DNS_CHECK_ACCUMLATE(ret, tmp, parseUnsignedShort(real_offset, buf, offset+ret, maxlen));
real_offset -= COMPRESSED_NAME<<8;
if( real_offset < offset)
{
std::string val;
DNS_CHECK_ACCUMLATE(tmp, tmp, parseDomainName(val, buf, real_offset, maxlen));
name+=val;
return ret;
tmp = parseUnsignedShort(real_offset, buf, curr_offset, maxlen);
if (tmp < 1) {
return 0;
}
if (curr_offset >= max_offset) {
max_offset = curr_offset + tmp;
}
real_offset -= COMPRESSED_NAME<<8;
if(real_offset < curr_offset)
{
curr_offset = real_offset;
continue;
}
else {
if (o.debugging) {
log_write(LOG_STDOUT, "DNS compression pointer is not backwards\n");
}
return 0;
}
else return 0;
}
for(u8 i=0; i<label_length; ++i)
{
size_t index = offset+ret++; // Postincrement important here
DNS_CHECK_UPPER_BOUND(index, maxlen);
name += buf[index];
if (label_length > DNS_LABEL_MAX_LENGTH) {
if (o.debugging) {
log_write(LOG_STDOUT, "DNS label exceeds max length\n");
}
return 0;
}
curr_offset++;
DNS_CHECK_UPPER_BOUND(curr_offset + label_length, maxlen);
name.append(reinterpret_cast<const char *>(buf + curr_offset), label_length);
curr_offset += label_length;
if (curr_offset > max_offset) {
max_offset = curr_offset;
}
name += '.';
if (name.length() > DNS_NAME_MAX_LENGTH - 1) {
if (o.debugging) {
log_write(LOG_STDOUT, "DNS name exceeds max length\n");
}
return 0;
}
}
if (max_offset == curr_offset && buf[curr_offset] == '\0') {
max_offset++;
}
std::string::iterator it = name.end()-1;
if( *it == '.') name.erase(it);
return ret;
return max_offset - offset;
}
size_t DNS::A_Record::parseFromBuffer(const u8 *buf, size_t offset, size_t maxlen)