[HOTFIX] add apksigner.jar for reading signatures (#2254)

* Add `apksigner.jar`
* Use apksigner to extract signature versions (v1, v2, v3, v4)
* Fix: #2120
This commit is contained in:
Ajin Abraham
2023-08-31 21:52:48 -07:00
committed by GitHub
parent e6cee553d6
commit bba141d2fd
4 changed files with 54 additions and 28 deletions
@@ -6,6 +6,8 @@ import hashlib
import logging
import os
import re
import subprocess
from pathlib import Path
from androguard.util import get_certificate_name_string
@@ -15,6 +17,10 @@ from oscrypto import asymmetric
from django.utils.html import escape
from mobsf.MobSF.utils import (
find_java_binary,
)
logger = logging.getLogger(__name__)
ANDROID_8_1_LEVEL = 27
HIGH = 'high'
@@ -85,14 +91,41 @@ def get_pub_key_details(data):
return certlist
def apksigtool_cert(apk_path):
def get_signature_versions(app_path, tools_dir):
"""Get signature versions using apksigner."""
v1, v2, v3, v4 = False, False, False, False
try:
logger.info('Getting Signature Versions')
apksigner = Path(tools_dir) / 'apksigner.jar'
args = [find_java_binary(), '-Xmx1024M',
'-Djava.library.path=', '-jar', apksigner,
'verify', '--verbose', app_path]
out = subprocess.check_output(
args, stderr=subprocess.STDOUT)
out = out.decode('utf-8', 'ignore')
if re.findall(r'v1 scheme \(JAR signing\): true', out):
v1 = True
if re.findall(r'\(APK Signature Scheme v2\): true', out):
v2 = True
if re.findall(r'\(APK Signature Scheme v3\): true', out):
v3 = True
if re.findall(r'\(APK Signature Scheme v4\): true', out):
v4 = True
except Exception:
logger.exception('Failed to get signature versions')
return v1, v2, v3, v4
def apksigtool_cert(apk_path, tools_dir):
"""Get Human readable certificate with apksigtool."""
certlist = []
certs = []
pub_keys = []
signed, v1, v2, v3, v4 = False, False, False, False, 'Unknown'
signed = False
certs_no = 0
min_sdk = None
v1, v2, v3, v4 = get_signature_versions(
apk_path, tools_dir)
try:
from apksigtool import (
APKSignatureSchemeBlock,
@@ -104,12 +137,6 @@ def apksigtool_cert(apk_path):
b = pair.value
if isinstance(b, APKSignatureSchemeBlock):
signed = True
if b.version == 1:
v1 = True
if b.version == 2:
v2 = True
if b.version == 3:
v3 = True
for signer in b.signers:
if b.is_v3():
min_sdk = signer.min_sdk
@@ -149,19 +176,18 @@ def apksigtool_cert(apk_path):
}
def get_cert_data(a):
def get_cert_data(a, app_path, tools_dir):
"""Get Human readable certificate."""
certlist = []
signed, v1, v2, v3, v4 = False, False, False, False, 'Unknown'
signed = False
v1, v2, v3, v4 = get_signature_versions(
app_path, tools_dir)
if a.is_signed():
signed = True
certlist.append('Binary is signed')
else:
certlist.append('Binary is not signed')
certlist.append('Missing certificate')
v1 = a.is_signed_v1()
v2 = a.is_signed_v2()
v3 = a.is_signed_v3()
certlist.append(f'v1 signature: {v1}')
certlist.append(f'v2 signature: {v2}')
certlist.append(f'v3 signature: {v3}')
@@ -192,7 +218,7 @@ def get_cert_data(a):
}
def cert_info(a, app_path, app_dir, man_dict):
def cert_info(a, app_dic, man_dict):
"""Return certificate information."""
try:
logger.info('Reading Code Signing Certificate')
@@ -202,13 +228,15 @@ def cert_info(a, app_path, app_dir, man_dict):
summary = {HIGH: 0, WARNING: 0, INFO: 0}
if a:
cert_data = get_cert_data(a)
cert_data = get_cert_data(
a, app_dic['app_path'], app_dic['tools_dir'])
else:
logger.warning('androguard certificate parsing failed,'
' switching to apksigtool')
cert_data = apksigtool_cert(app_path)
cert_data = apksigtool_cert(
app_dic['app_path'], app_dic['tools_dir'])
cert_path = os.path.join(app_dir, 'META-INF/')
cert_path = os.path.join(app_dic['app_dir'], 'META-INF/')
if os.path.exists(cert_path):
files = [f for f in os.listdir(
cert_path) if os.path.isfile(os.path.join(cert_path, f))]
@@ -100,8 +100,7 @@ def common_analysis(request, app_dic, rescan, api, analysis_type):
)
cert_dic = cert_info(
apk,
app_dic['app_path'],
app_dic['app_dir'],
app_dic,
man_data_dic)
else:
app_dic['manifest_file'] = None
@@ -205,8 +205,7 @@ def static_analyzer(request, api=False):
elf_dict = library_analysis(app_dic['app_dir'], 'elf')
cert_dic = cert_info(
apk,
app_dic['app_path'],
app_dic['app_dir'],
app_dic,
man_data_dic)
apkid_results = apkid_analysis(app_dic[
'app_dir'], app_dic['app_path'], app_dic['app_name'])
Generated
+7 -7
View File
@@ -1301,13 +1301,13 @@ pyasn1 = ">=0.4.6"
[[package]]
name = "libsast"
version = "2.0.0"
version = "2.0.2"
description = "A generic SAST library built on top of semgrep and regex"
optional = false
python-versions = ">=3.8,<4.0"
files = [
{file = "libsast-2.0.0-py3-none-any.whl", hash = "sha256:424c94abadb9801dc5bb1c9afa8f189a8a4097e0b04b7a857e15da35de76c60b"},
{file = "libsast-2.0.0.tar.gz", hash = "sha256:476d43d5af63d99ea57c9ece2b5d8b7da113ece18c219a258fecc31b6fcc97bb"},
{file = "libsast-2.0.2-py3-none-any.whl", hash = "sha256:f9c0a78cad457444af391be355419956abb7019f616437094153efb279ddf4c9"},
{file = "libsast-2.0.2.tar.gz", hash = "sha256:6465fb44ae0a27a48b398445117f5a785b41b923965a1a3c653e253e2ec29339"},
]
[package.dependencies]
@@ -2959,13 +2959,13 @@ testing = ["coverage (>=5.0)", "pytest", "pytest-cover"]
[[package]]
name = "wcmatch"
version = "8.4.1"
version = "8.5"
description = "Wildcard/glob file name matcher."
optional = false
python-versions = ">=3.7"
python-versions = ">=3.8"
files = [
{file = "wcmatch-8.4.1-py3-none-any.whl", hash = "sha256:3476cd107aba7b25ba1d59406938a47dc7eec6cfd0ad09ff77193f21a964dee7"},
{file = "wcmatch-8.4.1.tar.gz", hash = "sha256:b1f042a899ea4c458b7321da1b5e3331e3e0ec781583434de1301946ceadb943"},
{file = "wcmatch-8.5-py3-none-any.whl", hash = "sha256:14554e409b142edeefab901dc68ad570b30a72a8ab9a79106c5d5e9a6d241bd5"},
{file = "wcmatch-8.5.tar.gz", hash = "sha256:86c17572d0f75cbf3bcb1a18f3bf2f9e72b39a9c08c9b4a74e991e1882a8efb3"},
]
[package.dependencies]