Skip to content

Commit

Permalink
Avoid recursion in DNS parsing; check label/name lengths
Browse files Browse the repository at this point in the history
  • Loading branch information
bonsaiviking committed May 19, 2023
1 parent 0bc88ba commit e633a21
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 16 deletions.
61 changes: 45 additions & 16 deletions nmap_dns.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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));
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 < offset)
if(real_offset < curr_offset)
{
std::string val;
DNS_CHECK_ACCUMLATE(tmp, tmp, parseDomainName(val, buf, real_offset, maxlen));
name+=val;
return ret;
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)
Expand Down
2 changes: 2 additions & 0 deletions nmap_dns.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ class Target;
#include <algorithm>
#include <sstream>

#define DNS_LABEL_MAX_LENGTH 63
#define DNS_NAME_MAX_LENGTH 255

namespace DNS
{
Expand Down

0 comments on commit e633a21

Please sign in to comment.