├── htb-cli └── __init__.py ├── readme.txt ├── LICENSE ├── bin └── hackthebox.py └── setup.py /htb-cli/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | HTB_CLI - Interact with HTB through a terminal. 2 | Copyleft: Gr3atWh173 3 | based upon https://github.com/kulinacs/htb 4 | 5 | INSTALL: pip install htb-cli 6 | 7 | SETUP: 8 | 1. get your API key from HackTheBox (profile settings) 9 | 2. set the HTB_API_KEY environment variable to your api key 10 | 11 | USAGE: 12 | LIST MACHINES: hackthebox.py list machines [active/retired] 13 | GET A SPECIFIC MACHINE: hackthebox.py get machine (machine id) 14 | RESET A MACHINE: hackthebox.py reset (machine id) 15 | SWITCH VPN: hackthebox.py switch (lab) 16 | SUBMIT FLAG: hackthebox.py submit (root/user) (machine id) (hash) (difficulty [10-100]) 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bin/hackthebox.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from sys import argv, exit 4 | from os import environ 5 | from htb import HTB 6 | from prettytable import PrettyTable 7 | 8 | try: 9 | htb = HTB(environ["HTB_API_KEY"]) 10 | except: 11 | print("Setup the HTB_API_KEY first!") 12 | exit(1) 13 | 14 | def print_machine(argv): 15 | global htb 16 | mid = int(argv.pop()) 17 | machine = htb.get_machine(mid) 18 | 19 | for key, value in machine.items(): 20 | if key == "avatar" or key == "avatar_thumb": 21 | continue 22 | print(key.upper() + ": ", end="") 23 | if type(value) is dict: 24 | print() 25 | for k, v in value.items(): 26 | print("\t" + k.upper() + ": " + str(v)) 27 | else: 28 | print(str(value)) 29 | 30 | def reset_machine(argv): 31 | global htb 32 | mid = int(argv.pop()) 33 | 34 | print(htb.reset_machine(mid)["output"]) 35 | 36 | def print_machines(argv): 37 | global htb 38 | 39 | if len(argv) == 0: 40 | argv.append("all") 41 | 42 | machines = htb.get_machines() 43 | t = PrettyTable(['ID', 'Name', 'OS', 'Points', 'Maker']) 44 | 45 | fltr = argv.pop() 46 | for machine in machines: 47 | if fltr == "retired" and (machine.get("retired_date") != None): 48 | t.add_row([machine["id"], machine["name"], machine["os"], machine["points"], machine["maker"]["name"]]) 49 | elif fltr == "active" and (machine.get("retired_date") == None): 50 | t.add_row([machine["id"], machine["name"], machine["os"], machine["points"], machine["maker"]["name"]]) 51 | elif fltr == "all": 52 | t.add_row([machine["id"], machine["name"], machine["os"], machine["points"], machine["maker"]["name"]]) 53 | 54 | print(t) 55 | 56 | def print_usage(): 57 | print("USAGE:") 58 | print("LIST MACHINES: python hackthebox.py list machines [active/retired]") 59 | print("GET A SPECIFIC MACHINE: python hackthebox.py get machine (machine id)") 60 | print("RESET A MACHINE: hackthebox.py reset (machine id)") 61 | print("SWITCH VPN: python hackthebox.py switch (lab)") 62 | print("SUBMIT FLAG: python hackthebox.py submit (root/user) (mid) (hash) (difficulty[10-100])") 63 | 64 | def ls(argv): 65 | global htb 66 | t = argv.pop() 67 | if t == "machines": 68 | print_machines(argv) 69 | elif t == "vpns": 70 | print("eufree, usfree, euvip, usvip") 71 | else: 72 | print(t + ": I can't list that") 73 | 74 | def get(argv): 75 | global htb 76 | t = argv.pop() 77 | if t == "machine": 78 | print_machine(argv) 79 | 80 | def switch_vpn(argv): 81 | global htb 82 | htb.switch_vpn(argv.pop()) 83 | 84 | def submit_flag(argv): 85 | diff, flag, mid, lvl = argv 86 | diff = int(diff) 87 | mid = int(mid) 88 | if diff not in range(10, 100): 89 | print("Difficulty should be between 10 and 100") 90 | return 91 | elif lvl not in ["root", "user"]: 92 | print("Flag type should be root or user") 93 | return 94 | if lvl == "root": 95 | a = htb.own_machine_root(mid, flag, diff) 96 | else: 97 | a = htb.own_machine_user(mid, flag, diff) 98 | if not a: 99 | print("Submit failed!") 100 | 101 | def main(): 102 | if len(argv) < 2: 103 | print("type 'hackthebox.py usage' for usage") 104 | exit() 105 | 106 | argv.reverse() 107 | argv.pop() 108 | 109 | t = argv.pop() 110 | if t == "list": 111 | ls(argv) 112 | elif t == "get": 113 | get(argv) 114 | elif t == "switch": 115 | switch_vpn(argv) 116 | elif t == "usage": 117 | print_usage() 118 | exit() 119 | elif t == "submit": 120 | submit_flag(argv) 121 | elif t == "reset": 122 | reset_machine(argv) 123 | else: 124 | print("I don't understand") 125 | exit() 126 | 127 | main() 128 | 129 | 130 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from os import path 3 | 4 | here = path.abspath(path.dirname(__file__)) 5 | 6 | # Get the long description from the README file 7 | with open(path.join(here, 'readme.txt'), encoding='utf-8') as f: 8 | long_description = f.read() 9 | 10 | # Arguments marked as "Required" below must be included for upload to PyPI. 11 | # Fields marked as "Optional" may be commented out. 12 | 13 | setup( 14 | # This is the name of your project. The first time you publish this 15 | # package, this name will be registered for you. It will determine how 16 | # users can install this project, e.g.: 17 | # 18 | # $ pip install sampleproject 19 | # 20 | # And where it will live on PyPI: https://pypi.org/project/sampleproject/ 21 | # 22 | # There are some restrictions on what makes a valid project name 23 | # specification here: 24 | # https://packaging.python.org/specifications/core-metadata/#name 25 | name='htb-cli', # Required 26 | 27 | # Versions should comply with PEP 440: 28 | # https://www.python.org/dev/peps/pep-0440/ 29 | # 30 | # For a discussion on single-sourcing the version across setup.py and the 31 | # project code, see 32 | # https://packaging.python.org/en/latest/single_source_version.html 33 | version='0.1.2', # Required 34 | 35 | # This is a one-line description or tagline of what your project does. This 36 | # corresponds to the "Summary" metadata field: 37 | # https://packaging.python.org/specifications/core-metadata/#summary 38 | description='Interact with hackthebox with your terminal', # Optional 39 | 40 | # This is an optional longer description of your project that represents 41 | # the body of text which users will see when they visit PyPI. 42 | # 43 | # Often, this is the same as your README, so you can just read it in from 44 | # that file directly (as we have already done above) 45 | # 46 | # This field corresponds to the "Description" metadata field: 47 | # https://packaging.python.org/specifications/core-metadata/#description-optional 48 | long_description=long_description, # Optional 49 | 50 | # Denotes that our long_description is in Markdown; valid values are 51 | # text/plain, text/x-rst, and text/markdown 52 | # 53 | # Optional if long_description is written in reStructuredText (rst) but 54 | # required for plain-text or Markdown; if unspecified, "applications should 55 | # attempt to render [the long_description] as text/x-rst; charset=UTF-8 and 56 | # fall back to text/plain if it is not valid rst" (see link below) 57 | # 58 | # This field corresponds to the "Description-Content-Type" metadata field: 59 | # https://packaging.python.org/specifications/core-metadata/#description-content-type-optional 60 | long_description_content_type='text/plain', # Optional (see note above) 61 | 62 | # This should be a valid link to your project's main homepage. 63 | # 64 | # This field corresponds to the "Home-Page" metadata field: 65 | # https://packaging.python.org/specifications/core-metadata/#home-page-optional 66 | url='https://github.com/Gr3atWh173/htb_cli', # Optional 67 | 68 | # This should be your name or the name of the organization which owns the 69 | # project. 70 | author='Great White', # Optional 71 | 72 | # This should be a valid email address corresponding to the author listed 73 | # above. 74 | # author_email='pypa-dev@googlegroups.com', # Optional 75 | 76 | # Classifiers help users find your project by categorizing it. 77 | # 78 | # For a list of valid classifiers, see https://pypi.org/classifiers/ 79 | #classifiers=[ # Optional 80 | # How mature is this project? Common values are 81 | # 3 - Alpha 82 | # 4 - Beta 83 | # 5 - Production/Stable 84 | # 'Development Status :: 4 - Beta', 85 | 86 | # Indicate who your project is intended for 87 | # 'Intended Audience :: Developers', 88 | # 'Topic :: Information Security :: Helper Scripts', 89 | 90 | # Pick your license as you wish 91 | # 'License :: OSI Approved :: MIT License', 92 | 93 | # Specify the Python versions you support here. In particular, ensure 94 | # that you indicate whether you support Python 2, Python 3 or both. 95 | # These classifiers are *not* checked by 'pip install'. See instead 96 | # 'python_requires' below. 97 | # 'Programming Language :: Python :: 3', 98 | # 'Programming Language :: Python :: 3.4', 99 | # 'Programming Language :: Python :: 3.5', 100 | # 'Programming Language :: Python :: 3.6', 101 | # 'Programming Language :: Python :: 3.7', 102 | # ], 103 | 104 | # This field adds keywords for your project which will appear on the 105 | # project page. What does your project relate to? 106 | # 107 | # Note that this is a string of words separated by whitespace, not a list. 108 | keywords='hackthebox htb cli terminal', # Optional 109 | 110 | # You can just specify package directories manually here if your project is 111 | # simple. Or you can use find_packages(). 112 | # 113 | # Alternatively, if you just want to distribute a single Python file, use 114 | # the `py_modules` argument instead as follows, which will expect a file 115 | # called `my_module.py` to exist: 116 | # 117 | # py_modules=["my_module"], 118 | # 119 | packages=find_packages(exclude=['contrib', 'docs', 'tests']), # Required 120 | 121 | # Specify which Python versions you support. In contrast to the 122 | # 'Programming Language' classifiers above, 'pip install' will check this 123 | # and refuse to install the project if the version does not match. If you 124 | # do not support Python 2, you can simplify this to '>=3.5' or similar, see 125 | # https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires 126 | python_requires='>=3.5', 127 | 128 | # This field lists other packages that your project depends on to run. 129 | # Any package you put here will be installed by pip when your project is 130 | # installed, so they must be valid existing projects. 131 | # 132 | # For an analysis of "install_requires" vs pip's requirements files see: 133 | # https://packaging.python.org/en/latest/requirements.html 134 | install_requires=[ 135 | 'htb>=1.1.0', 136 | 'prettytable>=0.7.2', 137 | 'requests>=2.20.0' 138 | ], # Optional 139 | 140 | # List additional groups of dependencies here (e.g. development 141 | # dependencies). Users will be able to install these using the "extras" 142 | # syntax, for example: 143 | # 144 | # $ pip install sampleproject[dev] 145 | # 146 | # Similar to `install_requires` above, these must be valid existing 147 | # projects. 148 | # extras_require={ # Optional 149 | # 'dev': ['check-manifest'], 150 | # 'test': ['coverage'], 151 | # }, 152 | 153 | # If there are data files included in your packages that need to be 154 | # installed, specify them here. 155 | # 156 | # If using Python 2.6 or earlier, then these have to be included in 157 | # MANIFEST.in as well. 158 | # package_data={ # Optional 159 | # 'sample': ['package_data.dat'], 160 | # }, 161 | 162 | # Although 'package_data' is the preferred approach, in some case you may 163 | # need to place data files outside of your packages. See: 164 | # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files 165 | # 166 | # In this case, 'data_file' will be installed into '/my_data' 167 | # data_files=[('my_data', ['data/data_file'])], # Optional 168 | 169 | # To provide executable scripts, use entry points in preference to the 170 | # "scripts" keyword. Entry points provide cross-platform support and allow 171 | # `pip` to create the appropriate form of executable for the target 172 | # platform. 173 | # 174 | # For example, the following would provide a command called `sample` which 175 | # executes the function `main` from this package when invoked: 176 | # entry_points={ # Optional 177 | # 'console_scripts': [ 178 | # 'sample=sample:main', 179 | # ], 180 | # }, 181 | scripts=['bin/hackthebox.py'], 182 | 183 | # List additional URLs that are relevant to your project as a dict. 184 | # 185 | # This field corresponds to the "Project-URL" metadata fields: 186 | # https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use 187 | # 188 | # Examples listed include a pattern for specifying where the package tracks 189 | # issues, where the source is hosted, where to say thanks to the package 190 | # maintainers, and where to support the project financially. The key is 191 | # what's used to render the link text on PyPI. 192 | project_urls={ # Optional 193 | 'Bug Reports': 'https://github.com/Gr3atWh173/htb_cli/issues', 194 | 'Source': 'https://github.com/Gr3atWh173/htb_cli', 195 | }, 196 | ) --------------------------------------------------------------------------------