Skip to content

Commit

Permalink
Merge pull request #13 from devaa-security/u/s5dev/release
Browse files Browse the repository at this point in the history
Release 1.1.0
  • Loading branch information
s5dev authored Aug 27, 2023
2 parents f252980 + 035db84 commit a9c5dc6
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 69 deletions.
7 changes: 4 additions & 3 deletions manifest-scanner/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "manifest-scanner",
"version": "1.0.9",
"version": "1.1.0",
"description": "Manifest Scanner for Android Application",
"author": "Shivasurya @s5dev",
"bin": {
Expand All @@ -14,7 +14,8 @@
"/bin",
"/dist",
"/npm-shrinkwrap.json",
"/oclif.manifest.json"
"/oclif.manifest.json",
"/dist/resource/*.jar"
],
"dependencies": {
"@oclif/core": "^2",
Expand Down Expand Up @@ -57,7 +58,7 @@
}
},
"scripts": {
"build": "shx rm -rf dist && tsc -b",
"build": "shx rm -rf dist && tsc -b && npm run copy-jar",
"lint": "eslint . --ext .ts --config .eslintrc --fix",
"postpack": "shx rm -f oclif.manifest.json",
"posttest": "npm run lint",
Expand Down
13 changes: 9 additions & 4 deletions manifest-scanner/src/commands/scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export default class Scan extends Command {
}),
enableAST: Flags.boolean({
char: 'a',
description: 'Enable AST to parse Android Studio Project Java & Kotlin source code',
description:
'Enable AST to parse Android Studio Project Java & Kotlin source code',
}),
};

Expand Down Expand Up @@ -60,20 +61,24 @@ export default class Scan extends Command {
parseXmlFileToJson(filePath)
.then((result: any) => {
// console.log(JSON.stringify(result, null, 2));
const AndroidManifestXML = JSON.parse(JSON.stringify(result, null, 2))
const AndroidManifestXML = JSON.parse(
JSON.stringify(result, null, 2),
)
ManifestPlugin.updateManifest(
AndroidManifestXML,
filePath,
flags.file,
flags.enableAST
flags.enableAST,
)

const folders = [path.join(__dirname, '..', 'plugins', 'manifest')];

(async () => {
for (const folder of folders) {
let files = await fs.readdir(folder)
files = files.filter((file: any) => file.endsWith('.js') || !file.endsWith('.d.ts'))
files = files.filter(
(file: any) => file.endsWith('.js') || !file.endsWith('.d.ts'),
)

for (const file of files) {
// console.log(folder + "/" + file);
Expand Down
2 changes: 1 addition & 1 deletion manifest-scanner/src/plugins/ManifestPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default abstract class ManifestPlugin extends BasePlugin {
static targetSdk = -1;
static packageName = 'PACKAGE_NOT_FOUND';
static androidProjectDirectory = '';
static isASTEnabled = false
static isASTEnabled = false;

// add constructor accepting category, severity and description
constructor(category: string, severity: Severity, description: string) {
Expand Down
3 changes: 2 additions & 1 deletion manifest-scanner/src/plugins/manifest/AllowBackupRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export default class AllowBackupRule extends ManifestPlugin {

run(): void {
console.log('✅ Running AllowBackupRule')
const applicationTag = ManifestPlugin.manifestXMLObject.manifest.application
const applicationTag =
ManifestPlugin.manifestXMLObject.manifest.application
if (applicationTag && applicationTag.length > 0 && applicationTag[0].$) {
const allowBackupAttribute = applicationTag[0].$['android:allowBackup']

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ automatically by the tools',

run(): void {
console.log('✅ Running AndroidDebuggableRule')
const applicationTag = ManifestPlugin.manifestXMLObject.manifest.application
const applicationTag =
ManifestPlugin.manifestXMLObject.manifest.application
if (applicationTag && applicationTag.length > 0 && applicationTag[0].$) {
const allowBackupAttribute = applicationTag[0].$['android:debuggable']

Expand Down
12 changes: 6 additions & 6 deletions manifest-scanner/src/plugins/manifest/CustomPermissionRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,16 @@ device that can negatively impact the user.';
})
}
// else if protection level is signature or signatureOrSystem add to issues
else if ((
protectionLevel === 'signature' ||
protectionLevel === 'signatureOrSystem'
) && ManifestPlugin.targetSdk < 21) {
else if (
(protectionLevel === 'signature' ||
protectionLevel === 'signatureOrSystem') &&
ManifestPlugin.targetSdk < 21
) {
this.issues.push({
category: this.category,
name: 'Custom Permission Check',
severity: this.severity,
description:
this.SIGNATURE_OR_SIGNATURE_OR_SYSTEM_DESCRIPTION,
description: this.SIGNATURE_OR_SIGNATURE_OR_SYSTEM_DESCRIPTION,
file: getRelativePath(
ManifestPlugin.androidProjectDirectory,
ManifestPlugin.manifestPath,
Expand Down
112 changes: 61 additions & 51 deletions manifest-scanner/src/plugins/manifest/ExportedComponentRule.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { BaseJavaCstVisitorWithDefaults } from 'java-parser'
import { ManifestPlugin } from '../ManifestPlugin'
import { Severity, getRelativePath, searchKeywordInFile } from '../util'
import path from 'node:path';
import { execFileSync } from 'node:child_process';
const { execFile } = require('child_process');

import {BaseJavaCstVisitorWithDefaults} from 'java-parser'
import {ManifestPlugin} from '../ManifestPlugin'
import {Severity, getRelativePath, searchKeywordInFile} from '../util'
import path from 'node:path'
import {execFileSync} from 'node:child_process'
const {execFile} = require('child_process')

export default class ExportedComponentRule extends ManifestPlugin {
BAD_EXPORTED_TAGS = [
Expand Down Expand Up @@ -275,7 +274,6 @@ if the Intent carries data that is tainted (2nd order injection)`;
// });

// }

}

checkManifestIssue(exported_tag: string, tag: any): void {
Expand All @@ -293,36 +291,51 @@ if the Intent carries data that is tainted (2nd order injection)`;
}

if (ManifestPlugin.isASTEnabled) {
const resourceDir = path.resolve(path.join(__dirname, "..", "..", "resource"))
const resourceDir = path.resolve(
path.join(__dirname, '..', '..', 'resource'),
)

const javaPath = 'java'
const jarPath = path.join(
resourceDir,
'android-project-parser-1.0-SNAPSHOT-shaded.jar',
)
const lastDotIndex = name.lastIndexOf('.')
const className = name.slice(Math.max(0, lastDotIndex + 1))

const javaPath = 'java';
const jarPath = path.join(resourceDir, 'android-project-parser-1.0-SNAPSHOT-shaded.jar');
let lastDotIndex = name.lastIndexOf('.');
const className = name.substring(lastDotIndex + 1);

const args = [
'-jar',
jarPath,
'find-methods-declaration-invocations-arguments',
ManifestPlugin.androidProjectDirectory,
className
];
className,
]

const result = execFileSync(javaPath, args);
const result = execFileSync(javaPath, args)

if (result) {
methodResults = JSON.parse(result.toString());
methodResults = JSON.parse(result.toString())
if (!methodResults.errorMessage && methodResults.length > 0) {
let declaredMethods = methodResults;
declaredMethods.forEach((declaredMethod: { methodInvocations: any[]; }) => {
if (declaredMethod.methodInvocations.length > 0) {
declaredMethod.methodInvocations.forEach((methodInvocation: { methodName: string, arguments: [] }) => {
if (this.EXTRAS_METHOD_NAMES.includes(methodInvocation.methodName)) {
argumentVal = argumentVal.concat(methodInvocation.arguments)
}
});
}
});
const declaredMethods = methodResults
declaredMethods.forEach(
(declaredMethod: { methodInvocations: any[] }) => {
if (declaredMethod.methodInvocations.length > 0) {
declaredMethod.methodInvocations.forEach(
(methodInvocation: { methodName: string; arguments: [] }) => {
if (
this.EXTRAS_METHOD_NAMES.includes(
methodInvocation.methodName,
)
) {
argumentVal = argumentVal.concat(
methodInvocation.arguments,
)
}
},
)
}
},
)
}
}
}
Expand Down Expand Up @@ -355,9 +368,9 @@ if the Intent carries data that is tainted (2nd order injection)`;
ManifestPlugin.manifestPath,
),
exploit: {
"exported_enum": name,
"tag_name": exported_tag,
"arguments": argumentVal,
exported_enum: name,
tag_name: exported_tag,
arguments: argumentVal,
},
line: result?.line,
start_column: result?.start_column,
Expand All @@ -383,10 +396,10 @@ if the Intent carries data that is tainted (2nd order injection)`;
ManifestPlugin.manifestPath,
),
exploit: {
"exported_enum": name,
"tag_name": exported_tag,
"package_name": ManifestPlugin.packageName,
"arguments": argumentVal
exported_enum: name,
tag_name: exported_tag,
package_name: ManifestPlugin.packageName,
arguments: argumentVal,
},
line: result?.line,
start_column: result?.start_column,
Expand All @@ -407,7 +420,6 @@ if the Intent carries data that is tainted (2nd order injection)`;
)

if (this.PROTECTED_BROADCASTS.includes(actionName)) {

let description = this.EXPORTED_IN_PROTECTED
description = description.replaceAll('{tag}', exported_tag)
description = description.replace('{tag_name}', name)
Expand All @@ -422,17 +434,16 @@ if the Intent carries data that is tainted (2nd order injection)`;
ManifestPlugin.manifestPath,
),
exploit: {
"exported_enum": name,
"tag_name": exported_tag,
"package_name": ManifestPlugin.packageName,
"arguments": argumentVal
exported_enum: name,
tag_name: exported_tag,
package_name: ManifestPlugin.packageName,
arguments: argumentVal,
},
line: result?.line,
start_column: result?.start_column,
end_column: result?.end_column,
})
} else if (permission && ManifestPlugin.minSdk < 20) {

let description = this.EXPORTED_AND_PERMISSION_TAG
description = description.replaceAll('{tag}', exported_tag)
description = description.replace('{tag_name}', name)
Expand All @@ -447,17 +458,16 @@ if the Intent carries data that is tainted (2nd order injection)`;
ManifestPlugin.manifestPath,
),
exploit: {
"exported_enum": name,
"tag_name": exported_tag,
"package_name": ManifestPlugin.packageName,
"arguments": argumentVal
exported_enum: name,
tag_name: exported_tag,
package_name: ManifestPlugin.packageName,
arguments: argumentVal,
},
line: result?.line,
start_column: result?.start_column,
end_column: result?.end_column,
})
} else {

let description = this.EXPORTED
description = description.replaceAll('{tag}', exported_tag)
description = description.replace('{tag_name}', name)
Expand All @@ -471,10 +481,10 @@ if the Intent carries data that is tainted (2nd order injection)`;
ManifestPlugin.manifestPath,
),
exploit: {
"exported_enum": name,
"tag_name": exported_tag,
"package_name": ManifestPlugin.packageName,
"arguments": argumentVal
exported_enum: name,
tag_name: exported_tag,
package_name: ManifestPlugin.packageName,
arguments: argumentVal,
},
name: 'Exported Components Check',
line: result?.line,
Expand Down Expand Up @@ -526,4 +536,4 @@ const TAG_INFO: any = {
activity: Activity,
'activity-alias': Activity,
service: Service,
}
}
12 changes: 10 additions & 2 deletions manifest-scanner/test/commands/scan.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@ describe('scan', () => {
.stdout()
.command(['help', 'scan'])
.it('runs scan help command', ctx => {
expect(ctx.stdout).to.contain('DEVAA Manifest Scanner helps to scan for vulnerable configurations in Android Manifest file')
expect(ctx.stdout).to.contain(
'DEVAA Manifest Scanner helps to scan for vulnerable configurations in Android Studio Project',
)
})

test
.stdout()
.command(['scan', '--file', 'C:\\Users\\Shiva\\AndroidStudioProjects\\DEVAAVulnerableApp', '--report', 'json'])
.command([
'scan',
'--file',
'C:\\Users\\Shiva\\AndroidStudioProjects\\DEVAAVulnerableApp',
'--report',
'json',
])
.it('runs scan with file and report parameter', ctx => {
expect(ctx.stdout).to.contain('Running')
})
Expand Down

0 comments on commit a9c5dc6

Please sign in to comment.