feat: added first commit malpacks

main
Muhammad Daffa 2023-08-14 21:01:01 +07:00
parent 98cba0c8c2
commit a88420f2d9
17 changed files with 43616 additions and 676 deletions

22
.github/scripts/append_data.py vendored Normal file
View File

@ -0,0 +1,22 @@
import json
with open('/path/to/list/malicious/pkgs.txt', 'r') as file:
lines = file.read().splitlines()
with open('database.json', 'r') as file:
existing_data = json.load(file)
for line in lines:
new_object = {
"type": "pypi",
"name": line,
"url": "https://github.com/DataDog/malicious-software-packages-dataset"
}
existing_data.append(new_object)
with open('database_new.json', 'w') as file:
json.dump(existing_data, file, indent=4)
print("Data appended and saved to database_new.json")
# This script is used to append data to the database.json file

17
.github/scripts/count.py vendored Normal file
View File

@ -0,0 +1,17 @@
import json
with open("../../database.json", "r") as json_file:
data = json.load(json_file)
type_counts = {}
for item in data:
item_type = item.get("type")
if item_type:
if item_type in type_counts:
type_counts[item_type] += 1
else:
type_counts[item_type] = 1
for item_type, count in type_counts.items():
print(f"{item_type}: {count}")

1348
LICENSE

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +1,52 @@
# malware-package-scanner
Tools to find malicious packages
# Malpacks
Tools to find malicious packages inside package manager (PyPI, npm, and Gem)
## Total data
* npm: 1823
* pypi: 5985
* gem: 725
## Installation
Simply clone the repository, install requirements and run the script
* $ git clone https://github.com/daffainfo/malpacks
* $ pip3 install -r requirements.txt
* $ python3 main.py
## Usage
Available options:
* `--all` option
To scan all the package managers (PyPI, npm, and Gem)
Example:
```bash
$ python3 main.py --all
```
* `--packages` option
Define package manager to test (PyPI, npm, and Gem)
Example:
```bash
$ python3 main.php --packages npm,pypi
```
## To-Do List
- [ ] Scan a file that contain list of packages
- [ ] Scan requirements.txt (Python)
- [ ] Scan package.json (npm)
- [ ] More output options
- [ ] JSON
- [ ] YAML
- [ ] Add more package manager
- [x] PyPI
- [x] npm
- [x] Gem
- [ ] Go
- [ ] Composer
- [ ] Add more malicious packages
- [x] https://blog.phylum.io/phylum-discovers-another-attack-on-pypi/
- [x] https://www.reversinglabs.com/blog/mining-for-malicious-ruby-gems
- [ ] https://github.com/DataDog/malicious-software-packages-dataset

Binary file not shown.

Binary file not shown.

16
core/cli.py Normal file
View File

@ -0,0 +1,16 @@
from colorama import Fore, Style
def banner():
banner = Fore.BLUE + """
# # ## # ##### ## #### # # ####
## ## # # # # # # # # # # # #
# ## # # # # # # # # # #### ####
# # ###### # ##### ###### # # # #
# # # # # # # # # # # # # #
# # # # ###### # # # #### # # ####
Version: 1.0.0
Author: daffainfo
"""
print(banner + Style.RESET_ALL)

55
core/scanner.py Normal file
View File

@ -0,0 +1,55 @@
import json
from colorama import Fore, Style
from packages import npm, pypi, gem
npm_packages = []
pypi_packages = []
gem_packages = []
def scan(args):
if args.all:
npm_packages = npm.list_all_npm_packages()
pypi_packages = pypi.list_all_pypi_packages()
gem_packages = gem.list_all_gem_packages()
check('npm', npm_packages)
check('pypi', pypi_packages)
check('gem', gem_packages)
if args.packages:
packages_type = args.packages.split(',')
for package_type in packages_type:
if package_type == 'npm':
npm_packages = npm.list_all_npm_packages()
check('npm', npm_packages)
elif package_type == 'pypi':
pypi_packages = pypi.list_all_pypi_packages()
check('pypi', pypi_packages)
elif package_type == 'gem':
gem_packages = gem.list_all_gem_packages()
check('gem', gem_packages)
else:
print(Fore.RED + f"[!] Unknown package type: {package_type}")
print(Style.RESET_ALL)
def check(package_type, package_names):
with open('database.json') as json_file:
database = json.load(json_file)
print(Fore.YELLOW + f"[!] Checking {package_type} packages...")
found_count = 0
for package in database:
package_type_in_db = package.get('type', '')
package_name = package.get('name', '')
package_url = package.get('url', '')
if package_type == package_type_in_db and package_name in package_names:
print(Fore.RED + f"[+] Package found: {package_name}")
print(Fore.RED + f"[+] Advisory: {package_url}")
print(Style.RESET_ALL)
found_count = found_count + 1
if found_count == 0:
print(Fore.GREEN + f"[+] No malicious {package_type} packages found.")
print(Style.RESET_ALL)

42667
database.json Normal file

File diff suppressed because it is too large Load Diff

20
main.py Normal file
View File

@ -0,0 +1,20 @@
import argparse
from colorama import Fore, Style
from core import scanner, cli
def main():
cli.banner()
parser = argparse.ArgumentParser(description='Specify scan parameters.')
parser.add_argument('--all', action='store_true', help='Scanning all package managers')
parser.add_argument('--packages', type=str, help='Define package manager to test', default="")
args = parser.parse_args()
if not args.all and not args.packages:
parser.error('Please specify either --all or --packages')
scanner.scan(args)
if __name__ == '__main__':
main()

Binary file not shown.

Binary file not shown.

Binary file not shown.

30
packages/gem.py Normal file
View File

@ -0,0 +1,30 @@
import subprocess
def list_all_gem_packages():
try:
result = subprocess.run(['gem', 'list'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
if result.returncode == 0:
# Split the captured output into lines to get package lines
package_lines = result.stdout.split('\n')
# Initialize an empty list to store package names
package_names = []
# Print only the package names
for package_line in package_lines:
package_info = package_line.strip().split(' ')
if len(package_info) > 0:
package_name = package_info[0]
package_names.append(package_name)
return package_names # Return the list of package names
else:
print("Error:", result.stderr)
except Exception as e:
print("An error occurred:", e)
# packages_array = list_all_gem_packages()
# print(packages_array)

32
packages/npm.py Normal file
View File

@ -0,0 +1,32 @@
import subprocess
def list_all_npm_packages():
try:
result = subprocess.run(['npm', 'ls', '-g'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
if result.returncode == 0:
# Split the captured output into lines to get package lines
package_lines = result.stdout.split('\n')
# Initialize an empty list to store package names
package_names = []
# Print only the package names without directory structure
for package_line in package_lines:
package_name = package_line.strip()
if package_name and package_name != '/usr/local/lib':
package_name = package_line.split('@')[0].strip()
package_name = package_name.replace('├──', '').replace('└──', '').strip()
if package_name:
package_names.append(package_name)
return package_names # Return the list of package names
else:
print("Error:", result.stderr)
except Exception as e:
print("An error occurred:", e)
#packages_array = list_all_npm_packages()
#print(packages_array)

30
packages/pypi.py Normal file
View File

@ -0,0 +1,30 @@
import subprocess
def list_all_pypi_packages():
try:
# Run the 'pip freeze' command and capture its output
result = subprocess.run(['pip3', 'freeze', '--all'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
if result.returncode == 0:
# Split the captured output into lines to get package names
package_lines = result.stdout.split('\n')
# Initialize an empty list to store package names
package_names = []
# Append package names to the list
for package_line in package_lines:
package_name = package_line.split('==')[0] # Extract the package name
if package_name:
package_names.append(package_name)
return package_names # Return the list of package names
else:
print("Error:", result.stderr)
except Exception as e:
print("An error occurred:", e)
# packages_array = list_all_pypi_packages()
# print(packages_array)

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
colorama==0.4.4