Saturday, 16 March 2019

ESP8266 Firmware Buffer Overflows

The ESP8266 is a popular IoT-style module. You've probably heard of it.

Let's look at the firmware.

Arduino/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.cpp

Here is a classic remote buffer overflow.

void MDNSResponder::_parsePacket(){
  int i;
  char tmp;
  bool serviceParsed = false;
  bool protoParsed = false;
  bool localParsed = false;

  char hostName[255];
  uint8_t hostNameLen;

  char serviceName[32];
...

  hostNameLen = _conn_read8() % 255;
  _conn_readS(hostName, hostNameLen);
  hostName[hostNameLen] = '\0';

  if(hostName[0] == '_'){
    serviceParsed = true;
    memcpy(serviceName, hostName+1, hostNameLen);
    serviceNameLen = hostNameLen-1;
    hostNameLen = 0;
  }

This appears non exploitable due to the buffer overflow overflowing into an adjacent buffer.

There are other bugs too. The following probably will probably result in a Denial of Service.


void MDNSResponder::_parsePacket(){
  int i;
  char tmp;
  bool serviceParsed = false;
  bool protoParsed = false;
  bool localParsed = false;

  char hostName[255];
  uint8_t hostNameLen;

  char serviceName[32];
  uint8_t serviceNameLen;
  uint16_t servicePort = 0;

  char protoName[32];
  protoName[0] = 0;
  uint8_t protoNameLen = 0;

...

        _conn_readS(serviceName, tmp8);
        serviceName[tmp8] = '\0';
#ifdef DEBUG_ESP_MDNS_RX
        DEBUG_ESP_PORT.printf(" %d ", tmp8);
        for (int n = 0; n < tmp8; n++) {
          DEBUG_ESP_PORT.printf("%c", serviceName[n]);
        }
        DEBUG_ESP_PORT.println();

+++ no validation on tmp8.. serviceName is buffer of 32
+++ this isn't the DoS bug.

...

      uint16_t answerType = _conn_read16(); // Read type
      uint16_t answerClass = _conn_read16(); // Read class
      uint32_t answerTtl = _conn_read32(); // Read ttl
      uint16_t answerRdlength = _conn_read16(); // Read rdlength

+++ andwerRdLength can be < 3

      (void) answerClass;
      (void) answerTtl;

      if(answerRdlength > 255){
        if(answerType == MDNS_TYPE_TXT && answerRdlength < 1460){
          while(--answerRdlength) _conn->read();
        } else {
#ifdef DEBUG_ESP_MDNS_RX
        DEBUG_ESP_PORT.printf("Data len too long! %u\n", answerRdlength);
#endif
          _conn->flush();
          return;
        }
      }

#ifdef DEBUG_ESP_MDNS_RX
      DEBUG_ESP_PORT.printf("type: %04x rdlength: %d\n", answerType, answerRdlength);
#endif

      if (answerType == MDNS_TYPE_PTR) {
        partsCollected |= 0x01;
        _conn_readS(hostName, answerRdlength); // Read rdata
        if(hostName[answerRdlength-2] & 0xc0){
          memcpy(answerHostName, hostName+1, answerRdlength-3);

+++ int underflow when answerRdLength is < 3

          answerHostName[answerRdlength-3] = '\0';
        }

Exploiting the Lorex 2K Indoor Wifi at Pwn2Own Ireland

Introduction In October InfoSect participated in Pwn2Own Ireland 2024 and successfully exploited the Sonos Era 300 smart speaker and Lor...