@@ -84,14 +84,19 @@ ARG LIGOLO_NG_VERSION=0.8.3
8484ARG MEDUSA_COMMIT=fef1e1f0ee91f6108a5a48d3b3c11dc4df40b122
8585ARG FREERDP_VERSION=3.24.1
8686ARG FREERDP_COMMIT=b6e770ccba87c58ffd0a55366fef33361798e39c
87+ ARG ADSCAN_RUNTIME_CONTRACT_VERSION="1"
8788SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
8889
8990ENV ADSCAN_HOME=/opt/adscan \
9091 HOME=/opt/adscan \
92+ ADSCAN_RUNTIME_CONTRACT_VERSION=${ADSCAN_RUNTIME_CONTRACT_VERSION} \
9193 XDG_CONFIG_HOME=/opt/adscan/.config \
9294 NPM_CONFIG_UPDATE_NOTIFIER=false \
95+ PLAYWRIGHT_BROWSERS_PATH=/opt/adscan/ms-playwright \
9396 PATH="/opt/adscan/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
9497
98+ RUN mkdir -p /opt/adscan
99+
95100RUN apt-get update -y && apt-get install -y --no-install-recommends \
96101 ca-certificates \
97102 curl \
@@ -213,6 +218,33 @@ RUN apt-get update -y && apt-get install -y --no-install-recommends \
213218 && printf '%s\n' 'libnvidia-opencl.so.1' > /etc/OpenCL/vendors/nvidia.icd \
214219 && rm -rf /var/lib/apt/lists/*
215220
221+ RUN printf '%s\n' \
222+ '#!/usr/bin/env bash' \
223+ 'set -euo pipefail' \
224+ 'if curl "$@"; then' \
225+ ' exit 0' \
226+ 'else' \
227+ ' status=$?' \
228+ 'fi' \
229+ 'if [[ "$status" -ne 60 ]]; then' \
230+ ' exit "$status"' \
231+ 'fi' \
232+ 'echo "warning: curl TLS verification failed; retrying with insecure fallback (-k)" >&2' \
233+ 'exec curl -k "$@"' \
234+ > /usr/local/bin/adscan-curl \
235+ && chmod +x /usr/local/bin/adscan-curl
236+
237+ # Install the browser revision expected by the Python Playwright package bundled
238+ # into the PRO binary. The Debian chromium package remains installed as a
239+ # fallback and for workflows that call Chromium directly.
240+ RUN set -eux; \
241+ python3 -m venv /tmp/playwright-installer; \
242+ /tmp/playwright-installer/bin/python -m pip install --no-cache-dir --upgrade pip; \
243+ /tmp/playwright-installer/bin/python -m pip install --no-cache-dir playwright==1.57.0; \
244+ PLAYWRIGHT_BROWSERS_PATH=/opt/adscan/ms-playwright \
245+ /tmp/playwright-installer/bin/python -m playwright install chromium; \
246+ rm -rf /tmp/playwright-installer
247+
216248# Codex CLI (official ChatGPT plan sign-in path for Plus/Pro subscriptions).
217249# Installed globally so `ask login codex` and `ask` can use `codex` directly.
218250RUN set -eux; \
@@ -224,6 +256,8 @@ RUN mkdir -p /opt/adscan/{bin,tools,tool_venvs,wordlists,logs,fonts} /workspaces
224256 && fc-cache -f \
225257 && chmod -R 0777 /opt/adscan /workspaces
226258
259+ COPY wordlists/ /opt/adscan/wordlists/
260+
227261COPY --from=john_builder /opt/adscan/tools/john/run /opt/adscan/tools/john/run
228262
229263# Install Python tool environments (mirrors `PipToolsConfig` from adscan.py)
@@ -248,7 +282,7 @@ RUN set -eux; \
248282 \
249283 python3 -m venv /opt/adscan/tool_venvs/netexec/venv; \
250284 pip_retry /opt/adscan/tool_venvs/netexec/venv/bin/python -U pip; \
251- pip_retry /opt/adscan/tool_venvs/netexec/venv/bin/python "git+https://github.com/Pennyw0rth/NetExec.git@f187717 "; \
285+ pip_retry /opt/adscan/tool_venvs/netexec/venv/bin/python "git+https://github.com/Pennyw0rth/NetExec.git@73ccf0d "; \
252286 \
253287 python3 -m venv /opt/adscan/tool_venvs/certipy/venv; \
254288 pip_retry /opt/adscan/tool_venvs/certipy/venv/bin/python -U pip; \
@@ -262,10 +296,6 @@ RUN set -eux; \
262296 pip_retry /opt/adscan/tool_venvs/bloodhound-ce-py/venv/bin/python -U pip; \
263297 pip_retry /opt/adscan/tool_venvs/bloodhound-ce-py/venv/bin/python "bloodhound-ce==1.9.1"; \
264298 \
265- python3 -m venv /opt/adscan/tool_venvs/weakpass/venv; \
266- pip_retry /opt/adscan/tool_venvs/weakpass/venv/bin/python -U pip; \
267- pip_retry /opt/adscan/tool_venvs/weakpass/venv/bin/python "weakpass-lookup"; \
268- \
269299 python3 -m venv /opt/adscan/tool_venvs/enum-trusts/venv; \
270300 pip_retry /opt/adscan/tool_venvs/enum-trusts/venv/bin/python -U pip; \
271301 pip_retry /opt/adscan/tool_venvs/enum-trusts/venv/bin/python "git+https://github.com/ADScanPro/enum-trusts.git@f7eae14"; \
@@ -291,7 +321,11 @@ RUN set -eux; \
291321# External tools (git/curl)
292322RUN set -eux; \
293323 mkdir -p /opt/adscan/tools; \
294- curl -fsSL "https://hashcat.net/files/hashcat-${HASHCAT_VERSION}.7z" -o /tmp/hashcat.7z; \
324+ if ! adscan-curl -fsSL "https://hashcat.net/files/hashcat-${HASHCAT_VERSION}.7z" -o /tmp/hashcat.7z; then \
325+ echo "warning: official hashcat download failed; falling back to SourceForge mirror" >&2; \
326+ wget --max-redirect=10 --no-check-certificate -O /tmp/hashcat.7z \
327+ "https://sourceforge.net/projects/hashcat.mirror/files/v${HASHCAT_VERSION}/hashcat-${HASHCAT_VERSION}.7z/download"; \
328+ fi; \
295329 7z x /tmp/hashcat.7z -o/opt/adscan/tools >/dev/null; \
296330 test -x "/opt/adscan/tools/hashcat-${HASHCAT_VERSION}/hashcat.bin"; \
297331 ln -sf "/opt/adscan/tools/hashcat-${HASHCAT_VERSION}/hashcat.bin" /opt/adscan/bin/hashcat; \
@@ -300,8 +334,8 @@ RUN set -eux; \
300334 \
301335 git clone --depth 1 https://github.com/Greenwolf/ntlm_theft.git /opt/adscan/tools/ntlm_theft; \
302336 mkdir -p /opt/adscan/tools/firepwd; \
303- curl -fsSL https://raw.githubusercontent.com/lclevy/firepwd/refs/heads/master/firepwd.py -o /opt/adscan/tools/firepwd/firepwd.py; \
304- curl -fsSL https://raw.githubusercontent.com/lclevy/firepwd/refs/heads/master/requirements.txt -o /opt/adscan/tools/firepwd/requirements.txt; \
337+ adscan- curl -fsSL https://raw.githubusercontent.com/lclevy/firepwd/refs/heads/master/firepwd.py -o /opt/adscan/tools/firepwd/firepwd.py; \
338+ adscan- curl -fsSL https://raw.githubusercontent.com/lclevy/firepwd/refs/heads/master/requirements.txt -o /opt/adscan/tools/firepwd/requirements.txt; \
305339 python3 -m venv /opt/adscan/tool_venvs/firepwd/venv; \
306340 /opt/adscan/tool_venvs/firepwd/venv/bin/python -m pip install --no-cache-dir -U pip; \
307341 /opt/adscan/tool_venvs/firepwd/venv/bin/python -m pip install --no-cache-dir -r /opt/adscan/tools/firepwd/requirements.txt; \
@@ -312,19 +346,19 @@ RUN set -eux; \
312346 /opt/adscan/tool_venvs/LSA-Reaper/venv/bin/python -m pip install --no-cache-dir -r /opt/adscan/tools/LSA-Reaper/requirements.txt impacket; \
313347 \
314348 mkdir -p /opt/adscan/tools/PKINITtools; \
315- curl -fsSL https://raw.githubusercontent.com/dirkjanm/PKINITtools/refs/heads/master/gettgtpkinit.py -o /opt/adscan/tools/PKINITtools/gettgtpkinit.py; \
316- curl -fsSL https://raw.githubusercontent.com/dirkjanm/PKINITtools/refs/heads/master/getnthash.py -o /opt/adscan/tools/PKINITtools/getnthash.py; \
317- curl -fsSL https://raw.githubusercontent.com/dirkjanm/PKINITtools/refs/heads/master/requirements.txt -o /opt/adscan/tools/PKINITtools/requirements.txt; \
349+ adscan- curl -fsSL https://raw.githubusercontent.com/dirkjanm/PKINITtools/refs/heads/master/gettgtpkinit.py -o /opt/adscan/tools/PKINITtools/gettgtpkinit.py; \
350+ adscan- curl -fsSL https://raw.githubusercontent.com/dirkjanm/PKINITtools/refs/heads/master/getnthash.py -o /opt/adscan/tools/PKINITtools/getnthash.py; \
351+ adscan- curl -fsSL https://raw.githubusercontent.com/dirkjanm/PKINITtools/refs/heads/master/requirements.txt -o /opt/adscan/tools/PKINITtools/requirements.txt; \
318352 python3 -m venv /opt/adscan/tool_venvs/PKINITtools/venv; \
319353 /opt/adscan/tool_venvs/PKINITtools/venv/bin/python -m pip install --no-cache-dir -U pip; \
320354 /opt/adscan/tool_venvs/PKINITtools/venv/bin/python -m pip install --no-cache-dir -r /opt/adscan/tools/PKINITtools/requirements.txt; \
321355 \
322356 mkdir -p /opt/adscan/tools/kerbrute; \
323- curl -fsSL https://github.com/ropnop/kerbrute/releases/download/v1.0.3/kerbrute_linux_amd64 -o /opt/adscan/tools/kerbrute/kerbrute; \
357+ adscan- curl -fsSL https://github.com/ropnop/kerbrute/releases/download/v1.0.3/kerbrute_linux_amd64 -o /opt/adscan/tools/kerbrute/kerbrute; \
324358 chmod +x /opt/adscan/tools/kerbrute/kerbrute; \
325359 \
326360 mkdir -p /opt/adscan/tools/ligolo-ng/proxy/linux-amd64; \
327- curl -fsSL \
361+ adscan- curl -fsSL \
328362 "https://github.com/nicocha30/ligolo-ng/releases/download/v${LIGOLO_NG_VERSION}/ligolo-ng_proxy_${LIGOLO_NG_VERSION}_linux_amd64.tar.gz" \
329363 -o /tmp/ligolo_proxy.tar.gz; \
330364 tar -xzf /tmp/ligolo_proxy.tar.gz -C /opt/adscan/tools/ligolo-ng/proxy/linux-amd64 proxy; \
@@ -334,7 +368,7 @@ RUN set -eux; \
334368 rm -f /tmp/ligolo_proxy.tar.gz; \
335369 \
336370 mkdir -p /opt/adscan/tools/ligolo-ng/agent/windows-amd64; \
337- curl -fsSL \
371+ adscan- curl -fsSL \
338372 "https://github.com/nicocha30/ligolo-ng/releases/download/v${LIGOLO_NG_VERSION}/ligolo-ng_agent_${LIGOLO_NG_VERSION}_windows_amd64.zip" \
339373 -o /tmp/ligolo_agent_windows_amd64.zip; \
340374 unzip -q /tmp/ligolo_agent_windows_amd64.zip agent.exe -d /opt/adscan/tools/ligolo-ng/agent/windows-amd64; \
@@ -447,20 +481,20 @@ RUN set -eux; \
447481 /opt/adscan/tools/windows-tools/runascs; \
448482 \
449483 # mimikatz – credential extraction (official gentilkiwi release ZIP)
450- curl -fsSL \
484+ adscan- curl -fsSL \
451485 "https://github.com/gentilkiwi/mimikatz/releases/download/${MIMIKATZ_VERSION}/mimikatz_trunk.zip" \
452486 -o /tmp/mimikatz.zip; \
453487 unzip -p /tmp/mimikatz.zip x64/mimikatz.exe \
454488 > /opt/adscan/tools/windows-tools/mimikatz/mimikatz.exe; \
455489 rm /tmp/mimikatz.zip; \
456490 \
457491 # Rubeus – Kerberos attacks (Ghostpack compiled binaries mirror)
458- curl -fsSL \
492+ adscan- curl -fsSL \
459493 "https://github.com/r3motecontrol/Ghostpack-CompiledBinaries/raw/master/Rubeus.exe" \
460494 -o /opt/adscan/tools/windows-tools/rubeus/Rubeus.exe; \
461495 \
462496 # Certify – ADCS exploitation (Ghostpack compiled binaries mirror)
463- curl -fsSL \
497+ adscan- curl -fsSL \
464498 "https://github.com/r3motecontrol/Ghostpack-CompiledBinaries/raw/master/Certify.exe" \
465499 -o /opt/adscan/tools/windows-tools/certify/Certify.exe; \
466500 \
@@ -486,14 +520,14 @@ RUN set -eux; \
486520 rm -rf /tmp/Whisker; \
487521 \
488522 # Seatbelt – host security enumeration (Ghostpack compiled binaries mirror)
489- curl -fsSL \
523+ adscan- curl -fsSL \
490524 "https://github.com/r3motecontrol/Ghostpack-CompiledBinaries/raw/master/Seatbelt.exe" \
491525 -o /opt/adscan/tools/windows-tools/seatbelt/Seatbelt.exe; \
492526 \
493527 # SharpHound – BloodHound collection from inside the target.
494528 # Keep this aligned with the managed BloodHound CE version. For BH CE v8.7.0,
495529 # upstream pins SHARPHOUND_VERSION=v2.10.0 in their Dockerfiles.
496- curl -fsSL \
530+ adscan- curl -fsSL \
497531 "https://github.com/SpecterOps/SharpHound/releases/download/${SHARPHOUND_VERSION}/SharpHound_${SHARPHOUND_VERSION}_windows_x86.zip" \
498532 -o /tmp/sharphound.zip; \
499533 unzip -p /tmp/sharphound.zip SharpHound.exe \
@@ -504,12 +538,12 @@ RUN set -eux; \
504538 # The historical GitHub release URL now returns 404 and the source tree
505539 # requires a larger Mono/xbuild compatibility patch set than we want inside
506540 # the runtime image, so use the maintained OffSec knowledge-base binary.
507- curl -fsSL "${KRBRELAYUP_URL}" \
541+ adscan- curl -fsSL "${KRBRELAYUP_URL}" \
508542 -o /opt/adscan/tools/windows-tools/krbrelayup/KrbRelayUp.exe; \
509543 \
510544 # RunasCs – run as different user (official GitHub release ZIP)
511545 # Also symlinked to the legacy path so runascs_manager.py finds it.
512- curl -fsSL \
546+ adscan- curl -fsSL \
513547 "https://github.com/antonioCoco/RunasCs/releases/download/v${RUNASCS_VERSION}/RunasCs.zip" \
514548 -o /tmp/runascs.zip; \
515549 unzip -p /tmp/runascs.zip RunasCs.exe \
@@ -524,19 +558,29 @@ RUN set -eux; \
524558
525559# Wordlists
526560RUN set -eux; \
561+ download_wordlist() { \
562+ local url="$1"; \
563+ local dest="$2"; \
564+ if curl -fsSL "$url" -o "$dest"; then \
565+ return 0; \
566+ fi; \
567+ case "$url" in \
568+ https://weakpass.com/*) \
569+ echo "warning: TLS verification failed for $url; retrying with insecure fallback (-k)" >&2; \
570+ curl -kfsSL "$url" -o "$dest"; \
571+ ;; \
572+ *) \
573+ return 1; \
574+ ;; \
575+ esac; \
576+ }; \
527577 mkdir -p /opt/adscan/wordlists; \
528- curl -fsSL https://github.com/brannondorsey/naive-hashcat/releases/download/data/rockyou.txt -o /opt/adscan/wordlists/rockyou.txt; \
529- curl -fsSL https://gist.github.com/The-Viper-One/a1ee60d8b3607807cc387d794e809f0b/raw/b7d83af6a8bbb43013e04f78328687d19d0cf9a7/kerberoast_pws.xz -o /opt/adscan/wordlists/kerberoast_pws.xz; \
578+ download_wordlist https://github.com/brannondorsey/naive-hashcat/releases/download/data/rockyou.txt /opt/adscan/wordlists/rockyou.txt; \
579+ download_wordlist https://gist.github.com/The-Viper-One/a1ee60d8b3607807cc387d794e809f0b/raw/b7d83af6a8bbb43013e04f78328687d19d0cf9a7/kerberoast_pws.xz /opt/adscan/wordlists/kerberoast_pws.xz; \
530580 xz -d -c /opt/adscan/wordlists/kerberoast_pws.xz > /opt/adscan/wordlists/kerberoast_pws; \
531- curl -fsSL https://weakpass.com/download/2073/hashmob.net_2025.medium.found.7z -o /opt/adscan/wordlists/hashmob.net_2025.medium.found.7z; \
532- 7z x -y -o/opt/adscan/wordlists /opt/adscan/wordlists/hashmob.net_2025.medium.found.7z; \
533- curl -fsSL https://weakpass.com/download/1938/kaonashi14M.txt.7z -o /opt/adscan/wordlists/kaonashi14M.txt.7z; \
534- 7z x -y -o/opt/adscan/wordlists /opt/adscan/wordlists/kaonashi14M.txt.7z; \
535581 mkdir -p /usr/share/wordlists; \
536582 git clone --depth 1 https://github.com/insidetrust/statistically-likely-usernames.git /usr/share/wordlists/statistically-likely-usernames; \
537583 rm -f /opt/adscan/wordlists/kerberoast_pws.xz; \
538- rm -f /opt/adscan/wordlists/hashmob.net_2025.medium.found.7z; \
539- rm -f /opt/adscan/wordlists/kaonashi14M.txt.7z; \
540584 chmod -R 0777 /opt/adscan/wordlists /usr/share/wordlists/statistically-likely-usernames
541585
542586COPY adscan_internal/assets/wordlists/kerberos-format-inference.txt /opt/adscan/wordlists/kerberos-format-inference.txt
@@ -558,8 +602,23 @@ RUN chmod +x /usr/local/bin/adscan-entrypoint
558602###############################################################################
559603FROM runtime-common AS runtime-pro
560604
605+ ARG ADSCAN_RUNTIME_VERSION=""
606+
607+ ENV ADSCAN_RUNTIME_LICENSE_MODE=PRO \
608+ ADSCAN_RUNTIME_VERSION=${ADSCAN_RUNTIME_VERSION}
609+
610+ # Partner tag baked at build time — identifies which partner this image was built for.
611+ # Passed via: docker build --build-arg ADSCAN_PARTNER_TAG=glenn-mssp-beta1
612+ # Empty in untagged builds (dev/CI). Used by telemetry for partner-level filtering.
613+ ARG ADSCAN_PARTNER_TAG=""
614+ ENV ADSCAN_PARTNER_TAG=${ADSCAN_PARTNER_TAG}
615+
561616COPY dist/adscan /usr/local/bin/adscan
562- RUN chmod +x /usr/local/bin/adscan
617+ RUN set -eux; \
618+ chmod +x /usr/local/bin/adscan; \
619+ if [[ -n "${ADSCAN_RUNTIME_VERSION}" ]]; then \
620+ printf '%s\n' "${ADSCAN_RUNTIME_VERSION}" > /opt/adscan/version; \
621+ fi
563622
564623ENTRYPOINT ["/usr/local/bin/adscan-entrypoint"]
565624
@@ -568,6 +627,11 @@ ENTRYPOINT ["/usr/local/bin/adscan-entrypoint"]
568627###############################################################################
569628FROM runtime-common AS runtime-lite
570629
630+ ARG ADSCAN_RUNTIME_VERSION=""
631+
632+ ENV ADSCAN_RUNTIME_LICENSE_MODE=LITE \
633+ ADSCAN_RUNTIME_VERSION=${ADSCAN_RUNTIME_VERSION}
634+
571635# Runtime Python dependencies for source-mode ADscan CLI.
572636RUN set -eux; \
573637 python3 -m venv /opt/adscan/venv; \
@@ -609,6 +673,7 @@ RUN set -eux; \
609673 textual==0.80.1 \
610674 "redis>=5.0.0,<5.3.0" \
611675 weasyprint>=60.0 \
676+ playwright==1.57.0 \
612677 jinja2>=3.0; \
613678 runtime_python="$(readlink -f /opt/adscan/venv/bin/python)"; \
614679 setcap cap_net_bind_service+ep "${runtime_python}"
@@ -640,4 +705,9 @@ RUN printf '%s\n' \
640705 > /usr/local/bin/adscan \
641706 && chmod +x /usr/local/bin/adscan
642707
708+ RUN set -eux; \
709+ if [[ -n "${ADSCAN_RUNTIME_VERSION}" ]]; then \
710+ printf '%s\n' "${ADSCAN_RUNTIME_VERSION}" > /opt/adscan/version; \
711+ fi
712+
643713ENTRYPOINT ["/usr/local/bin/adscan-entrypoint"]
0 commit comments