Skip to content

Commit a9c5dc6

Browse files
authored
Merge pull request #13 from devaa-security/u/s5dev/release
Release 1.1.0
2 parents f252980 + 035db84 commit a9c5dc6

8 files changed

Lines changed: 95 additions & 69 deletions

File tree

manifest-scanner/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "manifest-scanner",
3-
"version": "1.0.9",
3+
"version": "1.1.0",
44
"description": "Manifest Scanner for Android Application",
55
"author": "Shivasurya @s5dev",
66
"bin": {
@@ -14,7 +14,8 @@
1414
"/bin",
1515
"/dist",
1616
"/npm-shrinkwrap.json",
17-
"/oclif.manifest.json"
17+
"/oclif.manifest.json",
18+
"/dist/resource/*.jar"
1819
],
1920
"dependencies": {
2021
"@oclif/core": "^2",
@@ -57,7 +58,7 @@
5758
}
5859
},
5960
"scripts": {
60-
"build": "shx rm -rf dist && tsc -b",
61+
"build": "shx rm -rf dist && tsc -b && npm run copy-jar",
6162
"lint": "eslint . --ext .ts --config .eslintrc --fix",
6263
"postpack": "shx rm -f oclif.manifest.json",
6364
"posttest": "npm run lint",

manifest-scanner/src/commands/scan.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export default class Scan extends Command {
2727
}),
2828
enableAST: Flags.boolean({
2929
char: 'a',
30-
description: 'Enable AST to parse Android Studio Project Java & Kotlin source code',
30+
description:
31+
'Enable AST to parse Android Studio Project Java & Kotlin source code',
3132
}),
3233
};
3334

@@ -60,20 +61,24 @@ export default class Scan extends Command {
6061
parseXmlFileToJson(filePath)
6162
.then((result: any) => {
6263
// console.log(JSON.stringify(result, null, 2));
63-
const AndroidManifestXML = JSON.parse(JSON.stringify(result, null, 2))
64+
const AndroidManifestXML = JSON.parse(
65+
JSON.stringify(result, null, 2),
66+
)
6467
ManifestPlugin.updateManifest(
6568
AndroidManifestXML,
6669
filePath,
6770
flags.file,
68-
flags.enableAST
71+
flags.enableAST,
6972
)
7073

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

7376
(async () => {
7477
for (const folder of folders) {
7578
let files = await fs.readdir(folder)
76-
files = files.filter((file: any) => file.endsWith('.js') || !file.endsWith('.d.ts'))
79+
files = files.filter(
80+
(file: any) => file.endsWith('.js') || !file.endsWith('.d.ts'),
81+
)
7782

7883
for (const file of files) {
7984
// console.log(folder + "/" + file);

manifest-scanner/src/plugins/ManifestPlugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export default abstract class ManifestPlugin extends BasePlugin {
88
static targetSdk = -1;
99
static packageName = 'PACKAGE_NOT_FOUND';
1010
static androidProjectDirectory = '';
11-
static isASTEnabled = false
11+
static isASTEnabled = false;
1212

1313
// add constructor accepting category, severity and description
1414
constructor(category: string, severity: Severity, description: string) {

manifest-scanner/src/plugins/manifest/AllowBackupRule.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ export default class AllowBackupRule extends ManifestPlugin {
1414

1515
run(): void {
1616
console.log('✅ Running AllowBackupRule')
17-
const applicationTag = ManifestPlugin.manifestXMLObject.manifest.application
17+
const applicationTag =
18+
ManifestPlugin.manifestXMLObject.manifest.application
1819
if (applicationTag && applicationTag.length > 0 && applicationTag[0].$) {
1920
const allowBackupAttribute = applicationTag[0].$['android:allowBackup']
2021

manifest-scanner/src/plugins/manifest/AndroidDebuggableRule.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ automatically by the tools',
1818

1919
run(): void {
2020
console.log('✅ Running AndroidDebuggableRule')
21-
const applicationTag = ManifestPlugin.manifestXMLObject.manifest.application
21+
const applicationTag =
22+
ManifestPlugin.manifestXMLObject.manifest.application
2223
if (applicationTag && applicationTag.length > 0 && applicationTag[0].$) {
2324
const allowBackupAttribute = applicationTag[0].$['android:debuggable']
2425

manifest-scanner/src/plugins/manifest/CustomPermissionRule.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,16 @@ device that can negatively impact the user.';
5959
})
6060
}
6161
// else if protection level is signature or signatureOrSystem add to issues
62-
else if ((
63-
protectionLevel === 'signature' ||
64-
protectionLevel === 'signatureOrSystem'
65-
) && ManifestPlugin.targetSdk < 21) {
62+
else if (
63+
(protectionLevel === 'signature' ||
64+
protectionLevel === 'signatureOrSystem') &&
65+
ManifestPlugin.targetSdk < 21
66+
) {
6667
this.issues.push({
6768
category: this.category,
6869
name: 'Custom Permission Check',
6970
severity: this.severity,
70-
description:
71-
this.SIGNATURE_OR_SIGNATURE_OR_SYSTEM_DESCRIPTION,
71+
description: this.SIGNATURE_OR_SIGNATURE_OR_SYSTEM_DESCRIPTION,
7272
file: getRelativePath(
7373
ManifestPlugin.androidProjectDirectory,
7474
ManifestPlugin.manifestPath,

manifest-scanner/src/plugins/manifest/ExportedComponentRule.ts

Lines changed: 61 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { BaseJavaCstVisitorWithDefaults } from 'java-parser'
2-
import { ManifestPlugin } from '../ManifestPlugin'
3-
import { Severity, getRelativePath, searchKeywordInFile } from '../util'
4-
import path from 'node:path';
5-
import { execFileSync } from 'node:child_process';
6-
const { execFile } = require('child_process');
7-
1+
import {BaseJavaCstVisitorWithDefaults} from 'java-parser'
2+
import {ManifestPlugin} from '../ManifestPlugin'
3+
import {Severity, getRelativePath, searchKeywordInFile} from '../util'
4+
import path from 'node:path'
5+
import {execFileSync} from 'node:child_process'
6+
const {execFile} = require('child_process')
87

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

277276
// }
278-
279277
}
280278

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

295293
if (ManifestPlugin.isASTEnabled) {
296-
const resourceDir = path.resolve(path.join(__dirname, "..", "..", "resource"))
294+
const resourceDir = path.resolve(
295+
path.join(__dirname, '..', '..', 'resource'),
296+
)
297+
298+
const javaPath = 'java'
299+
const jarPath = path.join(
300+
resourceDir,
301+
'android-project-parser-1.0-SNAPSHOT-shaded.jar',
302+
)
303+
const lastDotIndex = name.lastIndexOf('.')
304+
const className = name.slice(Math.max(0, lastDotIndex + 1))
297305

298-
const javaPath = 'java';
299-
const jarPath = path.join(resourceDir, 'android-project-parser-1.0-SNAPSHOT-shaded.jar');
300-
let lastDotIndex = name.lastIndexOf('.');
301-
const className = name.substring(lastDotIndex + 1);
302-
303306
const args = [
304307
'-jar',
305308
jarPath,
306309
'find-methods-declaration-invocations-arguments',
307310
ManifestPlugin.androidProjectDirectory,
308-
className
309-
];
311+
className,
312+
]
310313

311-
const result = execFileSync(javaPath, args);
314+
const result = execFileSync(javaPath, args)
312315

313316
if (result) {
314-
methodResults = JSON.parse(result.toString());
317+
methodResults = JSON.parse(result.toString())
315318
if (!methodResults.errorMessage && methodResults.length > 0) {
316-
let declaredMethods = methodResults;
317-
declaredMethods.forEach((declaredMethod: { methodInvocations: any[]; }) => {
318-
if (declaredMethod.methodInvocations.length > 0) {
319-
declaredMethod.methodInvocations.forEach((methodInvocation: { methodName: string, arguments: [] }) => {
320-
if (this.EXTRAS_METHOD_NAMES.includes(methodInvocation.methodName)) {
321-
argumentVal = argumentVal.concat(methodInvocation.arguments)
322-
}
323-
});
324-
}
325-
});
319+
const declaredMethods = methodResults
320+
declaredMethods.forEach(
321+
(declaredMethod: { methodInvocations: any[] }) => {
322+
if (declaredMethod.methodInvocations.length > 0) {
323+
declaredMethod.methodInvocations.forEach(
324+
(methodInvocation: { methodName: string; arguments: [] }) => {
325+
if (
326+
this.EXTRAS_METHOD_NAMES.includes(
327+
methodInvocation.methodName,
328+
)
329+
) {
330+
argumentVal = argumentVal.concat(
331+
methodInvocation.arguments,
332+
)
333+
}
334+
},
335+
)
336+
}
337+
},
338+
)
326339
}
327340
}
328341
}
@@ -355,9 +368,9 @@ if the Intent carries data that is tainted (2nd order injection)`;
355368
ManifestPlugin.manifestPath,
356369
),
357370
exploit: {
358-
"exported_enum": name,
359-
"tag_name": exported_tag,
360-
"arguments": argumentVal,
371+
exported_enum: name,
372+
tag_name: exported_tag,
373+
arguments: argumentVal,
361374
},
362375
line: result?.line,
363376
start_column: result?.start_column,
@@ -383,10 +396,10 @@ if the Intent carries data that is tainted (2nd order injection)`;
383396
ManifestPlugin.manifestPath,
384397
),
385398
exploit: {
386-
"exported_enum": name,
387-
"tag_name": exported_tag,
388-
"package_name": ManifestPlugin.packageName,
389-
"arguments": argumentVal
399+
exported_enum: name,
400+
tag_name: exported_tag,
401+
package_name: ManifestPlugin.packageName,
402+
arguments: argumentVal,
390403
},
391404
line: result?.line,
392405
start_column: result?.start_column,
@@ -407,7 +420,6 @@ if the Intent carries data that is tainted (2nd order injection)`;
407420
)
408421

409422
if (this.PROTECTED_BROADCASTS.includes(actionName)) {
410-
411423
let description = this.EXPORTED_IN_PROTECTED
412424
description = description.replaceAll('{tag}', exported_tag)
413425
description = description.replace('{tag_name}', name)
@@ -422,17 +434,16 @@ if the Intent carries data that is tainted (2nd order injection)`;
422434
ManifestPlugin.manifestPath,
423435
),
424436
exploit: {
425-
"exported_enum": name,
426-
"tag_name": exported_tag,
427-
"package_name": ManifestPlugin.packageName,
428-
"arguments": argumentVal
437+
exported_enum: name,
438+
tag_name: exported_tag,
439+
package_name: ManifestPlugin.packageName,
440+
arguments: argumentVal,
429441
},
430442
line: result?.line,
431443
start_column: result?.start_column,
432444
end_column: result?.end_column,
433445
})
434446
} else if (permission && ManifestPlugin.minSdk < 20) {
435-
436447
let description = this.EXPORTED_AND_PERMISSION_TAG
437448
description = description.replaceAll('{tag}', exported_tag)
438449
description = description.replace('{tag_name}', name)
@@ -447,17 +458,16 @@ if the Intent carries data that is tainted (2nd order injection)`;
447458
ManifestPlugin.manifestPath,
448459
),
449460
exploit: {
450-
"exported_enum": name,
451-
"tag_name": exported_tag,
452-
"package_name": ManifestPlugin.packageName,
453-
"arguments": argumentVal
461+
exported_enum: name,
462+
tag_name: exported_tag,
463+
package_name: ManifestPlugin.packageName,
464+
arguments: argumentVal,
454465
},
455466
line: result?.line,
456467
start_column: result?.start_column,
457468
end_column: result?.end_column,
458469
})
459470
} else {
460-
461471
let description = this.EXPORTED
462472
description = description.replaceAll('{tag}', exported_tag)
463473
description = description.replace('{tag_name}', name)
@@ -471,10 +481,10 @@ if the Intent carries data that is tainted (2nd order injection)`;
471481
ManifestPlugin.manifestPath,
472482
),
473483
exploit: {
474-
"exported_enum": name,
475-
"tag_name": exported_tag,
476-
"package_name": ManifestPlugin.packageName,
477-
"arguments": argumentVal
484+
exported_enum: name,
485+
tag_name: exported_tag,
486+
package_name: ManifestPlugin.packageName,
487+
arguments: argumentVal,
478488
},
479489
name: 'Exported Components Check',
480490
line: result?.line,
@@ -526,4 +536,4 @@ const TAG_INFO: any = {
526536
activity: Activity,
527537
'activity-alias': Activity,
528538
service: Service,
529-
}
539+
}

manifest-scanner/test/commands/scan.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@ describe('scan', () => {
55
.stdout()
66
.command(['help', 'scan'])
77
.it('runs scan help command', ctx => {
8-
expect(ctx.stdout).to.contain('DEVAA Manifest Scanner helps to scan for vulnerable configurations in Android Manifest file')
8+
expect(ctx.stdout).to.contain(
9+
'DEVAA Manifest Scanner helps to scan for vulnerable configurations in Android Studio Project',
10+
)
911
})
1012

1113
test
1214
.stdout()
13-
.command(['scan', '--file', 'C:\\Users\\Shiva\\AndroidStudioProjects\\DEVAAVulnerableApp', '--report', 'json'])
15+
.command([
16+
'scan',
17+
'--file',
18+
'C:\\Users\\Shiva\\AndroidStudioProjects\\DEVAAVulnerableApp',
19+
'--report',
20+
'json',
21+
])
1422
.it('runs scan with file and report parameter', ctx => {
1523
expect(ctx.stdout).to.contain('Running')
1624
})

0 commit comments

Comments
 (0)