fox-it/dissect.target

Some Netscaler /flash partitions throw errors

Closed this issue · 2 comments

Dissect seems to not be able to parse some Citrix Netscaler /flash partition disk images.

The errors below happen when trying to parse some netscaler /flash partition images, but not all.

To verify this was not a PEBKAC error:

Verification the disk image is actually created properly


--- netscaler-flash.img
Regular file, size 1.600 GiB (1717567488 bytes)
FreeBSD boot loader (i386 boot1 at sector 0)
FreeBSD boot loader (i386 boot2/BTX 1.02 at sector 2)
BSD disklabel (at sector 1), 8 partitions
Partition a: 1.600 GiB (1717567488 bytes, 3354624 sectors from 0)
  Type 7 (4.2BSD fast file system)
  Includes the disklabel and boot code
  UFS2 file system, 64 KiB offset, little-endian
    Volume name "rootfs" (in superblock)
    Last mounted at "/flash"
Partition b: 4.100 GiB (4401922048 bytes, 8597504 sectors from 3354624)
  Type 1 (swap)
Partition c: 20.00 GiB (21474786816 bytes, 41942943 sectors from 0)
  Type 0 (Unused)
Partition d: 2 MiB (2097152 bytes, 4096 sectors from 11952128)
  Type 7 (4.2BSD fast file system)
Partition e: 14.30 GiB (15353200128 bytes, 29986719 sectors from 11956224)
  Type 7 (4.2BSD fast file system)

Errors

(dissect) root@hostname:/tmp# target-info netscaler-flash.img
2023-12-14T11:47:03.463100Z [warning  ] Failed to detect fat filesystem [dissect.target.filesystem]
2023-12-14T11:47:03.463451Z [warning  ] <Target netscaler-flash.img>: Can't identify filesystem: <Volume name='part_66600000' size=4401922048 fs=None> [dissect.target.target]
2023-12-14T11:47:03.463571Z [warning  ] Failed to detect fat filesystem [dissect.target.filesystem]
2023-12-14T11:47:03.463733Z [warning  ] <Target netscaler-flash.img>: Can't identify filesystem: <Volume name='part_16cc00000' size=2097152 fs=None> [dissect.target.target]
2023-12-14T11:47:03.463840Z [warning  ] Failed to detect fat filesystem [dissect.target.filesystem]
2023-12-14T11:47:03.464000Z [warning  ] <Target netscaler-flash.img>: Can't identify filesystem: <Volume name='part_16ce00000' size=15353200128 fs=None> [dissect.target.target]
2023-12-14T11:47:03.544186Z [error    ] Unable to import dissect.target.plugins.filesystem.yara [dissect.target.plugin]
2023-12-14T11:47:03.898760Z [error    ] <Target netscaler-flash.img>: Broken OS plugin: VyosPlugin [dissect.target.target]
Traceback (most recent call last):
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/target.py", line 455, in _init_os
    fs = os_plugin.detect(self)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/plugins/os/unix/linux/debian/vyos/_os.py", line 39, in detect
    for d in boot_dir.iterdir():
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/helpers/fsutil.py", line 686, in iterdir
    for entry in self._accessor.scandir(self):
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/filesystems/ffs.py", line 81, in scandir
    for entry in self._iterdir():
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/filesystems/ffs.py", line 70, in _iterdir
    for entry in self.entry.iterdir():
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 264, in iterdir
    buf = self.open()
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 333, in open
    return RunlistStream(self.fs.fh, self.dataruns(), self.size, self.fs.fragment_size)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 297, in dataruns
    for block_num in self._iter_blocks():
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 336, in _iter_blocks
    num_blocks = (self.size + (self.fs.block_size - 1)) // self.fs.block_size
  File "/usr/lib/python3.9/functools.py", line 969, in __get__
    val = self.func(instance)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 183, in size
    return self.inode.di_size
  File "/usr/lib/python3.9/functools.py", line 969, in __get__
    val = self.func(instance)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 179, in inode
    return self._read_inode()
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 171, in _read_inode
    return self.fs._inode_type(self.fs.fh)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/cstruct/types/base.py", line 24, in __call__
    return self.read(*args, **kwargs)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/cstruct/types/base.py", line 73, in read
    return self._read(obj)
  File "<compiled ufs2_dinode>", line 15, in _read
EOFError
2023-12-14T11:47:03.901420Z [error    ] netscaler-flash.img: Failed to load target with loader RawLoader('netscaler-flash.img') [dissect.target.target]
Traceback (most recent call last):
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/target.py", line 412, in _load
    target.apply()
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/target.py", line 159, in apply
    self._init_os()
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/target.py", line 485, in _init_os
    self._os = self.add_plugin(os_plugin.create(self, fs))
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/plugins/os/unix/_os.py", line 38, in create
    return cls(target)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/plugins/os/unix/bsd/citrix/_os.py", line 27, in __init__
    self._parse_netscaler_configs()
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/plugins/os/unix/bsd/citrix/_os.py", line 32, in _parse_netscaler_configs
    for config_path in self.target.fs.path("/flash/nsconfig/").glob("ns.conf*"):
  File "/usr/lib/python3.9/pathlib.py", line 1166, in glob
    for p in selector.select_from(self):
  File "/usr/lib/python3.9/pathlib.py", line 548, in _select_from
    entries = list(scandir_it)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/filesystem.py", line 1438, in scandir
    for entry in fsentry.scandir():
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/filesystems/ffs.py", line 81, in scandir
    for entry in self._iterdir():
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/filesystems/ffs.py", line 70, in _iterdir
    for entry in self.entry.iterdir():
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 264, in iterdir
    buf = self.open()
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 333, in open
    return RunlistStream(self.fs.fh, self.dataruns(), self.size, self.fs.fragment_size)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 297, in dataruns
    for block_num in self._iter_blocks():
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 336, in _iter_blocks
    num_blocks = (self.size + (self.fs.block_size - 1)) // self.fs.block_size
  File "/usr/lib/python3.9/functools.py", line 969, in __get__
    val = self.func(instance)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 183, in size
    return self.inode.di_size
  File "/usr/lib/python3.9/functools.py", line 969, in __get__
    val = self.func(instance)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 179, in inode
    return self._read_inode()
  File "/opt/dissect/lib/python3.9/site-packages/dissect/ffs/ffs.py", line 171, in _read_inode
    return self.fs._inode_type(self.fs.fh)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/cstruct/types/base.py", line 24, in __call__
    return self.read(*args, **kwargs)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/cstruct/types/base.py", line 73, in read
    return self._read(obj)
  File "<compiled ufs2_dinode>", line 15, in _read
EOFError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/target.py", line 289, in open_all
    target = cls._load(sub_entry, ldr)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/target.py", line 415, in _load
    raise TargetError(f"Failed to load target: {path}", cause=e)
dissect.target.exceptions.TargetError: Failed to load target: netscaler-flash.img
Traceback (most recent call last):
  File "/opt/dissect/bin/target-info", line 8, in <module>
    sys.exit(main())
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/tools/utils.py", line 250, in wrapper
    return func(*args, **kwargs)
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/tools/info.py", line 75, in main
    for i, target in enumerate(Target.open_all(args.targets)):
  File "/opt/dissect/lib/python3.9/site-packages/dissect/target/target.py", line 309, in open_all
    raise TargetError(f"Failed to find any loader for targets: {paths}")
dissect.target.exceptions.TargetError: Failed to find any loader for targets: ['netscaler-flash.img']

used Python 3.9 with:

(dissect) root@hostname:/tmp# pip freeze | grep dissect
dissect==3.10
dissect.cim==3.7
dissect.clfs==1.6
dissect.cstruct==3.10
dissect.esedb==3.9
dissect.etl==3.7
dissect.eventlog==3.6
dissect.evidence==3.7
dissect.executable==1.4
dissect.extfs==3.6
dissect.fat==3.7
dissect.ffs==3.6
dissect.hypervisor==3.10
dissect.ntfs==3.7
dissect.ole==3.6
dissect.regf==3.8
dissect.shellitem==3.6
dissect.sql==3.7
dissect.squashfs==1.3
dissect.target==3.14.dev29
dissect.thumbcache==1.6
dissect.util==3.12
dissect.vmfs==3.6
dissect.volume==3.7
dissect.xfs==3.6

we created a new dd image using /dev/ad0 instead of /dev/ad0s1a (flash) and /dev/ad0s1e (/var), this new image gets parsed properly.

(dissect) root@hostname:/tmp# disktype dev_ad0.img

--- /tmp/dev_ad0.img
Regular file, size 20 GiB (21474836480 bytes)
DOS/MBR partition map
Partition 1: 20.00 GiB (21474786816 bytes, 41942943 sectors from 63, bootable)
  Type 0xA5 (FreeBSD)
  FreeBSD boot loader (i386 boot1 at sector 0)
  FreeBSD boot loader (i386 boot2/BTX 1.02 at sector 2)
  BSD disklabel (at sector 1), 8 partitions
  Partition a: 1.600 GiB (1717567488 bytes, 3354624 sectors from 0)
    Type 7 (4.2BSD fast file system)
    Includes the disklabel and boot code
    UFS2 file system, 64 KiB offset, little-endian
      Volume name "rootfs" (in superblock)
      Last mounted at "/flash"
  Partition b: 4.100 GiB (4401922048 bytes, 8597504 sectors from 3354624)
    Type 1 (swap)
  Partition c: 20.00 GiB (21474786816 bytes, 41942943 sectors from 0)
    Type 0 (Unused)
  Partition d: 2 MiB (2097152 bytes, 4096 sectors from 11952128)
    Type 7 (4.2BSD fast file system)
    Blank disk/medium
  Partition e: 14.30 GiB (15353200128 bytes, 29986719 sectors from 11956224)
    Type 7 (4.2BSD fast file system)
    UFS2 file system, 64 KiB offset, little-endian
      Volume name "varfs" (in superblock)
      Last mounted at "/var"```

Can this issue be closed? The improved Netscaler OS detection is now merged, and I think we determined that a correct full dd is required, instead of just the partition. Unfortunately important information seems to be lost when doing the latter. Perhaps we can still update the README in the ioctrix repo.