Skip to content

Instantly share code, notes, and snippets.

@khanzf
Created December 7, 2017 17:47
Show Gist options
  • Save khanzf/51d122b1e5af7d253ddcaac091ccd478 to your computer and use it in GitHub Desktop.
Save khanzf/51d122b1e5af7d253ddcaac091ccd478 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
'''
Recursively downloads Debian/Ubuntu/Kali packages and all associated dependencies
By: Farhan Khan ([email protected]) ([email protected])
You MUST run this on the same distribution AND version of the target system.
This only downloads the latest version of the package available within the
target distribution.
Download a single package:
Example run: ./apt-recursive -p package_name
Download from a list
Example run: ./apt-recursive -l packages.lst
'''
import subprocess
import argparse
import sys
import os
# Initial global variables
localfiles = os.listdir() # Stores local files in current directory
dash_count = 0 # Used to print '-' characters
def download_recursive(debname, dash_count):
print("\033[44mTop Level: %s\033[0m" % debname)
raw_output = subprocess.getoutput('apt-cache depends --recurse --no-recommends --no-suggests --no-conflicts --no-breaks --no-replaces --no-enhances --no-pre-depends %s | grep -v "^ "' % debname)
if 'No packages found' in raw_output:
print('\033[41mSkipping: %s, package does not exist\033[0m' % debname)
return
packages = [package.strip(":").strip("<").strip(">") for package in raw_output.split('\n')]
for package in packages:
if package == '': # Not sure why some package names are empty, not printing otherwise
continue
file_check = subprocess.getoutput("apt-cache show %s | grep Filename | awk '{print $2}' | rev | cut -d'/' -f1 | rev" % package)
if file_check == '': # If the return is empty, ignore
continue
if file_check in localfiles:
print("Skipping package: %s, already downloaded in %s" % (package, file_check))
continue
print("Downloading %s" % package)
subprocess.getoutput("apt-get download %s" % package)
localfiles.append(file_check)
def argument_parse():
parser = argparse.ArgumentParser()
parser.add_argument('--package', '-p', type=str, help="Specify individual package")
parser.add_argument('--list', '-l', type=str, help="Specify list of packages")
args = parser.parse_args()
if args.package and args.list:
print("Cannot specify both -p and -l")
sys.exit()
if not args.package and not args.list:
print("Must specify -p or -l")
sys.exit()
return args
def main():
args = argument_parse()
if args.package:
download_recursive(args.package, 0)
elif args.list:
try:
f = open(args.list)
for package_line in f.readlines():
package_line = package_line.strip('\n')
download_recursive(package_line, 0)
except:
print("Unable to open '%s', check permissions or if it exists." % args.list)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment