- 更新apktool为最新版本

- 优化部分环节流程
- 修复excle文件导出时超时行数限制
- 修复脚本执行时卡顿的问题
- 修复Mac下Playload文件权限不足的问题
v1.0.09 V1.0.9_Releases
kelvinBen 2 years ago
parent 51ca5a0c5b
commit 827ef29e65
  1. 40
      app.py
  2. 120
      config.py
  3. 5
      libs/core/__init__.py
  4. 23
      libs/core/download.py
  5. 40
      libs/core/net.py
  6. 48
      libs/core/parses.py
  7. 77
      libs/task/android_task.py
  8. 70
      libs/task/base_task.py
  9. 18
      libs/task/download_task.py
  10. 86
      libs/task/ios_task.py
  11. 64
      libs/task/net_task.py
  12. 19
      libs/task/web_task.py
  13. 2
      requirements.txt
  14. BIN
      tools/apktool.jar
  15. 7
      update.md

@ -8,21 +8,24 @@ import click
from libs.core import Bootstrapper from libs.core import Bootstrapper
from libs.task.base_task import BaseTask from libs.task.base_task import BaseTask
@click.group(help="Python script for automatically retrieving key information in app.") @click.group(help="Python script for automatically retrieving key information in app.")
def cli(): def cli():
pass pass
# 创建Android任务 # 创建Android任务
@cli.command(help="Get the key information of Android system.") @cli.command(help="Get the key information of Android system.")
@click.option("-i", "--inputs", required=True, type=str, help="Please enter the APK file or DEX file to be scanned or the corresponding APK download address.") @click.option("-i", "--inputs", required=True, type=str, help="Please enter the APK file or DEX file to be scanned or the corresponding APK download address.")
@click.option("-r", "--rules", required=False, type=str, default="", help="Please enter a rule for temporary scanning of file contents.") @click.option("-r", "--rules", required=False, type=str, default="", help="Please enter a rule for temporary scanning of file contents.")
@click.option("-s", "--sniffer", is_flag=True, default=False, help="Enable the network sniffer function. It is on by default.") @click.option("-s", "--sniffer", is_flag=True, default=False, help="Enable the network sniffer function. It is on by default.")
@click.option("-n", '--no-resource', is_flag=True, default=False,help="Ignore all resource files, including network sniffing. It is not enabled by default.") @click.option("-n", '--no-resource', is_flag=True, default=False, help="Ignore all resource files, including network sniffing. It is not enabled by default.")
@click.option("-a", '--all',is_flag=True, default=False,help="Output the string content that conforms to the scan rules.It is on by default.") @click.option("-a", '--all', is_flag=True, default=False, help="Output the string content that conforms to the scan rules.It is on by default.")
@click.option("-t", '--threads',required=False, type=int,default=10,help="Set the number of concurrency. The larger the concurrency, the faster the speed. The default value is 10.") @click.option("-t", '--threads', required=False, type=int, default=10, help="Set the number of concurrency. The larger the concurrency, the faster the speed. The default value is 10.")
@click.option("-o", '--output',required=False, type=str,default=None,help="Specify the result set output directory.") @click.option("-o", '--output', required=False, type=str, default=None, help="Specify the result set output directory.")
@click.option("-p", '--package',required=False,type=str,default="",help="Specifies the package name information that needs to be scanned.") @click.option("-p", '--package', required=False, type=str, default="", help="Specifies the package name information that needs to be scanned.")
def android(inputs: str, rules: str, sniffer: bool, no_resource:bool, all:bool, threads:int, output, package:str) -> None: def android(inputs: str, rules: str, sniffer: bool, no_resource: bool, all: bool, threads: int, output, package: str) -> None:
try: try:
bootstrapper = Bootstrapper(__file__, output, all, no_resource) bootstrapper = Bootstrapper(__file__, output, all, no_resource)
bootstrapper.init() bootstrapper.init()
@ -31,15 +34,16 @@ def android(inputs: str, rules: str, sniffer: bool, no_resource:bool, all:bool,
except Exception as e: except Exception as e:
raise e raise e
@cli.command(help="Get the key information of iOS system.") @cli.command(help="Get the key information of iOS system.")
@click.option("-i", "--inputs", required=True, type=str, help="Please enter IPA file or ELF file to scan or corresponding IPA download address. App store is not supported at present.") @click.option("-i", "--inputs", required=True, type=str, help="Please enter IPA file or ELF file to scan or corresponding IPA download address. App store is not supported at present.")
@click.option("-r", "--rules", required=False, type=str, default="", help="Please enter a rule for temporary scanning of file contents.") @click.option("-r", "--rules", required=False, type=str, default="", help="Please enter a rule for temporary scanning of file contents.")
@click.option("-s", "--sniffer", is_flag=True, default=False, help="Enable the network sniffer function. It is on by default.") @click.option("-s", "--sniffer", is_flag=True, default=False, help="Enable the network sniffer function. It is on by default.")
@click.option("-n", '--no-resource', is_flag=True, default=False,help="Ignore all resource files, including network sniffing. It is not enabled by default.") @click.option("-n", '--no-resource', is_flag=True, default=False, help="Ignore all resource files, including network sniffing. It is not enabled by default.")
@click.option("-a", '--all',is_flag=True, default=False,help="Output the string content that conforms to the scan rules.It is on by default.") @click.option("-a", '--all', is_flag=True, default=False, help="Output the string content that conforms to the scan rules.It is on by default.")
@click.option("-t", '--threads',required=False, type=int,default=10,help="Set the number of concurrency. The larger the concurrency, the faster the speed. The default value is 10.") @click.option("-t", '--threads', required=False, type=int, default=10, help="Set the number of concurrency. The larger the concurrency, the faster the speed. The default value is 10.")
@click.option("-o", '--output',required=False, type=str,default=None,help="Specify the result set output directory.") @click.option("-o", '--output', required=False, type=str, default=None, help="Specify the result set output directory.")
def ios(inputs: str, rules: str, sniffer: bool, no_resource:bool, all:bool, threads:int, output:str) -> None: def ios(inputs: str, rules: str, sniffer: bool, no_resource: bool, all: bool, threads: int, output: str) -> None:
try: try:
bootstrapper = Bootstrapper(__file__, output, all, no_resource) bootstrapper = Bootstrapper(__file__, output, all, no_resource)
bootstrapper.init() bootstrapper.init()
@ -48,15 +52,16 @@ def ios(inputs: str, rules: str, sniffer: bool, no_resource:bool, all:bool, thre
except Exception as e: except Exception as e:
raise e raise e
@cli.command(help="Get the key information of Web system.") @cli.command(help="Get the key information of Web system.")
@click.option("-i", "--inputs", required=True, type=str, help="Please enter the site directory or site file to scan or the corresponding site download address.") @click.option("-i", "--inputs", required=True, type=str, help="Please enter the site directory or site file to scan or the corresponding site download address.")
@click.option("-r", "--rules", required=False, type=str, default="", help="Please enter a rule for temporary scanning of file contents.") @click.option("-r", "--rules", required=False, type=str, default="", help="Please enter a rule for temporary scanning of file contents.")
@click.option("-s", "--sniffer", is_flag=True, default=False, help="Enable the network sniffer function. It is on by default.") @click.option("-s", "--sniffer", is_flag=True, default=False, help="Enable the network sniffer function. It is on by default.")
@click.option("-n", '--no-resource', is_flag=True, default=False,help="Ignore all resource files, including network sniffing. It is not enabled by default.") @click.option("-n", '--no-resource', is_flag=True, default=False, help="Ignore all resource files, including network sniffing. It is not enabled by default.")
@click.option("-a", '--all',is_flag=True, default=False,help="Output the string content that conforms to the scan rules.It is on by default.") @click.option("-a", '--all', is_flag=True, default=False, help="Output the string content that conforms to the scan rules.It is on by default.")
@click.option("-t", '--threads',required=False, type=int,default=10,help="Set the number of concurrency. The larger the concurrency, the faster the speed. The default value is 10.") @click.option("-t", '--threads', required=False, type=int, default=10, help="Set the number of concurrency. The larger the concurrency, the faster the speed. The default value is 10.")
@click.option("-o", '--output',required=False, type=str,default=None,help="Specify the result set output directory.") @click.option("-o", '--output', required=False, type=str, default=None, help="Specify the result set output directory.")
def web(inputs: str, rules: str, sniffer: bool, no_resource:bool, all:bool, threads:int, output:str) -> None: def web(inputs: str, rules: str, sniffer: bool, no_resource: bool, all: bool, threads: int, output: str) -> None:
try: try:
bootstrapper = Bootstrapper(__file__, output, all, no_resource) bootstrapper = Bootstrapper(__file__, output, all, no_resource)
bootstrapper.init() bootstrapper.init()
@ -65,9 +70,10 @@ def web(inputs: str, rules: str, sniffer: bool, no_resource:bool, all:bool, thre
except Exception as e: except Exception as e:
raise e raise e
def main(): def main():
cli() cli()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

@ -28,7 +28,7 @@ filter_components = [
# 1. https://以及http://开头的 # 1. https://以及http://开头的
# 2. IPv4的ip地址 # 2. IPv4的ip地址
# 3. URI地址,URI不能很好的拼接所以此处忽略 # 3. URI地址,URI不能很好的拼接所以此处忽略
filter_strs =[ filter_strs = [
r'https://.*|http://.*', r'https://.*|http://.*',
# r'.*://([[0-9]{1,3}\.]{3}[0-9]{1,3}).*', # r'.*://([[0-9]{1,3}\.]{3}[0-9]{1,3}).*',
r'.*://([\d{1,3}\.]{3}\d{1,3}).*', r'.*://([\d{1,3}\.]{3}\d{1,3}).*',
@ -50,79 +50,80 @@ filter_no = [
r'.*w3school.com.cn', r'.*w3school.com.cn',
r'.*apple.com', r'.*apple.com',
r'.*.amap.com', r'.*.amap.com',
r'.*slf4j.org',
] ]
# AK集合 # AK集合
filter_ak_map = { filter_ak_map = {
"Aliyun_OSS": [ "Aliyun_OSS": [
r'.*accessKeyId.*".*"', r'.*accessKeyId.*".*?"',
r'.*accessKeySecret.*".*"', r'.*accessKeySecret.*".*?"',
r'.*secret.*".*"' r'.*secret.*".*?"'
], ],
#"Amazon_AWS_Access_Key_ID": r"([^A-Z0-9]|^)(AKIA|A3T|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{12,}", # "Amazon_AWS_Access_Key_ID": r"([^A-Z0-9]|^)(AKIA|A3T|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{12,}",
#"Amazon_AWS_S3_Bucket": [ # "Amazon_AWS_S3_Bucket": [
# r"//s3-[a-z0-9-]+\\.amazonaws\\.com/[a-z0-9._-]+", # r"//s3-[a-z0-9-]+\\.amazonaws\\.com/[a-z0-9._-]+",
# r"//s3\\.amazonaws\\.com/[a-z0-9._-]+", # r"//s3\\.amazonaws\\.com/[a-z0-9._-]+",
# r"[a-z0-9.-]+\\.s3-[a-z0-9-]\\.amazonaws\\.com", # r"[a-z0-9.-]+\\.s3-[a-z0-9-]\\.amazonaws\\.com",
# r"[a-z0-9.-]+\\.s3-website[.-](eu|ap|us|ca|sa|cn)", # r"[a-z0-9.-]+\\.s3-website[.-](eu|ap|us|ca|sa|cn)",
# r"[a-z0-9.-]+\\.s3\\.amazonaws\\.com", # r"[a-z0-9.-]+\\.s3\\.amazonaws\\.com",
# r"amzn\\.mws\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" # r"amzn\\.mws\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
#], # ],
#"Artifactory_API_Token": r"(?:\\s|=|:|\"|^)AKC[a-zA-Z0-9]{10,}", # "Artifactory_API_Token": r"(?:\\s|=|:|\"|^)AKC[a-zA-Z0-9]{10,}",
#"Artifactory_Password": r"(?:\\s|=|:|\"|^)AP[\\dABCDEF][a-zA-Z0-9]{8,}", # "Artifactory_Password": r"(?:\\s|=|:|\"|^)AP[\\dABCDEF][a-zA-Z0-9]{8,}",
# "Authorization_Basic": r"basic\\s[a-zA-Z0-9_\\-:\\.=]+", # "Authorization_Basic": r"basic\\s[a-zA-Z0-9_\\-:\\.=]+",
# "Authorization_Bearer": r"bearer\\s[a-zA-Z0-9_\\-:\\.=]+", # "Authorization_Bearer": r"bearer\\s[a-zA-Z0-9_\\-:\\.=]+",
#"AWS_API_Key": r"AKIA[0-9A-Z]{16}", # "AWS_API_Key": r"AKIA[0-9A-Z]{16}",
#"Basic_Auth_Credentials": r"(?<=:\/\/)[a-zA-Z0-9]+:[a-zA-Z0-9]+@[a-zA-Z0-9]+\\.[a-zA-Z]+", # "Basic_Auth_Credentials": r"(?<=:\/\/)[a-zA-Z0-9]+:[a-zA-Z0-9]+@[a-zA-Z0-9]+\\.[a-zA-Z]+",
#"Cloudinary_Basic_Auth": r"cloudinary:\/\/[0-9]{15}:[0-9A-Za-z]+@[a-z]+", # "Cloudinary_Basic_Auth": r"cloudinary:\/\/[0-9]{15}:[0-9A-Za-z]+@[a-z]+",
#"DEFCON_CTF_Flag": r"O{3}\\{.*\\}", # "DEFCON_CTF_Flag": r"O{3}\\{.*\\}",
#"Discord_BOT_Token": r"((?:N|M|O)[a-zA-Z0-9]{23}\\.[a-zA-Z0-9-_]{6}\\.[a-zA-Z0-9-_]{27})$", # "Discord_BOT_Token": r"((?:N|M|O)[a-zA-Z0-9]{23}\\.[a-zA-Z0-9-_]{6}\\.[a-zA-Z0-9-_]{27})$",
#"Facebook_Access_Token": r"EAACEdEose0cBA[0-9A-Za-z]+", # "Facebook_Access_Token": r"EAACEdEose0cBA[0-9A-Za-z]+",
#"Facebook_ClientID": r"[f|F][a|A][c|C][e|E][b|B][o|O][o|O][k|K](.{0,20})?['\"][0-9]{13,17}", # "Facebook_ClientID": r"[f|F][a|A][c|C][e|E][b|B][o|O][o|O][k|K](.{0,20})?['\"][0-9]{13,17}",
#"Facebook_OAuth": r"[f|F][a|A][c|C][e|E][b|B][o|O][o|O][k|K].*['|\"][0-9a-f]{32}['|\"]", # "Facebook_OAuth": r"[f|F][a|A][c|C][e|E][b|B][o|O][o|O][k|K].*['|\"][0-9a-f]{32}['|\"]",
#"Facebook_Secret_Key": r"([f|F][a|A][c|C][e|E][b|B][o|O][o|O][k|K]|[f|F][b|B])(.{0,20})?['\"][0-9a-f]{32}", # "Facebook_Secret_Key": r"([f|F][a|A][c|C][e|E][b|B][o|O][o|O][k|K]|[f|F][b|B])(.{0,20})?['\"][0-9a-f]{32}",
#"Firebase": r"[a-z0-9.-]+\\.firebaseio\\.com", # "Firebase": r"[a-z0-9.-]+\\.firebaseio\\.com",
#"Generic_API_Key": r"[a|A][p|P][i|I][_]?[k|K][e|E][y|Y].*['|\"][0-9a-zA-Z]{32,45}['|\"]", # "Generic_API_Key": r"[a|A][p|P][i|I][_]?[k|K][e|E][y|Y].*['|\"][0-9a-zA-Z]{32,45}['|\"]",
#"Generic_Secret": r"[s|S][e|E][c|C][r|R][e|E][t|T].*['|\"][0-9a-zA-Z]{32,45}['|\"]", # "Generic_Secret": r"[s|S][e|E][c|C][r|R][e|E][t|T].*['|\"][0-9a-zA-Z]{32,45}['|\"]",
#"GitHub": r"[g|G][i|I][t|T][h|H][u|U][b|B].*['|\"][0-9a-zA-Z]{35,40}['|\"]", # "GitHub": r"[g|G][i|I][t|T][h|H][u|U][b|B].*['|\"][0-9a-zA-Z]{35,40}['|\"]",
#"GitHub_Access_Token": r"([a-zA-Z0-9_-]*:[a-zA-Z0-9_-]+@github.com*)$", # "GitHub_Access_Token": r"([a-zA-Z0-9_-]*:[a-zA-Z0-9_-]+@github.com*)$",
#"Google_API_Key": r"AIza[0-9A-Za-z\\-_]{35}", # "Google_API_Key": r"AIza[0-9A-Za-z\\-_]{35}",
#"Google_Cloud_Platform_OAuth": r"[0-9]+-[0-9A-Za-z_]{32}\\.apps\\.googleusercontent\\.com", # "Google_Cloud_Platform_OAuth": r"[0-9]+-[0-9A-Za-z_]{32}\\.apps\\.googleusercontent\\.com",
#"Google_Cloud_Platform_Service_Account": r"\"type\": \"service_account\"", # "Google_Cloud_Platform_Service_Account": r"\"type\": \"service_account\"",
#"Google_OAuth_Access_Token": r"ya29\\.[0-9A-Za-z\\-_]+", # "Google_OAuth_Access_Token": r"ya29\\.[0-9A-Za-z\\-_]+",
#"HackerOne_CTF_Flag": r"[h|H]1(?:[c|C][t|T][f|F])?\\{.*\\}", # "HackerOne_CTF_Flag": r"[h|H]1(?:[c|C][t|T][f|F])?\\{.*\\}",
#"HackTheBox_CTF_Flag": r"[h|H](?:[a|A][c|C][k|K][t|T][h|H][e|E][b|B][o|O][x|X]|[t|T][b|B])\\{.*\\}$", # "HackTheBox_CTF_Flag": r"[h|H](?:[a|A][c|C][k|K][t|T][h|H][e|E][b|B][o|O][x|X]|[t|T][b|B])\\{.*\\}$",
#"Heroku_API_Key": r"[h|H][e|E][r|R][o|O][k|K][u|U].*[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}", # "Heroku_API_Key": r"[h|H][e|E][r|R][o|O][k|K][u|U].*[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}",
# "IP_Address": r"(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])", # "IP_Address": r"(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])",
#"JSON_Web_Token": r"(?i)^((?=.*[a-z])(?=.*[0-9])(?:[a-z0-9_=]+\\.){2}(?:[a-z0-9_\\-\\+\/=]*))$", # "JSON_Web_Token": r"(?i)^((?=.*[a-z])(?=.*[0-9])(?:[a-z0-9_=]+\\.){2}(?:[a-z0-9_\\-\\+\/=]*))$",
# "LinkFinder": r"(?:\"|')(((?:[a-zA-Z]{1,10}:\/\/|\/\/)[^\"'\/]{1,}\\.[a-zA-Z]{2,}[^\"']{0,})|((?:\/|\\.\\.\/|\\.\/)[^\"'><,;| *()(%%$^\/\\\\\\[\\]][^\"'><,;|()]{1,})|([a-zA-Z0-9_\\-\/]{1,}\/[a-zA-Z0-9_\\-\/]{1,}\\.(?:[a-zA-Z]{1,4}|action)(?:[\\?|#][^\"|']{0,}|))|([a-zA-Z0-9_\\-\/]{1,}\/[a-zA-Z0-9_\\-\/]{3,}(?:[\\?|#][^\"|']{0,}|))|([a-zA-Z0-9_\\-]{1,}\\.(?:php|asp|aspx|jsp|json|action|html|js|txt|xml)(?:[\\?|#][^\"|']{0,}|)))(?:\"|')", # "LinkFinder": r"(?:\"|')(((?:[a-zA-Z]{1,10}:\/\/|\/\/)[^\"'\/]{1,}\\.[a-zA-Z]{2,}[^\"']{0,})|((?:\/|\\.\\.\/|\\.\/)[^\"'><,;| *()(%%$^\/\\\\\\[\\]][^\"'><,;|()]{1,})|([a-zA-Z0-9_\\-\/]{1,}\/[a-zA-Z0-9_\\-\/]{1,}\\.(?:[a-zA-Z]{1,4}|action)(?:[\\?|#][^\"|']{0,}|))|([a-zA-Z0-9_\\-\/]{1,}\/[a-zA-Z0-9_\\-\/]{3,}(?:[\\?|#][^\"|']{0,}|))|([a-zA-Z0-9_\\-]{1,}\\.(?:php|asp|aspx|jsp|json|action|html|js|txt|xml)(?:[\\?|#][^\"|']{0,}|)))(?:\"|')",
#"Mac_Address": r"(([0-9A-Fa-f]{2}[:]){5}[0-9A-Fa-f]{2}|([0-9A-Fa-f]{2}[-]){5}[0-9A-Fa-f]{2}|([0-9A-Fa-f]{4}[\\.]){2}[0-9A-Fa-f]{4})$", # "Mac_Address": r"(([0-9A-Fa-f]{2}[:]){5}[0-9A-Fa-f]{2}|([0-9A-Fa-f]{2}[-]){5}[0-9A-Fa-f]{2}|([0-9A-Fa-f]{4}[\\.]){2}[0-9A-Fa-f]{4})$",
#"MailChimp_API_Key": r"[0-9a-f]{32}-us[0-9]{1,2}", # "MailChimp_API_Key": r"[0-9a-f]{32}-us[0-9]{1,2}",
#"Mailgun_API_Key": r"key-[0-9a-zA-Z]{32}", # "Mailgun_API_Key": r"key-[0-9a-zA-Z]{32}",
#"Mailto": r"(?<=mailto:)[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9.-]+", # "Mailto": r"(?<=mailto:)[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9.-]+",
#"Password_in_URL": r"[a-zA-Z]{3,10}://[^/\\s:@]{3,20}:[^/\\s:@]{3,20}@.{1,100}[\"'\\s]", # "Password_in_URL": r"[a-zA-Z]{3,10}://[^/\\s:@]{3,20}:[^/\\s:@]{3,20}@.{1,100}[\"'\\s]",
#"PayPal_Braintree_Access_Token": r"access_token\\$production\\$[0-9a-z]{16}\\$[0-9a-f]{32}", # "PayPal_Braintree_Access_Token": r"access_token\\$production\\$[0-9a-z]{16}\\$[0-9a-f]{32}",
#"PGP_private_key_block": r"-----BEGIN PGP PRIVATE KEY BLOCK-----", # "PGP_private_key_block": r"-----BEGIN PGP PRIVATE KEY BLOCK-----",
#"Picatic_API_Key": r"sk_live_[0-9a-z]{32}", # "Picatic_API_Key": r"sk_live_[0-9a-z]{32}",
#"RSA_Private_Key": r"-----BEGIN RSA PRIVATE KEY-----", # "RSA_Private_Key": r"-----BEGIN RSA PRIVATE KEY-----",
#"Slack_Token": r"(xox[p|b|o|a]-[0-9]{12}-[0-9]{12}-[0-9]{12}-[a-z0-9]{32})", # "Slack_Token": r"(xox[p|b|o|a]-[0-9]{12}-[0-9]{12}-[0-9]{12}-[a-z0-9]{32})",
#"Slack_Webhook": r"https://hooks.slack.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8}/[a-zA-Z0-9_]{24}", # "Slack_Webhook": r"https://hooks.slack.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8}/[a-zA-Z0-9_]{24}",
#"Square_Access_Token": r"sq0atp-[0-9A-Za-z\\-_]{22}", # "Square_Access_Token": r"sq0atp-[0-9A-Za-z\\-_]{22}",
#"Square_OAuth_Secret": r"sq0csp-[0-9A-Za-z\\-_]{43}", # "Square_OAuth_Secret": r"sq0csp-[0-9A-Za-z\\-_]{43}",
#"SSH_DSA_Private_Key": r"-----BEGIN DSA PRIVATE KEY-----", # "SSH_DSA_Private_Key": r"-----BEGIN DSA PRIVATE KEY-----",
#"SSH_EC_Private_Key": r"-----BEGIN EC PRIVATE KEY-----", # "SSH_EC_Private_Key": r"-----BEGIN EC PRIVATE KEY-----",
#"Stripe_API_Key": r"sk_live_[0-9a-zA-Z]{24}", # "Stripe_API_Key": r"sk_live_[0-9a-zA-Z]{24}",
#"Stripe_Restricted_API_Key": r"rk_live_[0-9a-zA-Z]{24}", # "Stripe_Restricted_API_Key": r"rk_live_[0-9a-zA-Z]{24}",
#"TryHackMe_CTF_Flag": r"[t|T](?:[r|R][y|Y][h|H][a|A][c|C][k|K][m|M][e|E]|[h|H][m|M])\\{.*\\}$", # "TryHackMe_CTF_Flag": r"[t|T](?:[r|R][y|Y][h|H][a|A][c|C][k|K][m|M][e|E]|[h|H][m|M])\\{.*\\}$",
#"Twilio_API_Key": r"SK[0-9a-fA-F]{32}", # "Twilio_API_Key": r"SK[0-9a-fA-F]{32}",
#"Twitter_Access_Token": r"[t|T][w|W][i|I][t|T][t|T][e|E][r|R].*[1-9][0-9]+-[0-9a-zA-Z]{40}", # "Twitter_Access_Token": r"[t|T][w|W][i|I][t|T][t|T][e|E][r|R].*[1-9][0-9]+-[0-9a-zA-Z]{40}",
#"Twitter_ClientID": r"[t|T][w|W][i|I][t|T][t|T][e|E][r|R](.{0,20})?['\"][0-9a-z]{18,25}", # "Twitter_ClientID": r"[t|T][w|W][i|I][t|T][t|T][e|E][r|R](.{0,20})?['\"][0-9a-z]{18,25}",
#"Twitter_OAuth": r"[t|T][w|W][i|I][t|T][t|T][e|E][r|R].*['|\"][0-9a-zA-Z]{35,44}['|\"]", # "Twitter_OAuth": r"[t|T][w|W][i|I][t|T][t|T][e|E][r|R].*['|\"][0-9a-zA-Z]{35,44}['|\"]",
#"Twitter_Secret_Key": r"[t|T][w|W][i|I][t|T][t|T][e|E][r|R](.{0,20})?['\"][0-9a-z]{35,44}" # "Twitter_Secret_Key": r"[t|T][w|W][i|I][t|T][t|T][e|E][r|R](.{0,20})?['\"][0-9a-z]{35,44}"
} }
# 此处配置壳信息 # 此处配置壳信息
shell_list =[ shell_list = [
'com.stub.StubApp', 'com.stub.StubApp',
's.h.e.l.l.S', 's.h.e.l.l.S',
'com.Kiwisec.KiwiSecApplication', 'com.Kiwisec.KiwiSecApplication',
@ -150,7 +151,7 @@ apk_permissions = [
] ]
# 此处配置需要扫描的web文件后缀 # 此处配置需要扫描的web文件后缀
web_file_suffix =[ web_file_suffix = [
"html", "html",
"js", "js",
"xml", "xml",
@ -163,7 +164,7 @@ web_file_suffix =[
] ]
# 配置需要忽略网络嗅探的文件后缀名,此处根据具体需求进行配置,默认为不过滤 # 配置需要忽略网络嗅探的文件后缀名,此处根据具体需求进行配置,默认为不过滤
sniffer_filter=[ sniffer_filter = [
"jpg", "jpg",
"png", "png",
"jpeg", "jpeg",
@ -172,8 +173,8 @@ sniffer_filter=[
# 配置自动下载Apk文件或者缓存HTML的请求头信息 # 配置自动下载Apk文件或者缓存HTML的请求头信息
headers = { headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0",
"Connection":"close" "Connection": "close"
} }
# 配置自动下载Apk文件或者缓存HTML的请求体信息 # 配置自动下载Apk文件或者缓存HTML的请求体信息
@ -183,4 +184,3 @@ data = {
# 配置自动下载Apk文件或者缓存HTML的请求方法信息,目前仅支持GET和POST # 配置自动下载Apk文件或者缓存HTML的请求方法信息,目前仅支持GET和POST
method = "GET" method = "GET"

@ -26,7 +26,7 @@ output_path = ""
download_flag = False download_flag = False
# excel 起始行号 # excel 起始行号
excel_row = 0 excel_row = 1
class Bootstrapper(object): class Bootstrapper(object):
@ -78,7 +78,7 @@ class Bootstrapper(object):
apktool_path = os.path.join(tools_dir, "apktool.jar") apktool_path = os.path.join(tools_dir, "apktool.jar")
download_path = os.path.join(out_dir,"download") download_path = os.path.join(out_dir,"download")
txt_result_path = os.path.join(out_dir,"result_"+str(create_time)+".txt") txt_result_path = os.path.join(out_dir,"result_"+str(create_time)+".txt")
xls_result_path = os.path.join(out_dir,"result_"+str(create_time)+".xls") xls_result_path = os.path.join(out_dir,"result_"+str(create_time)+".xlsx")
app_history_path = os.path.join(history_path,"app_history.txt") app_history_path = os.path.join(history_path,"app_history.txt")
domain_history_path = os.path.join(history_path,"domain_history.txt") domain_history_path = os.path.join(history_path,"domain_history.txt")
@ -100,7 +100,6 @@ class Bootstrapper(object):
print("[*] Create directory {}".format(output_path)) print("[*] Create directory {}".format(output_path))
if not os.path.exists(download_path): if not os.path.exists(download_path):
# shutil.rmtree(download_path)
os.makedirs(download_path) os.makedirs(download_path)
print("[*] Create directory {}".format(download_path)) print("[*] Create directory {}".format(download_path))

@ -2,10 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Author: kelvinBen # Author: kelvinBen
# Github: https://github.com/kelvinBen/AppInfoScanner # Github: https://github.com/kelvinBen/AppInfoScanner
import re
import os
import sys import sys
import time
import config import config
import requests import requests
import threading import threading
@ -13,9 +10,10 @@ import libs.core as cores
from requests.packages import urllib3 from requests.packages import urllib3
from requests.adapters import HTTPAdapter from requests.adapters import HTTPAdapter
class DownloadThreads(threading.Thread): class DownloadThreads(threading.Thread):
def __init__(self,input_path,file_name,cache_path,types): def __init__(self, input_path, file_name, cache_path, types):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.url = input_path self.url = input_path
self.types = types self.types = types
@ -27,23 +25,24 @@ class DownloadThreads(threading.Thread):
session = requests.Session() session = requests.Session()
session.mount('http://', HTTPAdapter(max_retries=3)) session.mount('http://', HTTPAdapter(max_retries=3))
session.mount('https://', HTTPAdapter(max_retries=3)) session.mount('https://', HTTPAdapter(max_retries=3))
session.keep_alive =False session.keep_alive = False
session.adapters.DEFAULT_RETRIES = 5 session.adapters.DEFAULT_RETRIES = 5
urllib3.disable_warnings() urllib3.disable_warnings()
if config.method.upper() == "POST": if config.method.upper() == "POST":
resp = session.post(url=self.url,params=config.data ,headers=config.headers,timeout=30) resp = session.post(
url=self.url, params=config.data, headers=config.headers, timeout=30)
else: else:
resp = session.get(url=self.url,data=config.data ,headers=config.headers,timeout=30) resp = session.get(url=self.url, data=config.data,
headers=config.headers, timeout=30)
if resp.status_code == requests.codes.ok: if resp.status_code == requests.codes.ok:
if self.types == "Android" or self.types == "iOS": if self.types == "Android" or self.types == "iOS":
count = 0 count = 0
progress_tmp = 0 progress_tmp = 0
time1 = time.time()
length = float(resp.headers['content-length']) length = float(resp.headers['content-length'])
with open(self.cache_path, "wb") as f: with open(self.cache_path, "wb") as f:
for chunk in resp.iter_content(chunk_size = 512): for chunk in resp.iter_content(chunk_size=512):
if chunk: if chunk:
f.write(chunk) f.write(chunk)
count += len(chunk) count += len(chunk)
@ -51,18 +50,18 @@ class DownloadThreads(threading.Thread):
if progress != progress_tmp: if progress != progress_tmp:
progress_tmp = progress progress_tmp = progress
print("\r", end="") print("\r", end="")
print("[*] Download progress: {}%: ".format(progress), "" * (progress // 2), end="") print(
"[*] Download progress: {}%: ".format(progress), "" * (progress // 2), end="")
sys.stdout.flush() sys.stdout.flush()
f.close() f.close()
else: else:
html = resp.text html = resp.text
with open(self.cache_path,"w",encoding='utf-8',errors='ignore') as f: with open(self.cache_path, "w", encoding='utf-8', errors='ignore') as f:
f.write(html) f.write(html)
f.close() f.close()
cores.download_flag = True cores.download_flag = True
except Exception as e: except Exception as e:
raise Exception(e) raise Exception(e)
return
def run(self): def run(self):
threadLock = threading.Lock() threadLock = threading.Lock()

@ -10,7 +10,7 @@ import libs.core as cores
class NetThreads(threading.Thread): class NetThreads(threading.Thread):
def __init__(self,threadID,name,domain_queue,worksheet): def __init__(self, threadID, name, domain_queue, worksheet):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.name = name self.name = name
self.threadID = threadID self.threadID = threadID
@ -18,7 +18,7 @@ class NetThreads(threading.Thread):
self.domain_queue = domain_queue self.domain_queue = domain_queue
self.worksheet = worksheet self.worksheet = worksheet
def __get_Http_info__(self,threadLock): def __get_Http_info__(self, threadLock):
while True: while True:
if self.domain_queue.empty(): if self.domain_queue.empty():
break break
@ -31,23 +31,33 @@ class NetThreads(threading.Thread):
if result != "error": if result != "error":
if self.lock.acquire(True): if self.lock.acquire(True):
cores.excel_row = cores.excel_row + 1 cores.excel_row = cores.excel_row + 1
self.worksheet.write(cores.excel_row, 0, label = cores.excel_row) self.worksheet.cell(row=cores.excel_row,
self.worksheet.write(cores.excel_row, 1, label = url_ip) column=1, value=cores.excel_row-1)
self.worksheet.write(cores.excel_row, 2, label = domain) self.worksheet.cell(row=cores.excel_row,
column=2, value=url_ip)
self.worksheet.cell(row=cores.excel_row,
column=3, value=domain)
if result != "timeout": if result != "timeout":
self.worksheet.write(cores.excel_row, 3, label = result["status"]) self.worksheet.cell(
self.worksheet.write(cores.excel_row, 4, label = result["des_ip"]) row=cores.excel_row, column=4, value=result["status"])
self.worksheet.write(cores.excel_row, 5, label = result["server"]) self.worksheet.cell(
self.worksheet.write(cores.excel_row, 6, label = result["title"]) row=cores.excel_row, column=5, value=result["des_ip"])
self.worksheet.write(cores.excel_row, 7, label = result["cdn"]) self.worksheet.cell(
# self.worksheet.write(cores.excel_row, 8, label = "") row=cores.excel_row, column=6, value=result["server"])
self.worksheet.cell(
row=cores.excel_row, column=7, value=result["title"])
self.worksheet.cell(
row=cores.excel_row, column=8, value=result["cdn"])
self.lock.release() self.lock.release()
def __get_request_result__(self,url): def __get_request_result__(self, url):
result={"status":"","server":"","cookie":"","cdn":"","des_ip":"","sou_ip":"","title":""} result = {"status": "", "server": "", "cookie": "",
"cdn": "", "des_ip": "", "sou_ip": "", "title": ""}
cdn = "" cdn = ""
try: try:
with requests.get(url, timeout=5,stream=True) as rsp: with requests.get(url, timeout=5, stream=True) as rsp:
status_code = rsp.status_code status_code = rsp.status_code
result["status"] = status_code result["status"] = status_code
headers = rsp.headers headers = rsp.headers
@ -71,7 +81,7 @@ class NetThreads(threading.Thread):
result["sou_ip"] = sou_ip result["sou_ip"] = sou_ip
sock.close() sock.close()
html = rsp.text html = rsp.text
title = re.findall('<title>(.+)</title>',html) title = re.findall('<title>(.+)</title>', html)
if title: if title:
result["title"] = title[0] result["title"] = title[0]
rsp.close() rsp.close()

@ -11,13 +11,13 @@ import libs.core as cores
class ParsesThreads(threading.Thread): class ParsesThreads(threading.Thread):
def __init__(self,threadID,name,file_queue,result_dict,types): def __init__(self, threadID, name, file_queue, result_dict, types):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.file_queue = file_queue self.file_queue = file_queue
self.name = name self.name = name
self.threadID = threadID self.threadID = threadID
self.result_list = [] self.result_list = []
self.result_dict=result_dict self.result_dict = result_dict
self.types = types self.types = types
def __regular_parse__(self): def __regular_parse__(self):
@ -25,7 +25,7 @@ class ParsesThreads(threading.Thread):
if self.file_queue.empty(): if self.file_queue.empty():
break break
file_path = self.file_queue.get(timeout = 5) file_path = self.file_queue.get(timeout=5)
scan_str = ("[+] Scan file : %s" % file_path) scan_str = ("[+] Scan file : %s" % file_path)
if self.types == "iOS": if self.types == "iOS":
self.__get_string_by_iOS__(file_path) self.__get_string_by_iOS__(file_path)
@ -36,19 +36,20 @@ class ParsesThreads(threading.Thread):
if len(result_set) != 0: if len(result_set) != 0:
self.result_dict[file_path] = result_set self.result_dict[file_path] = result_set
def __get_string_by_iOS__(self,file_path): def __get_string_by_iOS__(self, file_path):
output_path = cores.output_path output_path = cores.output_path
strings_path = cores.strings_path strings_path = cores.strings_path
temp = os.path.join(output_path,"temp.txt") temp = os.path.join(output_path, "temp.txt")
cmd_str = ('"%s" "%s" > "%s"') % (str(strings_path),str(file_path),str(temp)) cmd_str = ('"%s" "%s" > "%s"') % (
str(strings_path), str(file_path), str(temp))
if os.system(cmd_str) == 0: if os.system(cmd_str) == 0:
with open(temp,"r",encoding='utf-8',errors='ignore') as f: with open(temp, "r", encoding='utf-8', errors='ignore') as f:
lines = f.readlines() lines = f.readlines()
for line in lines: for line in lines:
self.__parse_string__(line) self.__parse_string__(line)
def __get_string_by_file__(self,file_path): def __get_string_by_file__(self, file_path):
with open(file_path,"r",encoding="utf8",errors='ignore') as f : with open(file_path, "r", encoding="utf8", errors='ignore') as f:
file_content = f.read() file_content = f.read()
# 获取到所有的字符串 # 获取到所有的字符串
pattern = re.compile(r'\"(.*?)\"') pattern = re.compile(r'\"(.*?)\"')
@ -56,8 +57,10 @@ class ParsesThreads(threading.Thread):
# 搜素AK和SK信息,由于iOS的逻辑处理效率过慢暂时忽略对iOS的AK检测 # 搜素AK和SK信息,由于iOS的逻辑处理效率过慢暂时忽略对iOS的AK检测
if not (".js" == file_path[-3:] and self.types == "iOS"): if not (".js" == file_path[-3:] and self.types == "iOS"):
for key,values in config.filter_ak_map.items(): # 未包含相关字段不进行ak或者sk信息采集
if isinstance(values,list): if "access" in file_content or "secret" in file_content:
for key, values in config.filter_ak_map.items():
if isinstance(values, list):
for value in values: for value in values:
self.__ak_and_sk__(key, value, file_content) self.__ak_and_sk__(key, value, file_content)
else: else:
@ -65,22 +68,24 @@ class ParsesThreads(threading.Thread):
# 遍历所有的字符串 # 遍历所有的字符串
for result in set(results): for result in set(results):
if ("http://" == result) or ("https://" == result) or result.startswith("https://.") or result.startswith("http://.") :
continue
self.__parse_string__(result) self.__parse_string__(result)
def __ak_and_sk__(self, name, ak_rule,content): def __ak_and_sk__(self, name, ak_rule, content):
akAndSkList = re.compile(ak_rule).findall(content) akAndSkList = re.compile(ak_rule).findall(content)
for akAndSk in akAndSkList: for akAndSk in akAndSkList:
ak = ("[%s]-->:%s") % (name,akAndSk.strip()) ak = ("[%s]-->:%s") % (name, akAndSk.strip())
self.result_list.append(ak) self.result_list.append(ak)
print(("[+] [%s] AK or SK in %s:") % (name, akAndSk.strip())) print(("[+] [%s] AK or SK in %s:") % (name, akAndSk.strip()))
def __parse_string__(self,result): def __parse_string__(self, result):
# 通过正则筛选需要过滤的字符串 # 通过正则筛选需要过滤的字符串
for filter_str in config.filter_strs: for filter_str in config.filter_strs:
filter_str_pat = re.compile(filter_str) filter_str_pat = re.compile(filter_str)
filter_resl = filter_str_pat.findall(result) filter_resl = filter_str_pat.findall(result)
# 过滤掉未搜索到的内容 # 过滤掉未搜索到的内容
if len(filter_resl)!=0: if len(filter_resl) != 0:
# 提取第一个结果 # 提取第一个结果
resl_str = filter_resl[0] resl_str = filter_resl[0]
# 过滤 # 过滤
@ -89,27 +94,30 @@ class ParsesThreads(threading.Thread):
self.threadLock.acquire() self.threadLock.acquire()
if cores.all_flag: if cores.all_flag:
print(("[+] The string searched for matching rule is: %s") % (resl_str)) print(
("[+] The string searched for matching rule is: %s") % (resl_str))
self.result_list.append(resl_str) self.result_list.append(resl_str)
self.threadLock.release() self.threadLock.release()
continue continue
def __filter__(self,resl_str): def __filter__(self, resl_str):
return_flag = 1 return_flag = 1
resl_str = resl_str.replace("\r","").replace("\n","").replace(" ","") resl_str = resl_str.replace("\r", "").replace(
"\n", "").replace(" ", "")
if len(resl_str) == 0: if len(resl_str) == 0:
return 0 return 0
for filte in set(config.filter_no): for filte in set(config.filter_no):
resl_str = resl_str.replace(filte,"") resl_str = resl_str.replace(filte, "")
if len(resl_str) == 0: if len(resl_str) == 0:
return_flag = 0 return_flag = 0
continue continue
if re.match(filte,resl_str): if re.match(filte, resl_str):
return_flag = 0 return_flag = 0
continue continue
return return_flag return return_flag
def run(self): def run(self):

@ -12,19 +12,19 @@ import libs.core as cores
class AndroidTask(object): class AndroidTask(object):
def __init__(self,path,package): def __init__(self, path, package):
self.path = path self.path = path
self.package = package self.package = package
self.file_queue = Queue() self.file_queue = Queue()
self.shell_flag=False self.shell_flag = False
self.packagename="" self.packagename = ""
self.comp_list=[] self.comp_list = []
self.file_identifier=[] self.file_identifier = []
self.permissions = [] self.permissions = []
def start(self): def start(self):
# 检查java环境是否存在 # 检查java环境是否存在
if os.system("java -version") !=0 : if os.system("java -version") != 0:
raise Exception("Please install the Java environment!") raise Exception("Please install the Java environment!")
input_file_path = self.path input_file_path = self.path
@ -33,23 +33,24 @@ class AndroidTask(object):
self.__decode_dir__(input_file_path) self.__decode_dir__(input_file_path)
else: else:
if self.__decode_file__(input_file_path) == "error": if self.__decode_file__(input_file_path) == "error":
raise Exception("Retrieval of this file type is not supported. Select APK file or DEX file.") raise Exception(
"Retrieval of this file type is not supported. Select APK file or DEX file.")
return {"comp_list":self.comp_list,"shell_flag":self.shell_flag,"file_queue":self.file_queue,"packagename":self.packagename,"file_identifier":self.file_identifier,"permissions":self.permissions} return {"comp_list": self.comp_list, "shell_flag": self.shell_flag, "file_queue": self.file_queue, "packagename": self.packagename, "file_identifier": self.file_identifier, "permissions": self.permissions}
def __decode_file__(self,file_path): def __decode_file__(self, file_path):
apktool_path = str(cores.apktool_path) apktool_path = str(cores.apktool_path)
backsmali_path = str(cores.backsmali_path) backsmali_path = str(cores.backsmali_path)
base_out_path = str(cores.output_path) base_out_path = str(cores.output_path)
filename = os.path.basename(file_path) filename = os.path.basename(file_path)
suffix_name = filename.split(".")[-1] suffix_name = filename.split(".")[-1]
if suffix_name == "apk": if suffix_name == "apk" or suffix_name == "hpk":
name = filename.split(".")[0] name = filename.split(".")[0]
output_path = os.path.join(base_out_path,name) output_path = os.path.join(base_out_path, name)
self.__decode_apk__(file_path,apktool_path,output_path) self.__decode_apk__(file_path, apktool_path, output_path)
elif suffix_name == "dex": elif suffix_name == "dex":
f = open(file_path,'rb') f = open(file_path, 'rb')
md5_obj = hashlib.md5() md5_obj = hashlib.md5()
while True: while True:
r = f.read(1024) r = f.read(1024)
@ -58,17 +59,17 @@ class AndroidTask(object):
md5_obj.update(r) md5_obj.update(r)
dex_md5 = md5_obj.hexdigest().lower() dex_md5 = md5_obj.hexdigest().lower()
self.file_identifier.append(dex_md5) self.file_identifier.append(dex_md5)
output_path = os.path.join(base_out_path,dex_md5) output_path = os.path.join(base_out_path, dex_md5)
if not os.path.exists(output_path): if not os.path.exists(output_path):
os.makedirs(output_path) os.makedirs(output_path)
self.__decode_dex__(file_path,backsmali_path,output_path) self.__decode_dex__(file_path, backsmali_path, output_path)
else: else:
return "error" return "error"
def __decode_dir__(self,root_dir): def __decode_dir__(self, root_dir):
dir_or_files = os.listdir(root_dir) dir_or_files = os.listdir(root_dir)
for dir_or_file in dir_or_files: for dir_or_file in dir_or_files:
dir_or_file_path = os.path.join(root_dir,dir_or_file) dir_or_file_path = os.path.join(root_dir, dir_or_file)
if os.path.isdir(dir_or_file_path): if os.path.isdir(dir_or_file_path):
self.__decode_dir__(dir_or_file_path) self.__decode_dir__(dir_or_file_path)
else: else:
@ -76,8 +77,9 @@ class AndroidTask(object):
continue continue
# 分解apk # 分解apk
def __decode_apk__(self,file_path,apktool_path,output_path): def __decode_apk__(self, file_path, apktool_path, output_path):
cmd_str = ('java -jar "%s" d -f "%s" -o "%s" --only-main-classe') % (str(apktool_path),str(file_path),str(output_path)) cmd_str = ('java -jar "%s" d -f "%s" -o "%s" --only-main-classe') % (
str(apktool_path), str(file_path), str(output_path))
if os.system(cmd_str) == 0: if os.system(cmd_str) == 0:
self.__shell_test__(output_path) self.__shell_test__(output_path)
self.__scanner_file_by_apktool__(output_path) self.__scanner_file_by_apktool__(output_path)
@ -85,63 +87,62 @@ class AndroidTask(object):
print("[-] Decompilation failed, please submit error information at https://github.com/kelvinBen/AppInfoScanner/issues") print("[-] Decompilation failed, please submit error information at https://github.com/kelvinBen/AppInfoScanner/issues")
raise Exception(file_path + ", Decompilation failed.") raise Exception(file_path + ", Decompilation failed.")
# 分解dex # 分解dex
def __decode_dex__(self,file_path,backsmali_path,output_path): def __decode_dex__(self, file_path, backsmali_path, output_path):
cmd_str = ('java -jar "%s" d "%s"') % (str(backsmali_path),str(file_path)) cmd_str = ('java -jar "%s" d "%s"') % (str(backsmali_path),
str(file_path))
if os.system(cmd_str) == 0: if os.system(cmd_str) == 0:
self.__get_scanner_file__(output_path) self.__get_scanner_file__(output_path)
else: else:
print("[-] Decompilation failed, please submit error information at https://github.com/kelvinBen/AppInfoScanner/issues") print("[-] Decompilation failed, please submit error information at https://github.com/kelvinBen/AppInfoScanner/issues")
raise Exception(file_path + ", Decompilation failed.") raise Exception(file_path + ", Decompilation failed.")
# 初始化检测文件信息 # 初始化检测文件信息
def __scanner_file_by_apktool__(self,output_path): def __scanner_file_by_apktool__(self, output_path):
file_names = os.listdir(output_path) file_names = os.listdir(output_path)
for file_name in file_names: for file_name in file_names:
file_path = os.path.join(output_path,file_name) file_path = os.path.join(output_path, file_name)
if not os.path.isdir(file_path): if not os.path.isdir(file_path):
continue continue
if "smali" in file_name or "assets" in file_name: if "smali" in file_name or "assets" in file_name:
scanner_file_suffixs = ["smali","js","xml"] scanner_file_suffixs = ["smali", "js", "xml"]
if cores.resource_flag: if cores.resource_flag:
scanner_file_suffixs =["smali"] scanner_file_suffixs = ["smali"]
self.__get_scanner_file__(file_path,scanner_file_suffixs) self.__get_scanner_file__(file_path, scanner_file_suffixs)
def __get_scanner_file__(self,scanner_dir,scanner_file_suffixs=["smali"]): def __get_scanner_file__(self, scanner_dir, scanner_file_suffixs=["smali"]):
dir_or_files = os.listdir(scanner_dir) dir_or_files = os.listdir(scanner_dir)
for dir_or_file in dir_or_files: for dir_or_file in dir_or_files:
dir_file_path = os.path.join(scanner_dir,dir_or_file) dir_file_path = os.path.join(scanner_dir, dir_or_file)
if os.path.isdir(dir_file_path): if os.path.isdir(dir_file_path):
self.__get_scanner_file__(dir_file_path,scanner_file_suffixs) self.__get_scanner_file__(dir_file_path, scanner_file_suffixs)
else: else:
if ("." not in dir_or_file) or (len(dir_or_file.split(".")) < 1) or (dir_or_file.split(".")[-1] not in scanner_file_suffixs): if ("." not in dir_or_file) or (len(dir_or_file.split(".")) < 1) or (dir_or_file.split(".")[-1] not in scanner_file_suffixs):
continue continue
self.file_queue.put(dir_file_path) self.file_queue.put(dir_file_path)
for component in config.filter_components: for component in config.filter_components:
comp = component.replace(".","/") comp = component.replace(".", "/")
if(comp in dir_file_path): if(comp in dir_file_path):
if(component not in self.comp_list): if(component not in self.comp_list):
self.comp_list.append(component) self.comp_list.append(component)
def __shell_test__(self,output): def __shell_test__(self, output):
am_path = os.path.join(output,"AndroidManifest.xml") am_path = os.path.join(output, "AndroidManifest.xml")
with open(am_path,"r",encoding='utf-8',errors='ignore') as f: with open(am_path, "r", encoding='utf-8', errors='ignore') as f:
am_str = f.read() am_str = f.read()
am_package= re.compile(r'<manifest.*package=\"(.*?)\".*') am_package = re.compile(r'<manifest.*package=\"(.*?)\".*')
apackage = am_package.findall(am_str) apackage = am_package.findall(am_str)
if len(apackage) >=1: if len(apackage) >= 1:
self.packagename = apackage[0] self.packagename = apackage[0]
self.file_identifier.append(apackage[0]) self.file_identifier.append(apackage[0])
am_name = re.compile(r'<application.*android:name=\"(.*?)\".*>') am_name = re.compile(r'<application.*android:name=\"(.*?)\".*>')
aname = am_name.findall(am_str) aname = am_name.findall(am_str)
if aname and len(aname)>=1: if aname and len(aname) >= 1:
if aname[0] in config.shell_list: if aname[0] in config.shell_list:
self.shell_flag = True self.shell_flag = True

@ -3,9 +3,7 @@
# Author: kelvinBen # Author: kelvinBen
# Github: https://github.com/kelvinBen/AppInfoScanner # Github: https://github.com/kelvinBen/AppInfoScanner
import os import os
import re
import config import config
import threading
from queue import Queue from queue import Queue
import libs.core as cores import libs.core as cores
from libs.task.ios_task import iOSTask from libs.task.ios_task import iOSTask
@ -15,12 +13,14 @@ from libs.core.parses import ParsesThreads
from libs.task.android_task import AndroidTask from libs.task.android_task import AndroidTask
from libs.task.download_task import DownloadTask from libs.task.download_task import DownloadTask
class BaseTask(object): class BaseTask(object):
thread_list =[] thread_list = []
result_dict = {} result_dict = {}
app_history_list=[] app_history_list = []
domain_history_list=[] domain_history_list = []
# 统一初始化入口 # 统一初始化入口
def __init__(self, types="Android", inputs="", rules="", sniffer=True, threads=10, package=""): def __init__(self, types="Android", inputs="", rules="", sniffer=True, threads=10, package=""):
self.types = types self.types = types
self.path = inputs self.path = inputs
@ -31,8 +31,8 @@ class BaseTask(object):
self.package = package self.package = package
self.file_queue = Queue() self.file_queue = Queue()
# 统一调度平台 # 统一调度平台
def start(self): def start(self):
print("[*] AI is analyzing filtering rules......") print("[*] AI is analyzing filtering rules......")
@ -40,7 +40,8 @@ class BaseTask(object):
# 获取历史记录 # 获取历史记录
self.__history_handle__() self.__history_handle__()
print("[*] The filtering rules obtained by AI are as follows: %s" % (set(config.filter_no)) ) print("[*] The filtering rules obtained by AI are as follows: %s" %
(set(config.filter_no)))
# 任务控制中心 # 任务控制中心
task_info = self.__tast_control__() task_info = self.__tast_control__()
@ -59,7 +60,8 @@ class BaseTask(object):
return return
# 线程控制中心 # 线程控制中心
print("[*] ========= Searching for strings that match the rules ===============") print(
"[*] ========= Searching for strings that match the rules ===============")
self.__threads_control__(file_queue) self.__threads_control__(file_queue)
# 等待线程结束 # 等待线程结束
@ -67,23 +69,24 @@ class BaseTask(object):
thread.join() thread.join()
# 结果输出中心 # 结果输出中心
self.__print_control__(packagename,comp_list,file_identifier,permissions) self.__print_control__(packagename, comp_list,
file_identifier, permissions)
def __tast_control__(self): def __tast_control__(self):
task_info = {} task_info = {}
# 自动根据文件后缀名称进行修正 # 自动根据文件后缀名称进行修正
cache_info = DownloadTask().start(self.path,self.types) cache_info = DownloadTask().start(self.path, self.types)
cacar_path = cache_info["path"] cacar_path = cache_info["path"]
types = cache_info["type"] types = cache_info["type"]
if (not os.path.exists(cacar_path) and cores.download_flag): if (not os.path.exists(cacar_path) and cores.download_flag):
print("[-] File download failed! Please download the file manually and try again.") print(
"[-] File download failed! Please download the file manually and try again.")
return task_info return task_info
# 调用Android 相关处理逻辑 # 调用Android 相关处理逻辑
if types == "Android": if types == "Android":
task_info = AndroidTask(cacar_path,self.package).start() task_info = AndroidTask(cacar_path, self.package).start()
# 调用iOS 相关处理逻辑 # 调用iOS 相关处理逻辑
elif types == "iOS": elif types == "iOS":
task_info = iOSTask(cacar_path).start() task_info = iOSTask(cacar_path).start()
@ -92,21 +95,24 @@ class BaseTask(object):
task_info = WebTask(cacar_path).start() task_info = WebTask(cacar_path).start()
return task_info return task_info
def __threads_control__(self,file_queue): def __threads_control__(self, file_queue):
for threadID in range(1,self.threads): for threadID in range(1, self.threads):
name = "Thread - " + str(int(threadID)) name = "Thread - " + str(int(threadID))
thread = ParsesThreads(threadID,name,file_queue,self.result_dict,self.types) thread = ParsesThreads(
threadID, name, file_queue, self.result_dict, self.types)
thread.start() thread.start()
self.thread_list.append(thread) self.thread_list.append(thread)
def __print_control__(self,packagename,comp_list,file_identifier,permissions): def __print_control__(self, packagename, comp_list, file_identifier, permissions):
txt_result_path = cores.txt_result_path txt_result_path = cores.txt_result_path
xls_result_path = cores.xls_result_path xls_result_path = cores.xls_result_path
all_flag = cores.all_flag all_flag = cores.all_flag
if self.sniffer: if self.sniffer:
print("[*] ========= Sniffing the URL address of the search ===============") print(
NetTask(self.result_dict,self.app_history_list,self.domain_history_list,file_identifier,self.threads).start() "[*] ========= Sniffing the URL address of the search ===============")
NetTask(self.result_dict, self.app_history_list,
self.domain_history_list, file_identifier, self.threads).start()
if packagename: if packagename:
print("[*] ========= The package name of this APP is: ===============") print("[*] ========= The package name of this APP is: ===============")
@ -118,14 +124,15 @@ class BaseTask(object):
print(json) print(json)
if len(permissions) != 0: if len(permissions) != 0:
print("[*] ========= Sensitive permission information is as follows: ===============") print(
"[*] ========= Sensitive permission information is as follows: ===============")
for permission in permissions: for permission in permissions:
print(permission) print(permission)
if all_flag: if all_flag:
value_list = [] value_list = []
with open(txt_result_path,"a+",encoding='utf-8',errors='ignore') as f: with open(txt_result_path, "a+", encoding='utf-8', errors='ignore') as f:
for key,value in self.result_dict.items(): for key, value in self.result_dict.items():
f.write(key+"\r") f.write(key+"\r")
for result in value: for result in value:
if result in value_list: if result in value_list:
@ -133,10 +140,12 @@ class BaseTask(object):
value_list.append(result) value_list.append(result)
f.write("\t"+result+"\r") f.write("\t"+result+"\r")
f.close() f.close()
print("[*] For more information about the search, see TXT file result: %s" %(txt_result_path)) print("[*] For more information about the search, see TXT file result: %s" %
(txt_result_path))
if self.sniffer: if self.sniffer:
print("[*] For more information about the search, see XLS file result: %s" %(xls_result_path)) print("[*] For more information about the search, see XLSX file result: %s" %
(xls_result_path))
def __history_handle__(self): def __history_handle__(self):
domain_history_path = cores.domain_history_path domain_history_path = cores.domain_history_path
@ -144,25 +153,24 @@ class BaseTask(object):
if os.path.exists(domain_history_path): if os.path.exists(domain_history_path):
domain_counts = {} domain_counts = {}
app_size = 0 app_size = 0
with open(app_history_path,"r",encoding='utf-8',errors='ignore') as f: with open(app_history_path, "r", encoding='utf-8', errors='ignore') as f:
lines = f.readlines() lines = f.readlines()
app_size = len(lines) app_size = len(lines)
for line in lines: for line in lines:
self.app_history_list.append(line.replace("\r","").replace("\n","")) self.app_history_list.append(
line.replace("\r", "").replace("\n", ""))
f.close() f.close()
with open(domain_history_path,"r",encoding='utf-8',errors='ignore') as f: with open(domain_history_path, "r", encoding='utf-8', errors='ignore') as f:
lines = f.readlines() lines = f.readlines()
cout = 3 cout = 3
if (app_size>3) and (app_size%3==0): if (app_size > 3) and (app_size % 3 == 0):
cout = cout + 1 cout = cout + 1
for line in lines: for line in lines:
domain = line.replace("\r","").replace("\n","") domain = line.replace("\r", "").replace("\n", "")
self.domain_history_list.append(domain) self.domain_history_list.append(domain)
domain_count = lines.count(line) domain_count = lines.count(line)
if domain_count >= cout: if domain_count >= cout:
config.filter_no.append(".*" + domain) config.filter_no.append(".*" + domain)
f.close() f.close()

@ -11,20 +11,21 @@ from queue import Queue
import libs.core as cores import libs.core as cores
from libs.core.download import DownloadThreads from libs.core.download import DownloadThreads
class DownloadTask(object): class DownloadTask(object):
def start(self,path,types): def start(self, path, types):
create_time = time.strftime("%Y%m%d%H%M%S", time.localtime()) create_time = time.strftime("%Y%m%d%H%M%S", time.localtime())
if path.endswith("apk"): if path.endswith("apk"):
types = "Android" types = "Android"
file_name = create_time+ ".apk" file_name = create_time + ".apk"
elif path.endswith("ipa"): elif path.endswith("ipa"):
types = "iOS" types = "iOS"
file_name = create_time + ".ipa" file_name = create_time + ".ipa"
else: else:
if types == "Android": if types == "Android":
types = "Android" types = "Android"
file_name = create_time+ ".apk" file_name = create_time + ".apk"
elif types == "iOS": elif types == "iOS":
types = "iOS" types = "iOS"
file_name = create_time + ".ipa" file_name = create_time + ".ipa"
@ -33,14 +34,15 @@ class DownloadTask(object):
file_name = create_time + ".html" file_name = create_time + ".html"
if not(path.startswith("http://") or path.startswith("https://")): if not(path.startswith("http://") or path.startswith("https://")):
if not os.path.isdir(path): # 不是目录 if not os.path.isdir(path): # 不是目录
return {"path":path,"type":types} return {"path": path, "type": types}
else: # 目录处理 else: # 目录处理
return {"path":path,"type":types} return {"path": path, "type": types}
else: else:
print("[*] Detected that the task is not local, preparing to download file......") print(
"[*] Detected that the task is not local, preparing to download file......")
cache_path = os.path.join(cores.download_path, file_name) cache_path = os.path.join(cores.download_path, file_name)
thread = DownloadThreads(path,file_name,cache_path,types) thread = DownloadThreads(path, file_name, cache_path, types)
thread.start() thread.start()
thread.join() thread.join()
print() print()
return {"path":cache_path,"type":types} return {"path": cache_path, "type": types}

@ -11,13 +11,15 @@ import platform
import libs.core as cores import libs.core as cores
from queue import Queue from queue import Queue
class iOSTask(object): class iOSTask(object):
elf_file_name = "" elf_file_name = ""
def __init__(self,path):
def __init__(self, path):
self.path = path self.path = path
self.file_queue = Queue() self.file_queue = Queue()
self.shell_flag = False self.shell_flag = False
self.file_identifier= [] self.file_identifier = []
self.permissions = [] self.permissions = []
def start(self): def start(self):
@ -28,50 +30,52 @@ class iOSTask(object):
elif self.__get_file_header__(file_path): elif self.__get_file_header__(file_path):
self.file_queue.put(file_path) self.file_queue.put(file_path)
else: else:
raise Exception("Retrieval of this file type is not supported. Select IPA file or Mach-o file.") raise Exception(
return {"shell_flag":self.shell_flag,"file_queue":self.file_queue,"comp_list":[],"packagename":None,"file_identifier":self.file_identifier,"permissions":self.permissions} "Retrieval of this file type is not supported. Select IPA file or Mach-o file.")
return {"shell_flag": self.shell_flag, "file_queue": self.file_queue, "comp_list": [], "packagename": None, "file_identifier": self.file_identifier, "permissions": self.permissions}
def __get_file_header__(self,file_path): def __get_file_header__(self, file_path):
hex_hand = 0x0 hex_hand = 0x0
macho_name = os.path.split(file_path)[-1] macho_name = os.path.split(file_path)[-1]
self.file_identifier.append(macho_name) self.file_identifier.append(macho_name)
with open(file_path,"rb") as macho_file: with open(file_path, "rb") as macho_file:
macho_file.seek(hex_hand,0) macho_file.seek(hex_hand, 0)
magic = binascii.hexlify(macho_file.read(4)).decode().upper() magic = binascii.hexlify(macho_file.read(4)).decode().upper()
macho_magics = ["CFFAEDFE","CEFAEDFE","BEBAFECA","CAFEBABE"] macho_magics = ["CFFAEDFE", "CEFAEDFE", "BEBAFECA", "CAFEBABE"]
if magic in macho_magics: if magic in macho_magics:
self.__shell_test__(macho_file,hex_hand) self.__shell_test__(macho_file, hex_hand)
macho_file.close() macho_file.close()
return True return True
macho_file.close() macho_file.close()
return False return False
def __shell_test__(self, macho_file, hex_hand):
def __shell_test__(self,macho_file,hex_hand):
while True: while True:
magic = binascii.hexlify(macho_file.read(4)).decode().upper() magic = binascii.hexlify(macho_file.read(4)).decode().upper()
if magic == "2C000000": if magic == "2C000000":
macho_file.seek(hex_hand,0) macho_file.seek(hex_hand, 0)
encryption_info_command = binascii.hexlify(macho_file.read(24)).decode() encryption_info_command = binascii.hexlify(
cryptid = encryption_info_command[-8:len(encryption_info_command)] macho_file.read(24)).decode()
cryptid = encryption_info_command[-8:len(
encryption_info_command)]
if cryptid == "01000000": if cryptid == "01000000":
self.shell_flag = True self.shell_flag = True
break break
hex_hand = hex_hand + 4 hex_hand = hex_hand + 4
def __scanner_file_by_ipa__(self,output): def __scanner_file_by_ipa__(self, output):
scanner_file_suffix = ["plist","js","xml","html"] scanner_file_suffix = ["plist", "js", "xml", "html"]
scanner_dir = os.path.join(output,"Payload") scanner_dir = os.path.join(output, "Payload")
self.__get_scanner_file__(scanner_dir,scanner_file_suffix) self.__get_scanner_file__(scanner_dir, scanner_file_suffix)
def __get_scanner_file__(self,scanner_dir,file_suffix): def __get_scanner_file__(self, scanner_dir, file_suffix):
dir_or_files = os.listdir(scanner_dir) dir_or_files = os.listdir(scanner_dir)
for dir_file in dir_or_files: for dir_file in dir_or_files:
dir_file_path = os.path.join(scanner_dir,dir_file) dir_file_path = os.path.join(scanner_dir, dir_file)
if os.path.isdir(dir_file_path): if os.path.isdir(dir_file_path):
if dir_file.endswith(".app"): if dir_file.endswith(".app"):
self.elf_file_name = dir_file.replace(".app","") self.elf_file_name = dir_file.replace(".app", "")
self.__get_scanner_file__(dir_file_path,file_suffix) self.__get_scanner_file__(dir_file_path, file_suffix)
else: else:
if self.elf_file_name == dir_file: if self.elf_file_name == dir_file:
self.__get_file_header__(dir_file_path) self.__get_file_header__(dir_file_path)
@ -84,52 +88,56 @@ class iOSTask(object):
self.__get_file_header__(dir_file_path) self.__get_file_header__(dir_file_path)
self.file_queue.put(dir_file_path) self.file_queue.put(dir_file_path)
def __decode_ipa__(self,output_path): def __decode_ipa__(self, output_path):
with zipfile.ZipFile(self.path,"r") as zip_files: with zipfile.ZipFile(self.path, "r") as zip_files:
zip_file_names = zip_files.namelist() zip_file_names = zip_files.namelist()
zip_files.extract(zip_file_names[0],output_path) zip_files.extract(zip_file_names[0], output_path)
try: try:
new_zip_file = zip_file_names[0].encode('cp437').decode('utf-8') new_zip_file = zip_file_names[0].encode(
'cp437').decode('utf-8')
except UnicodeEncodeError: except UnicodeEncodeError:
new_zip_file = zip_file_names[0].encode('utf-8').decode('utf-8') new_zip_file = zip_file_names[0].encode(
'utf-8').decode('utf-8')
old_zip_dir = self.__get_parse_dir__(output_path,zip_file_names[0]) old_zip_dir = self.__get_parse_dir__(
new_zip_dir = self.__get_parse_dir__(output_path,new_zip_file) output_path, zip_file_names[0])
os.rename(old_zip_dir,new_zip_dir) new_zip_dir = self.__get_parse_dir__(output_path, new_zip_file)
os.rename(old_zip_dir, new_zip_dir)
for zip_file in zip_file_names: for zip_file in zip_file_names:
old_ext_path = zip_files.extract(zip_file,output_path) old_ext_path = zip_files.extract(zip_file, output_path)
if not "Payload" in old_ext_path:
continue
start = str(old_ext_path).index("Payload") start = str(old_ext_path).index("Payload")
dir_path = old_ext_path[start:len(old_ext_path)] dir_path = old_ext_path[start:len(old_ext_path)]
old_ext_path = os.path.join(output_path,dir_path) old_ext_path = os.path.join(output_path, dir_path)
try: try:
new_zip_file = zip_file.encode('cp437').decode('utf-8') new_zip_file = zip_file.encode('cp437').decode('utf-8')
except UnicodeEncodeError: except UnicodeEncodeError:
new_zip_file = zip_file.encode('utf-8').decode('utf-8') new_zip_file = zip_file.encode('utf-8').decode('utf-8')
new_ext_path = os.path.join(output_path,new_zip_file) new_ext_path = os.path.join(output_path, new_zip_file)
if platform.system() == "Windows": if platform.system() == "Windows":
new_ext_path = new_ext_path.replace("/","\\") new_ext_path = new_ext_path.replace("/", "\\")
if not os.path.exists(new_ext_path): if not os.path.exists(new_ext_path):
dir_path = os.path.dirname(new_ext_path) dir_path = os.path.dirname(new_ext_path)
if not os.path.exists(dir_path): if not os.path.exists(dir_path):
os.makedirs(dir_path) os.makedirs(dir_path)
shutil.move(old_ext_path, new_ext_path) shutil.move(old_ext_path, new_ext_path)
if os.path.exists(old_ext_path): if os.path.exists(old_ext_path) and (".app" in old_ext_path):
try: try:
# mac发生权限问题的时候做处理 # mac发生权限问题的时候做处理
os.remove(old_ext_path) os.remove(old_ext_path)
except Exception: except Exception:
shutil.rmtree(old_ext_path) shutil.rmtree(old_ext_path)
def __get_parse_dir__(self, output_path, file_path):
def __get_parse_dir__(self,output_path,file_path):
start = file_path.index("Payload/") start = file_path.index("Payload/")
end = file_path.index(".app") end = file_path.index(".app")
root_dir = file_path[start:end] root_dir = file_path[start:end]
if platform.system() == "Windows": if platform.system() == "Windows":
root_dir = root_dir.replace("/","\\") root_dir = root_dir.replace("/", "\\")
old_root_dir = os.path.join(output_path,root_dir+".app") old_root_dir = os.path.join(output_path, root_dir+".app")
return old_root_dir return old_root_dir

@ -3,20 +3,18 @@
# Author: kelvinBen # Author: kelvinBen
# Github: https://github.com/kelvinBen/AppInfoScanner # Github: https://github.com/kelvinBen/AppInfoScanner
import re import openpyxl
import xlwt
import socket
import config import config
from queue import Queue from queue import Queue
import libs.core as cores import libs.core as cores
from libs.core.net import NetThreads from libs.core.net import NetThreads
import requests
class NetTask(object): class NetTask(object):
value_list = [] value_list = []
domain_list=[] domain_list = []
def __init__(self,result_dict,app_history_list,domain_history_list,file_identifier,threads): def __init__(self, result_dict, app_history_list, domain_history_list, file_identifier, threads):
self.result_dict = result_dict self.result_dict = result_dict
self.app_history_list = app_history_list self.app_history_list = app_history_list
self.file_identifier = file_identifier self.file_identifier = file_identifier
@ -27,7 +25,7 @@ class NetTask(object):
def start(self): def start(self):
xls_result_path = cores.xls_result_path xls_result_path = cores.xls_result_path
workbook = xlwt.Workbook(encoding = 'utf-8') workbook = openpyxl.Workbook()
worksheet = self.__creating_excel_header__(workbook) worksheet = self.__creating_excel_header__(workbook)
self.__write_result_to_txt__() self.__write_result_to_txt__()
@ -39,35 +37,34 @@ class NetTask(object):
workbook.save(xls_result_path) workbook.save(xls_result_path)
def __creating_excel_header__(self,workbook): def __creating_excel_header__(self, workbook):
worksheet = workbook.add_sheet("Result",cell_overwrite_ok=True) worksheet = workbook.create_sheet("Result", 0)
worksheet.write(0,0, label = "Number") worksheet.cell(row=1, column=1, value="Number")
worksheet.write(0,1, label = "IP/URL") worksheet.cell(row=1, column=2, value="IP/URL")
worksheet.write(0,2, label = "Domain") worksheet.cell(row=1, column=3, value="Domain")
worksheet.write(0,3, label = "Status") worksheet.cell(row=1, column=4, value="Status")
worksheet.write(0,4, label = "IP") worksheet.cell(row=1, column=5, value="IP")
worksheet.write(0,5, label = "Server") worksheet.cell(row=1, column=6, value="Server")
worksheet.write(0,6, label = "Title") worksheet.cell(row=1, column=7, value="Title")
worksheet.write(0,7, label = "CDN") worksheet.cell(row=1, column=8, value="CDN")
# worksheet.write(0,8, label = "Finger") worksheet.cell(row=1, column=9, value="Finger")
return worksheet return worksheet
def __write_result_to_txt__(self): def __write_result_to_txt__(self):
txt_result_path = cores.txt_result_path
append_file_flag = True append_file_flag = True
for key,value in self.result_dict.items(): for key, value in self.result_dict.items():
for result in value: for result in value:
if result in self.value_list: if result in self.value_list:
continue continue
self.value_list.append(result) self.value_list.append(result)
if (("http://" in result) or ("https://" in result)) and ("." in result): if (("http://" in result) or ("https://" in result)) and ("." in result):
domain = result.replace("https://","").replace("http://","")
if "{" in result or "}" in result or "[" in result or "]" in result or "\\" in result or "!" in result or "," in result: if "{" in result or "}" in result or "[" in result or "]" in result or "\\" in result or "!" in result or "," in result:
continue continue
domain = result.replace(
"https://", "").replace("http://", "")
if "/" in domain: if "/" in domain:
domain = domain[:domain.index("/")] domain = domain[:domain.index("/")]
@ -79,32 +76,35 @@ class NetTask(object):
url_suffix = result[result.rindex(".")+1:].lower() url_suffix = result[result.rindex(".")+1:].lower()
if not(cores.resource_flag and url_suffix in config.sniffer_filter): if not(cores.resource_flag and url_suffix in config.sniffer_filter):
self.domain_queue.put({"domain":domain,"url_ip":result}) self.domain_queue.put(
{"domain": domain, "url_ip": result})
for identifier in self.file_identifier: for identifier in self.file_identifier:
if identifier in self.app_history_list: if identifier in self.app_history_list:
if not(domain in self.domain_history_list): if not(domain in self.domain_history_list):
self.domain_list.append(domain) self.domain_list.append(domain)
self.__write_content_in_file__(cores.domain_history_path,domain) self.__write_content_in_file__(
cores.domain_history_path, domain)
continue continue
if not(domain in self.domain_list): if not(domain in self.domain_list):
self.domain_list.append(domain) self.domain_list.append(domain)
self.__write_content_in_file__(cores.domain_history_path,domain) self.__write_content_in_file__(
cores.domain_history_path, domain)
if append_file_flag: if append_file_flag:
self.__write_content_in_file__(cores.app_history_path,identifier) self.__write_content_in_file__(
cores.app_history_path, identifier)
append_file_flag = False append_file_flag = False
def __start_threads__(self,worksheet): def __start_threads__(self, worksheet):
for threadID in range(0,self.threads) : for threadID in range(0, self.threads):
name = "Thread - " + str(threadID) name = "Thread - " + str(threadID)
thread = NetThreads(threadID,name,self.domain_queue,worksheet) thread = NetThreads(threadID, name, self.domain_queue, worksheet)
thread.start() thread.start()
self.thread_list.append(thread) self.thread_list.append(thread)
def __write_content_in_file__(self,file_path,content): def __write_content_in_file__(self, file_path, content):
with open(file_path,"a+",encoding='utf-8',errors='ignore') as f: with open(file_path, "a+", encoding='utf-8', errors='ignore') as f:
f.write(content+"\r") f.write(content+"\r")
f.close() f.close()

@ -7,8 +7,9 @@ import config
import hashlib import hashlib
from queue import Queue from queue import Queue
class WebTask(object): class WebTask(object):
thread_list =[] thread_list = []
value_list = [] value_list = []
result_dict = {} result_dict = {}
@ -19,27 +20,27 @@ class WebTask(object):
self.permissions = [] self.permissions = []
def start(self): def start(self):
if len(config.web_file_suffix) <=0: if len(config.web_file_suffix) <= 0:
scanner_file_suffix = ["html","js","html","xml"] scanner_file_suffix = ["html", "js", "html", "xml"]
scanner_file_suffix = config.web_file_suffix scanner_file_suffix = config.web_file_suffix
if os.path.isdir(self.path): if os.path.isdir(self.path):
self.__get_scanner_file__(self.path,scanner_file_suffix) self.__get_scanner_file__(self.path, scanner_file_suffix)
else: else:
if not (self.path.split(".")[-1] in scanner_file_suffix): if not (self.path.split(".")[-1] in scanner_file_suffix):
err_info = ("Retrieval of this file type is not supported. Select a file or directory with a suffix of %s" % ",".join(scanner_file_suffix)) err_info = ("Retrieval of this file type is not supported. Select a file or directory with a suffix of %s" % ",".join(scanner_file_suffix))
raise Exception(err_info) raise Exception(err_info)
self.file_queue.put(self.path) self.file_queue.put(self.path)
return {"comp_list":[],"shell_flag":False,"file_queue":self.file_queue,"packagename":None,"file_identifier":self.file_identifier,"permissions":self.permissions} return {"comp_list": [], "shell_flag": False, "file_queue": self.file_queue, "packagename": None, "file_identifier": self.file_identifier, "permissions": self.permissions}
def __get_scanner_file__(self,scanner_dir,file_suffix): def __get_scanner_file__(self, scanner_dir, file_suffix):
dir_or_files = os.listdir(scanner_dir) dir_or_files = os.listdir(scanner_dir)
for dir_file in dir_or_files: for dir_file in dir_or_files:
dir_file_path = os.path.join(scanner_dir,dir_file) dir_file_path = os.path.join(scanner_dir, dir_file)
if os.path.isdir(dir_file_path): if os.path.isdir(dir_file_path):
self.__get_scanner_file__(dir_file_path,file_suffix) self.__get_scanner_file__(dir_file_path, file_suffix)
else: else:
if len(dir_file.split("."))>1: if len(dir_file.split(".")) > 1:
if dir_file.split(".")[-1] in file_suffix: if dir_file.split(".")[-1] in file_suffix:
with open(dir_file_path,'rb') as f: with open(dir_file_path,'rb') as f:
dex_md5 = str(hashlib.md5().update(f.read()).hexdigest()).upper() dex_md5 = str(hashlib.md5().update(f.read()).hexdigest()).upper()

@ -1,3 +1,3 @@
requests requests
click click
xlwt openpyxl

Binary file not shown.

@ -1,3 +1,10 @@
### V1.0.9
- 更新apktool为最新版本
- 优化部分环节流程
- 修复excle文件导出时超时行数限制
- 修复脚本执行时卡顿的问题
- 修复Mac下Playload文件权限不足的问题
### V1.0.8 ### V1.0.8
- 添加AK和SK的检测 - 添加AK和SK的检测
- 添加检测规则提交入口 - 添加检测规则提交入口

Loading…
Cancel
Save