Trend Micro Discovers Android Vulnerability that Can Lead to Exposure of Device Memory Content

We have discovered a vulnerability in the integrated Android debugger Debuggerd that can be used to expose the contents of the device’s memory in devices running Ice Cream Sandwich to Lollipop.

A specially crafted ELF (Executable and Linkable Format) file can crash the debugger and expose the memory content via tombstone files and corresponding logd log files. This information can be used in denial of service attacks, as well as to help bypass ASLR for arbitrary code execution. By itself, the vulnerability cannot be used for code execution. However, the information leaked here may be combined with other flaws for that purpose.

This vulnerability can be exploited by a malicious or repackaged app downloaded onto the device, although the impact would be relatively limited (as no code execution is possible by itself). No malicious code can be executed if this vulnerability is exploited. This vulnerability is present from Android 4.0 (Ice Cream Sandwich) up to Lollipop (5.x). However, the vulnerability has been resolved in the next version, Android M.

Vulnerability Description

The root cause of the vulnerability is that Debuggerd will use sym->st_name as an offset for a string copy command without any error checking. This value can be easily controlled by the malformed ELF file in such a way that if the offset value points to inaccessible memory, Debuggerd will crash. Repeated crashes would cause a denial-of-service attack;  it would disable other normal crashes which cannot be connected to Debuggerd anymore. A carefully designed offset will cause Debuggerd will expose the corresponding memory contents to related dump and log files.

For Android 5.0-5.1:, the vulnerability can be found in external/libunwind/src/elfxx.c:


126       for (sym = symtab;
127            sym < symtab_end;
128            sym = (Elf_W (Sym) *) ((char *) sym + syment_size))
129         {
130           if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC
131           && sym->st_shndx != SHN_UNDEF)
132         {
133           if (tdep_get_func_addr (as, sym->st_value, &val) < 0)
134             continue;
135           if (sym->st_shndx != SHN_ABS)
136             val += load_offset;
137           Debug (16, "0x%016lx info=0x%02x %s\n",
138              (long) val, sym->st_info, strtab + sym->st_name);
139
140                   /* ANDROID support update */
141                   if ((Elf_W (Addr)) (ip - val) < *min_dist
142                       && (Elf_W (Addr)) (ip - val) < sym->st_size)
143                   /* End of ANDROID update */
144             {
145               *min_dist = (Elf_W (Addr)) (ip - val);
146               strncpy (buf, strtab + sym->st_name, buf_len);  //the address st_name may be easily controlled by malformed  ELF
147               buf[buf_len - 1] = '';
148               ret = (strlen (strtab + sym->st_name) >= buf_len
149                  ? -UNW_ENOMEM : 0);
150             }
151         }
152         }

To reproduce the vulnerability, an ELF file whose main function directly crashes can be used. This can be done by modifying the symbol offset. After the ELF is embedded into an APK, the former will be executed in a loop. This will trigger the vulnerability, as seen below:

Figure 1. Trigger of vulnerability

Similar issues are also found in older versions of Android (specifically, 4.x versions such as Ice Cream Sandwich, Jelly Bean, and KitKat). These do not use the libunwind third-party library. In Android 4.0:, the vulnerability is in system/core/debuggerd/symbol_table.c: 

155     int j = 0;
156     if (dynsym_idx != -1) {
157         // …and populate them
158         for(i = 0; i < dynnumsyms; i++) {
159             if(dynsyms[i].st_shndx != SHN_UNDEF) {
160                 table->symbols[j].name = strdup(dynstr + dynsyms[i].st_name);//st_name is not carefully checked before using
161                 table->symbols[j].addr = dynsyms[i].st_value;
162                 table->symbols[j].size = dynsyms[i].st_size;
163                 XLOG2(“name: %s, addr: %x, size: %x\n”,
164                     table->symbols[j].name, table->symbols[j].addr, table->symbols[j].size);
165                 j++;
166             }
167         }
168     }
169
170     if (sym_idx != -1) {
171         // …and populate them
172         for(i = 0; i < numsyms; i++) {
173             if((syms[i].st_shndx != SHN_UNDEF) &&
174                 (strlen(str+syms[i].st_name)) &&
175                 (syms[i].st_value != 0) && (syms[i].st_size != 0)) {
176                 table->symbols[j].name = strdup(str + syms[i].st_name);//st_name is not checked before using
177                 table->symbols[j].addr = syms[i].st_value;
178                 table->symbols[j].size = syms[i].st_size;
179                 XLOG2(“name: %s, addr: %x, size: %x\n”,
180                     table->symbols[j].name, table->symbols[j].addr, table->symbols[j].size);
181                 j++;
182             }
183         }
184     }

In Android 4.1-4.4, the vulnerability is in system/core/libcorkscrew/symbol_table.c: 

150     size_t symbol_index = 0;
151     if (dynsym_idx != -1) {
152         // …and populate them
153         for (int i = 0; i < dynnumsyms; i++) {
154             if (dynsyms[i].st_shndx != SHN_UNDEF) {
155                 table->symbols[symbol_index].name = strdup(dynstr + dynsyms[i].st_name);//st_name is not checked before using
156                 table->symbols[symbol_index].start = dynsyms[i].st_value;
157                 table->symbols[symbol_index].end = dynsyms[i].st_value + dynsyms[i].st_size;
158                 ALOGV(”  [%d] ‘%s’ 0x%08x-0x%08x (DYNAMIC)”,
159                         symbol_index, table->symbols[symbol_index].name,
160                         table->symbols[symbol_index].start, table->symbols[symbol_index].end);
161                 symbol_index += 1;
162             }
163         }
164     }
165
166     if (sym_idx != -1) {
167         // …and populate them
168         for (int i = 0; i < numsyms; i++) {
169             if (syms[i].st_shndx != SHN_UNDEF
170                     && str[syms[i].st_name]
171                     && syms[i].st_value
172                     && syms[i].st_size) {
173                 table->symbols[symbol_index].name = strdup(str + syms[i].st_name);//st_name is type of uint32_t not be checked
174                 table->symbols[symbol_index].start = syms[i].st_value;
175                 table->symbols[symbol_index].end = syms[i].st_value + syms[i].st_size;
176                 ALOGV(”  [%d] ‘%s’ 0x%08x-0x%08x”,
177                         symbol_index, table->symbols[symbol_index].name,
178                         table->symbols[symbol_index].start, table->symbols[symbol_index].end);
179                 symbol_index += 1;
180             }
181}
182     }

 

Figure 2. Memory exposure snapshot

We first reported this vulnerability to Google on April 27 of this year; they acknowledged the issue the following day and assigned it a low severity rating. A fix was included in the Android Open Source Project (AOSP) code on May 15.

Post from: Trendlabs Security Intelligence Blog – by Trend Micro

Trend Micro Discovers Android Vulnerability that Can Lead to Exposure of Device Memory Content

Read more: Trend Micro Discovers Android Vulnerability that Can Lead to Exposure of Device Memory Content

Story added 26. June 2015, content source with full text you can find at link above.