Posts

Showing posts from March, 2019

OpenBIOS ELF Loader Buffer Overflow

Continuing to look at OpenBIOS. Here is a classic integer overflow leading to a heap based buffer overflow. nhdr->n_descsz is 32-bits. So we on x86 (32-bit), if we make it UINT_MAX, we cause ob_malloc to allocate 0 bytes. This returns a pointer. The memcpy causes memory corruption. Even if ob_calloc returned NULL, there is no error checking. if (nhdr->n_namesz==sizeof(ELF_NOTE_BOOT) && memcmp(name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT))==0) { if (nhdr->n_type == EIN_PROGRAM_NAME) { image_name = ob_calloc(1, nhdr->n_descsz + 1); memcpy(image_name, desc, nhdr->n_descsz); } And to see what ob_calloc does: static void *ob_calloc(size_t nmemb, size_t size) { size_t alloc_size = nmemb * size; void *mem; if (alloc_size < nmemb || alloc_size < size) { printf("calloc overflow: %u, %u\n", nmemb, size); return NULL; }

unmass Buffer Overflow

unmass is a package in Linux (e.g., Ubunut) to "ëxtract game archive files" void FillListSorted( e_sort sorttype ); CWndSize SizeCtrls; char ProgramPath[ 512 ], TempDir[ 512 ]; // no end slashes int NoExtInCombo; int ArchiveOpened; }; Ok.. so ProgramPath and TempDir are both 512 bytes. BOOL CUnmasswDlg::OnInitDialog() { CDialog::OnInitDialog(); icon = LoadIcon( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDR_MAINFRAME ) ); SetIcon( icon, true ); // Set big icon SetIcon( icon, false ); // Set small icon ArchiveOpened = 0; int i; GetModuleFileName( NULL, ProgramPath, 512 ); i = strlen( ProgramPath ) - 1; while (( ProgramPath[ i ] != '\\' ) && ( ProgramPath[ i ] != '/' )) i--; ProgramPath[ i ] = 0; strcpy( TempDir, ProgramPath );

strncat Buffer Overflow in OpenBIOS

It's easy to get strncat wrong. Here is an example from OpenBIOS. int load_plugin(const char *plugin_name) { void *handle; char *error; char path[PATHSIZE]; int (*init_plugin) (void); char **deps; char **plugin_info; plugin_t *p; if (is_loaded(plugin_name)) { printf("Plugin %s already loaded.\n", plugin_name); return 0; } strncpy(path, PLUGINDIR, PATHSIZE); strncat(path, "/plugin_", PATHSIZE); strncat(path, plugin_name, PATHSIZE); strncat(path, ".so", PATHSIZE); What does setting the size field in strncat to PATHSIZE do? It won't prevent the destination string from exceeding the size PATHSIZE. It will prevent the source string being copied to copy at most PATHSIZE characters. In the above code, if the plugin_name is near PATHSIZE, then a buffer overflow will occur. There are more bugs like this in OpenBIOS.

strncpy again in xen

I know I'm repeating myself.. strncpy must always be explicitly NULL terminated. Here is another example from xen (utils) static int get_name(int argc, char *argv[], char *name) { ssize_t len = strlen(argv[0]); if ( len > XEN_LIVEPATCH_NAME_SIZE ) { fprintf(stderr, "ID must be no more than %d characters.\n", XEN_LIVEPATCH_NAME_SIZE); errno = EINVAL; return errno; } /* Don't want any funny strings from the stack. */ memset(name, 0, XEN_LIVEPATCH_NAME_SIZE); strncpy(name, argv[0], len); return 0; } There are a few other places in xen too..

Does anyone get strncpy right?

I decided to have a quick look at OpenBIOS. 5 seconds in, it's clear that strncpy is used incorrectly in a number of places. OpenBSD realised many years ago how prone to bugs strncpy was and replaced it with the non standard strlcpy. static void create_free_part( char *ptr, int size ) { nvpart_t *nvp = (nvpart_t*)ptr; memset( nvp, 0, size ); strncpy( nvp->name, "777777777777", sizeof(nvp->name) ); nvp->signature = NV_SIG_FREE; nvp->len_hi = (size /16) >> 8; nvp->len_lo = size /16; nvp->checksum = nvpart_checksum(nvp); } And more.. static int create_nv_part( int signature, const char *name, int size ) { nvpart_t *p = NULL; int fs; while( next_nvpart(&p) > 0 ) { if( p->signature != NV_SIG_FREE ) continue; fs = nvpart_size( p ); if( fs < size ) size = fs;

Apache Nimble Bluetooth Stack

I had a quick look last night at Apache Nimble, an open source Bluetooth stack. Here are some minor findings: static char * ble_gatts_flags_to_str(uint16_t flags, char *buf, const char * const *names) { int bit; bool non_empty = false; size_t length = 0; buf[0] = '\0'; strcpy(buf, "["); length += 1; for (bit = 0; names[bit]; ++bit) { if (flags & (1 << bit)) { length += strlen(names[bit]); if (length + 1 >= BLE_CHR_FLAGS_STR_LEN) { return buf; } if (non_empty) { strcat(buf, "|"); length += 1; } strcat(buf, names[bit]); non_empty = true; } } strcat(buf, "]"); return buf; } The above code has an off-by-1. There are some strncpy bugs, where strings may be left unterminated. int bt_mesh_input_string(const char *str) {

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;   bo