Skip to content

Instantly share code, notes, and snippets.

@qtc-de
Created December 9, 2024 19:31
Show Gist options
  • Save qtc-de/c1e6950cce7cdc2281dbbc0160e7a0ec to your computer and use it in GitHub Desktop.
Save qtc-de/c1e6950cce7cdc2281dbbc0160e7a0ec to your computer and use it in GitHub Desktop.
This script contains a python version of sccm-http-looter (https://github.com/badsectorlabs/sccm-http-looter)
#!/usr/bin/env python3
# This script contains a python version of sccm-http-looter (https://github.com/badsectorlabs/sccm-http-looter)
# The following additional packages may need to be installed depending on the usage:
#
# pip install requests-ntlm (required for authenticated access to SCCM DPs)
# pip install requests[socks] (required for usage over socks proxy)
#
# The script attempts to obtain a package list via HTTP directory listing. However, when dealing
# with large package lists, this is not 100% reliable as the server may cut the amount of entries
# being returned. Once the package list was obtained, it is stored as `{host}-sccm-packages.txt`.
# Using the --packages option, you can also use an already obtained list.
import re
import time
import requests
import argparse
import urllib.parse
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 GLS/100.10.9939.100'
parser = argparse.ArgumentParser(description='sccm-http v1.0.0 - Loot SCCM DPs via HTTP')
parser.add_argument('url', help='url of the SCCM depot server')
parser.add_argument('--username', metavar='name', help='username for NTLM authentication')
parser.add_argument('--password', metavar='pw', help='password for NTLM authentication')
parser.add_argument('--domain', metavar='dom', help='domain for NTLM authentication')
parser.add_argument('--user-agent', metavar='ua', default=USER_AGENT, help='user agent to use (default: chrome)')
parser.add_argument('--proxy', metavar='proxy', help='proxy server to use')
parser.add_argument('--list-only', action='store_true', help='only obtain the package list')
parser.add_argument('--packages', metavar='file', type=argparse.FileType('r'), help='list of packages to check')
parser.add_argument('--delay', metavar='int', default=0, type=int, help='amount of time between each request in seconds (default: 0)')
def main():
'''
Main method :)
'''
args = parser.parse_args()
session = requests.Session()
if args.proxy:
proxies = {
'http': args.proxy,
'https': args.proxy,
}
session.proxies.update(proxies)
if args.username or args.password or args.domain:
if not (args.username and args.password and args.domain):
print('[-] If credentials are used, all auth parameters need to be specified.')
return
from requests_ntlm import HttpNtlmAuth
session.auth = HttpNtlmAuth(f'{args.domain}\\{args.username}', args.password)
if not args.packages:
count = 0
url = f'{args.url}/SMS_DP_SMSPKG$/DataLib'
hostname = urllib.parse.urlparse(url).netloc
print('[+] Obtaining package list...')
response = session.get(url)
regex = re.compile(f'{args.url}/?SMS_DP_SMSPKG\\$/DataLib/([^"<]+)"')
with open(f'{hostname}-sccm-packages.txt', 'w') as output:
for item in regex.finditer(response.text):
if item.group(1).endswith('.INI'):
continue
print(item.group(1), file=output)
count += 1
print(f'[+] Obtained {count} package names.')
print(f'[+] Results have been written to {hostname}-sccm-packages.txt')
if args.list_only:
return
print(f'[+] Using {hostname}-sccm-packages.txt as input file.')
args.packages = open(f'{hostname}-sccm-packages.txt')
lines = args.packages.readlines()
for line in lines:
package = line.strip()
url = f'{args.url}/SMS_DP_SMSPKG$/{package}'
regex_pre = re.compile('^([^<]+ )<a')
regex_post = re.compile(f'{args.url}/?SMS_DP_SMSPKG\\$/{package}/([^"<]+)"')
print(f'[+] {package}')
response = session.get(url)
if response.status_code not in [200, 404]:
if response.status_code == 401:
print('[-] Unauthorized. Credentials required / incorrect ?')
return
else:
print('[-] Obtained unexpected HTTP {response.status_code} response.')
print(response.headers)
print(response.text)
return
else:
if response.status_code == 200:
found = False
items = response.text.split('<br>')
for item in items:
pre = regex_pre.search(item)
found = regex_post.search(item)
if pre:
preface = pre.group(1)
preface = preface.replace('&lt;', ' ')
preface = preface.replace('&gt', '')
else:
preface = '\t'
if found:
print(f'[+] {preface}{found.group(1)}')
if not found:
print(response.text)
else:
print('[+] \tNot Found!')
time.sleep(args.delay)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment