{"id":28486147,"url":"https://github.com/fox-it/citrix-netscaler-triage","last_synced_at":"2025-07-20T22:06:00.663Z","repository":{"id":188484062,"uuid":"678824501","full_name":"fox-it/citrix-netscaler-triage","owner":"fox-it","description":"Dissect triage script for Citrix NetScaler devices","archived":false,"fork":false,"pushed_at":"2025-06-27T10:25:41.000Z","size":74,"stargazers_count":27,"open_issues_count":1,"forks_count":10,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-06-27T11:36:31.295Z","etag":null,"topics":["citrix","cve-2023-3519","dfir","dissect","iocs","netscaler","webshells"],"latest_commit_sha":null,"homepage":"https://blog.fox-it.com/2023/08/15/approximately-2000-citrix-netscalers-backdoored-in-mass-exploitation-campaign/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fox-it.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-08-15T13:19:06.000Z","updated_at":"2025-06-27T10:25:45.000Z","dependencies_parsed_at":"2024-06-25T15:31:20.519Z","dependency_job_id":"883e73ba-08f9-4feb-b295-eddd6ae52310","html_url":"https://github.com/fox-it/citrix-netscaler-triage","commit_stats":null,"previous_names":["fox-it/citrix-netscaler-triage"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fox-it/citrix-netscaler-triage","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fox-it%2Fcitrix-netscaler-triage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fox-it%2Fcitrix-netscaler-triage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fox-it%2Fcitrix-netscaler-triage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fox-it%2Fcitrix-netscaler-triage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fox-it","download_url":"https://codeload.github.com/fox-it/citrix-netscaler-triage/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fox-it%2Fcitrix-netscaler-triage/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266205048,"owners_count":23892389,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["citrix","cve-2023-3519","dfir","dissect","iocs","netscaler","webshells"],"created_at":"2025-06-08T01:10:23.070Z","updated_at":"2025-07-20T22:06:00.657Z","avatar_url":"https://github.com/fox-it.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Citrix NetScaler Triage\n\nThis repository contains triage scripts for Citrix NetScaler devices:\n\n* `iocitrix.py` -- a Dissect script to Triage a Citrix NetScaler image/target.\n* `scan-citrix-netscaler-version.py` -- fingerprint the version of a Citrix NetScaler device over HTTP.\n\n# scan-citrix-netscaler-version.py\n\nYou can use this script to scan and determine the version of a Citrix NetScaler device over HTTP.\n\n## Installing `scan-citrix-netscaler-version.py`\n\nUse the following steps:\n\n1. git clone https://github.com/fox-it/citrix-netscaler-triage.git\n2. cd citrix-netscaler-triage\n3. pip install httpx\n4. python3 scan-citrix-netscaler-version.py --help\n\nExample usage:\n\n```shell\n$ python3 scan-citrix-netscaler-version.py 192.168.1.10\n192.168.1.10 is running Citrix NetScaler version 13.1-51.15\n```\n\nOr get the results in JSON:\n\n```shell\n$ python3 scan-citrix-netscaler-version.py https://192.168.1.11 --json | jq\n{\n  \"scanned_at\": \"2024-05-13T13:37:08.039109+00:00\",\n  \"target\": \"https://192.168.1.11\",\n  \"rdx_en_stamp\": 1702548756,\n  \"rdx_en_dt\": \"2023-12-14T10:12:36+00:00\",\n  \"version\": \"13.0-92.21\",\n  \"error\": null\n}\n```\n\nFor more options see `--help`.\n\n# iocitrix.py\n\nYou can use `iocitrix.py` to check for known Indicators of Compromise on a NetScaler Dissect target. It checks for the following things:\n\n* Known strings used in webshells\n* Timestomped files\n* Suspicious cronjobs\n* Unknown SUID binaries\n\nNote that this script is meant to run on forensic disk images of Citrix NetScaler devices and not on the device itself.\nAlso see the [Creating Citrix NetScaler disk images](#creating-citrix-netscaler-disk-images) section on how to create forensic disk images of your Citrix NetScaler.\n\nEnsure that you have the latest version of Dissect, support for Citrix NetScaler was added in this PR: https://github.com/fox-it/dissect.target/pull/357\n\n**Disclaimer**: While this tool strives for accuracy, it is possible for it to produce false positives or false negatives. Users are advised to cross-check results and use their own judgement before making any decisions based on this tool's output.\n\n## Installing `iocitrix.py`\n\nUse the following steps:\n\n1. git clone https://github.com/fox-it/citrix-netscaler-triage.git\n2. cd citrix-netscaler-triage\n3. pip install -r requirements.txt\n4. pip install --upgrade --pre dissect.volume dissect.target\n \nNote that step 4 will print the following error, but you can ignore it:\n\n```\nERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n```\n\nYou can then run `iocitrix.py \u003cTARGETS\u003e` to start an IOC check against one or more forensic images. The script accepts any input that [dissect](https://github.com/fox-it/dissect.target) can read as a `Target`, such as a `.VMDK`, or a raw disk image. Some examples are provided below.\n\n```shell\npython3 iocitrix.py image.vmx\npython3 iocitrix.py image.vmdk\n```\n\nIf you have also created a forensic image of the [RAM disk](#create-a-disk-image-of-the-devmd0-disk-to-your-local-machine), you can utilize `iocitrix.py` to incorporate volatile data in its triage as such:\n\n```shell\npython3 iocitrix.py md0.img+image.vmx\npython3 iocitrix.py md0.img+image.vmdk\npython3 iocitrix.py md0.img+da0.img\n```\n\nThe `+` (plus) sign will load the two disk images as a single Dissect Target.\n\n## Creating Citrix NetScaler disk images\n\nA Citrix NetScaler exposes two important block devices which can imaged for offline forensic analysis. These block device files can be found at the following paths:\n* `/dev/md0`: The disk that holds the root (`/`) directory. This is a RAM disk\n* `/dev/da0`: The disk that holds the `/var` and `/flash` directories. This is a persistent disk.\n\nThe root directory (`/`) of Citrix NetScaler is a RAM disk, meaning that this is a volatile disk. This disk can be found at `/dev/md0` when the NetScaler is powered-on and running, and will be unavailable when the NetScaler is powered-off. The `/var` and `/flash` directories reside on the `/dev/da0` disk as two separate partitions and is persistent.\n\nThe following commands can be used on a local linux machine to create disk of your NetScaler over SSH:\n\n#### Create a disk image of the `/dev/da0` disk to your local machine\n\n```shell \nlocal ~ $ ssh nsroot@\u003cYOUR-NETSCALER-IP\u003e shell dd if=/dev/da0 bs=10M | tail -c +7 | head -c -6 \u003e da0.img\n```\n\nDo note, that this can take some time to complete. No progess is shown when using `dd`. \nIt is adviced to wait until you gain control back over the prompt. This is an indication that `dd` finished.\n\nAlso if you don't have `/dev/da0` it's most likely `/dev/ada0`, you can verify using the `mount` or `gpart show` command.\n\n#### Create a disk image of the `/dev/md0` disk to your local machine\n```shell\nlocal ~ $ ssh nsroot@\u003cYOUR-NETSCALER-IP\u003e shell dd if=/dev/md0 bs=10M | tail -c +7 | head -c -6 \u003e md0.img\n```\n\n**NOTE**: While it is recommended to create disk images of both `/dev/md0` and `/dev/da0`. Creating a disk image of `/dev/md0` is optional. This step could be skipped, though this can cause `iocitrix.py` to miss certains incicators of compromise.\n\n### Running `iocitrix.py` on your images\n\nAfter executing the previous commands on your local machine, the `da0.img` and `md0.img` files will be present. You can point `iocitrix` to these files to start triaging your images. Use the following command to do so:\n\n```shell\nlocal ~ $ python3 iocitrix.py md0.img+da0.img\n```\n\nExample output:\n```\n(venv) user@dissect:/data/netscaler/image$ python3 iocitrix.py md0.img+da0.img\n\u003cTarget md0.img+da0.img\u003e\n\nDisks\n- \u003cRawContainer size=555745286 vs=None\u003e\n- \u003cRawContainer size=21474836486 vs=\u003cDissectVolumeSystem serial=None\u003e\u003e\n\nVolumes\n- \u003cVolume name=None size=555745286 fs=\u003cFfsFilesystem\u003e\u003e\n- \u003cVolume name='part_00000000' size=1717567488 fs=\u003cFfsFilesystem\u003e\u003e\n- \u003cVolume name='part_66600000' size=4401922048 fs=\u003cFfsFilesystem\u003e\u003e\n- \u003cVolume name='part_16cc00000' size=2097152 fs=\u003cFfsFilesystem\u003e\u003e\n- \u003cVolume name='part_16ce00000' size=15353200128 fs=\u003cFfsFilesystem\u003e\u003e\n\nHostname      : None\nDomain        : None\nIPs           : 10.164.0.39, 10.164.0.10\nOS family     : citrix-netscaler (CitrixBsdPlugin)\nOS version    : NetScaler 13.1 build 30 (ns-13.1-30.52)\nArchitecture  : x86_64-citrix-netscaler\nLanguage(s)   :\nTimezone      : None\nInstall date  : 2023-08-08 13:59:38.228043+00:00\nLast activity : 2023-08-11 08:51:13.979536+00:00\n\n\n*** Checking for webshells ***\n\n\u003cioc/hit type='php-file-permission' alert='Suspicious php permission 0o644' confidence='high' path='/var/netscaler/logon/LogonPoint/uiareas/linux/adminupevents.php'\u003e\n\u003cioc/hit type='php-file-contents' alert=\"Suspicious PHP code 'b'array_filter(''\" confidence='high' path='/var/netscaler/logon/LogonPoint/uiareas/linux/adminupevents.php'\u003e\n\u003cioc/hit type='php-file-permission' alert='Suspicious php permission 0o644' confidence='high' path='/var/vpn/config.php'\u003e\n\u003cioc/hit type='php-file-contents' alert=\"Suspicious PHP code 'b'array_filter(''\" confidence='high' path='/var/vpn/config.php'\u003e\n\u003cioc/hit type='php-file-permission' alert='Suspicious php permission 0o644' confidence='high' path='/var/vpn/themes/config.php'\u003e\n\n*** Checking for timestomped files ***\n\n\n*** Checking for suspicious cronjobs ***\n\n\n*** Checking for SUID Binaries (this takes a while) ***\n\n\u003cioc/hit type='binary/suid' alert='Binary with SUID bit set Observed' confidence='medium' path='/tmp/python/bash'\u003e\n\n********************************************************************************\n***                                                                          ***\n*** There were findings for Indicators of Compromise.                        ***\n*** Please consider performing further forensic investigation of the system. ***\n***                                                                          ***\n********************************************************************************\n\nConfidence    Type                 Alert                                       Artefact Location\n------------  -------------------  ------------------------------------------  ---------------------------------------------------------------\nhigh          php-file-permission  Suspicious php permission 0o644             /var/netscaler/logon/LogonPoint/uiareas/linux/adminupevents.php\nhigh          php-file-contents    Suspicious PHP code 'b'array_filter(''      /var/netscaler/logon/LogonPoint/uiareas/linux/adminupevents.php\nhigh          php-file-permission  Suspicious php permission 0o644             /var/vpn/config.php\nhigh          php-file-contents    Suspicious PHP code 'b'array_filter(''      /var/vpn/config.php\nhigh          php-file-permission  Suspicious php permission 0o644             /var/vpn/themes/config.php\nmedium        binary/suid          Binary with SUID bit set Observed           /tmp/python/bash\n\nAll targets analyzed.\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffox-it%2Fcitrix-netscaler-triage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffox-it%2Fcitrix-netscaler-triage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffox-it%2Fcitrix-netscaler-triage/lists"}