diff --git a/fdroidserver/update.py b/fdroidserver/update.py index e548df43..f90e4993 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -496,8 +496,10 @@ def has_known_vulnerability(filename): Checks whether there are more than one classes.dex or AndroidManifest.xml files, which is invalid and an essential part of the "Master Key" attack. - http://www.saurik.com/id/17 + + Janus is similar to Master Key but is perhaps easier to scan for. + https://www.guardsquare.com/en/blog/new-android-vulnerability-allows-attackers-modify-apps-without-affecting-their-signatures """ found_vuln = False @@ -506,6 +508,13 @@ def has_known_vulnerability(filename): if not hasattr(has_known_vulnerability, "pattern"): has_known_vulnerability.pattern = re.compile(b'.*OpenSSL ([01][0-9a-z.-]+)') + with open(filename.encode(), 'rb') as fp: + first4 = fp.read(4) + if first4 != b'\x50\x4b\x03\x04': + raise FDroidException(_('{path} has bad file signature "{pattern}", possible Janus exploit!') + .format(path=filename, pattern=first4.decode().replace('\n', ' ')) + '\n' + + 'https://www.guardsquare.com/en/blog/new-android-vulnerability-allows-attackers-modify-apps-without-affecting-their-signatures') + files_in_apk = set() with zipfile.ZipFile(filename) as zf: for name in zf.namelist(): diff --git a/tests/janus.apk b/tests/janus.apk new file mode 100644 index 00000000..ed4eed96 Binary files /dev/null and b/tests/janus.apk differ diff --git a/tests/run-tests b/tests/run-tests index 696bcd75..af29f471 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -9,7 +9,7 @@ echo_header() { copy_apks_into_repo() { set +x find $APKDIR -type f -name '*.apk' -print0 | while IFS= read -r -d '' f; do - echo $f | grep -F -v -e unaligned -e unsigned -e badsig -e badcert -e bad-unicode || continue + echo $f | grep -F -v -e unaligned -e unsigned -e badsig -e badcert -e bad-unicode -e janus.apk || continue apk=`$aapt dump badging "$f" | sed -n "s,^package: name='\(.*\)' versionCode='\([0-9][0-9]*\)' .*,\1_\2.apk,p"` test "$f" -nt repo/$apk && rm -f repo/$apk # delete existing if $f is newer if [ ! -e repo/$apk ] && [ ! -e archive/$apk ]; then diff --git a/tests/update.TestCase b/tests/update.TestCase index e49e1bf0..db463a89 100755 --- a/tests/update.TestCase +++ b/tests/update.TestCase @@ -601,6 +601,35 @@ class UpdateTest(unittest.TestCase): self.assertEqual('urzip', data['Name']) self.assertEqual('urzip', data['Summary']) + def test_has_known_vulnerability(self): + good = [ + 'org.bitbucket.tickytacky.mirrormirror_1.apk', + 'org.bitbucket.tickytacky.mirrormirror_2.apk', + 'org.bitbucket.tickytacky.mirrormirror_3.apk', + 'org.bitbucket.tickytacky.mirrormirror_4.apk', + 'org.dyndns.fules.ck_20.apk', + 'urzip.apk', + 'urzip-badcert.apk', + 'urzip-badsig.apk', + 'urzip-release.apk', + 'urzip-release-unsigned.apk', + 'repo/com.politedroid_3.apk', + 'repo/com.politedroid_4.apk', + 'repo/com.politedroid_5.apk', + 'repo/com.politedroid_6.apk', + 'repo/obb.main.oldversion_1444412523.apk', + 'repo/obb.mainpatch.current_1619_another-release-key.apk', + 'repo/obb.mainpatch.current_1619.apk', + 'repo/obb.main.twoversions_1101613.apk', + 'repo/obb.main.twoversions_1101615.apk', + 'repo/obb.main.twoversions_1101617.apk', + 'repo/urzip-; Рахма́нинов, [rɐxˈmanʲɪnəf] سيرجي_رخمانينوف 谢尔盖·.apk', + ] + for f in good: + self.assertFalse(fdroidserver.update.has_known_vulnerability(f)) + with self.assertRaises(fdroidserver.exception.FDroidException): + fdroidserver.update.has_known_vulnerability('janus.apk') + if __name__ == "__main__": parser = optparse.OptionParser()