Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 123 additions & 33 deletions capabilities/dotnet-reversing/skills/dotnet-reversing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ description: Use when reverse engineering .NET assemblies, decompiling DLLs/EXEs

# .NET Reverse Engineering

Load the `vuln-assessment-methodology` skill alongside this one for severity
calibration, disprove-first discipline, and reporting standards.

## Quick Start

```
Expand Down Expand Up @@ -61,17 +64,27 @@ Use `dotnet_search_by_name` for name-based searches and `dotnet_search_reference
- **XML (XXE):** `XmlReader`, `XmlDocument`, `XDocument`, `XmlTextReader`
- **LDAP:** `DirectorySearcher`, `DirectoryEntry`, `System.DirectoryServices`

### Phase 3: Decompile Suspicious Code
### Phase 3: Decompile and Verify
```
dotnet_decompile_type(path="App.dll", type_name="App.Services.AuthenticationService")
```
Read the actual C# source. Look for:
Read the actual C# source. When you find a dangerous pattern, **read the full
function and its callers** before drawing conclusions. Check for:
- Hardcoded credentials
- Weak crypto (MD5, SHA1, DES, static IVs/keys)
- SQL string concatenation
- SQL string concatenation — **but check if the concatenated value comes from
user input (HTTP param) vs config/env var. Only HTTP-sourced values are high severity.**
- Unsanitized user input in file paths
- Dangerous deserialization
- Command injection
- Command injection — **but check if the calling function has validation/filtering.
If validation exists, look for bypasses rather than reporting "no sanitization."**

#### .NET-specific: JWT ReadToken is not always a finding

`ReadToken`/`ReadJwtToken` without `ValidateToken` is NOT a vulnerability when
the token is validated by a downstream service (Azure AD, ARM) or used only for
metadata extraction (expiry, caching). Only report it when unvalidated claims
drive authorization decisions.

### Phase 4: Trace Attack Paths
```
Expand All @@ -83,13 +96,32 @@ dotnet_get_call_flows(
```
Find how vulnerable methods are reached from entry points (controllers, handlers, public APIs).

### Phase 5: Report Findings
### Phase 5: Assess Severity and Report

Assign severity based on actual exploitability — not the vulnerability class
name. The `vuln-assessment-methodology` skill has the full guidance; the
essentials:

| Source of dangerous input | Access required | Severity |
|---|---|---|
| HTTP request parameter | Unauthenticated, internet-facing | Critical/High |
| HTTP request parameter | Authenticated user | High/Medium |
| HTTP request parameter | Internal network only | Medium |
| Config file / env var | Container or host access | Low |
| Hardcoded value (as sink input) | N/A | Not a finding (but hardcoded credentials are — see methodology skill) |

**Before reporting every finding:**
- Trace the data flow from attacker-controlled source to sink
- Actively try to disprove it — look for validation, encoding, authorization
- If defensive code exists, demonstrate a specific bypass or retract
- Verify severity reflects exploitability, not vulnerability class name

```
report_finding(
file="App.dll",
method="AuthService.ValidateToken",
criticality="high",
content="Hardcoded JWT secret found:\n```csharp\nprivate static string Secret = \"supersecret123\";\n```"
criticality="critical",
content="Hardcoded JWT signing secret in source code:\n```csharp\nprivate static string Secret = \"supersecret123\";\n```"
)

report_auth(auth_material="API key in config: `sk-1234567890abcdef`")
Expand All @@ -100,69 +132,127 @@ finish_task(success=True, markdown_summary="Found 2 high-severity issues...")
```
Always report findings to persist them to the Dreadnode platform.

## Common Vulnerability Patterns
## .NET Vulnerability Patterns: Vulnerable vs Safe

For each pattern, both vulnerable AND safe versions are shown. You must
check which one the code matches before reporting.

### Hardcoded Credentials
```csharp
// Look for string literals in auth code
// VULNERABLE — real secret in source code
private static string ApiKey = "sk-1234567890abcdef";
connectionString = "Server=db;User=admin;Password=P@ssw0rd";

// NOT A FINDING — loaded from config/env
var apiKey = Configuration["ApiKey"];
var connStr = Environment.GetEnvironmentVariable("DB_CONNECTION");

// NOT A FINDING — misleading error message (not a real credential)
throw new Exception("Api Key is invalid. Subscription validation failed.");
```

### Insecure Deserialization
```csharp
// BinaryFormatter = RCE
// VULNERABLE — BinaryFormatter with untrusted input
BinaryFormatter formatter = new BinaryFormatter();
object obj = formatter.Deserialize(stream); // VULNERABLE
object obj = formatter.Deserialize(untrustedStream);

// Type-controlling JSON deserialization
// VULNERABLE — TypeNameHandling enables type control
JsonConvert.DeserializeObject(json, new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.All // VULNERABLE
TypeNameHandling = TypeNameHandling.All
});

// SAFE — System.Text.Json (no type handling by default)
var obj = JsonSerializer.Deserialize<MyType>(json);

// SAFE — TypeNameHandling.None (default)
JsonConvert.DeserializeObject<MyType>(json);
```

### Command Injection
```csharp
// User input in process arguments
Process.Start("cmd.exe", "/c " + userInput); // VULNERABLE
// VULNERABLE — direct interpolation
Process.Start("cmd.exe", "/c " + userInput);
Arguments = $"-c \"{command} {string.Join(" ", args)}\"";

// PARTIALLY SAFE — has validation, but check for bypasses
var error = ValidateCommand(command); // blocks ; && || | etc.
if (error != null) return error;
// If ValidateCommand misses characters like " or ${ }, it's
// an incomplete validation bypass (Medium), not "no sanitization" (High)

// SAFE — no shell, direct exec with argument array
Process.Start("myapp", new[] { "--flag", sanitizedValue });
```

### Path Traversal
### SQL Injection
```csharp
// Unsanitized path concatenation
string path = Path.Combine(baseDir, userFileName); // VULNERABLE if userFileName = "../../../etc/passwd"
File.ReadAllText(path);
// VULNERABLE — user input concatenated into SQL
string query = "SELECT * FROM users WHERE id = " + request.UserId;

// LOW RISK — env var / config value concatenated (defense-in-depth issue)
// Attacker needs container access to control env var
string proc = "[" + schemaFromEnvVar + "].[MyProcedure]";

// SAFE — parameterized query
cmd.CommandText = "SELECT * FROM users WHERE id = @id";
cmd.Parameters.AddWithValue("@id", userId);
```

### SQL Injection
### Blazor XSS (MarkupString)
```csharp
// VULNERABLE — user input directly cast to MarkupString
builder.AddContent(0, (MarkupString)userInput);

// SAFE — HtmlEncoded BEFORE MarkupString cast
var encoded = WebUtility.HtmlEncode(userInput);
var colored = AnsiParser.ConvertToHtml(encoded, state); // adds <span> tags
builder.AddContent(0, (MarkupString)colored); // MarkupString needed for spans

// SAFE — Markdown pipeline with HTML disabled
pipeline.DisableHtml();
var html = Markdown.ToHtml(input, pipeline);
builder.AddContent(0, (MarkupString)html);
```

### JWT Validation
```csharp
// String concatenation in queries
string query = "SELECT * FROM users WHERE id = " + userId; // VULNERABLE
cmd.CommandText = query;
// VULNERABLE — claims trusted for local authorization
var token = new JwtSecurityTokenHandler().ReadJwtToken(jwt);
if (token.Claims.First(c => c.Type == "role").Value == "admin")
GrantAdminAccess(); // No signature verification!

// SAFE — token read for metadata, validated by downstream service
var token = handler.ReadJwtToken(jwt);
var expiry = token.ValidTo; // Just extracting expiry for caching
return DelegatedTokenCredential.Create(jwt); // Azure AD validates the sig
```

### Weak Cryptography
### Path Traversal
```csharp
// Deprecated algorithms
MD5.Create().ComputeHash(data); // Weak hash
DES.Create(); // Weak cipher
new RijndaelManaged { Mode = CipherMode.ECB }; // Weak mode
// VULNERABLE — user input in path without validation
string path = Path.Combine(baseDir, userFileName);
File.ReadAllText(path);

// SAFE — canonicalization check with trailing separator
string normalizedBase = Path.GetFullPath(baseDir) + Path.DirectorySeparatorChar;
string full = Path.GetFullPath(Path.Combine(baseDir, userFileName));
if (!full.StartsWith(normalizedBase)) throw new SecurityException();
```

## Critical Rules

**DO:**
- Always start with `dotnet_scan_binaries` to find targets
- Use `dotnet_decompile_type` for targeted analysis (not `dotnet_decompile_module`)
- Report ALL findings with `report_finding` — even low-severity ones
- Use `report_auth` immediately when you find credentials
- Report all verified findings with `report_finding` — even low-severity ones
- Use `report_auth` only for real credentials, not error messages or placeholders
- Call `finish_task` when analysis is complete

**DO NOT:**
- Report `ReadToken`/`ReadJwtToken` as "JWT bypass" when the token is validated server-side
- Report `MarkupString` as XSS when the content is `HtmlEncode`d upstream
- Use `dotnet_decompile_module` on large assemblies — it will overflow context
- Skip reporting — findings must be persisted to the platform
- Analyze only one assembly — check ALL binaries in the target directory
- Ignore Microsoft/System assemblies completely — they can have vulnerabilities too

## Tips

Expand Down
76 changes: 72 additions & 4 deletions capabilities/dotnet-reversing/skills/mcr-analysis/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ description: Use when analyzing .NET applications from Microsoft Container Regis

# MCR Container Image Analysis

Extract and analyze .NET assemblies from Microsoft Container Registry images without executing any container code. Uses pure HTTP—no Docker required.
Extract and analyze .NET assemblies from Microsoft Container Registry images
without executing any container code. Uses pure HTTP—no Docker required.

Load the `vuln-assessment-methodology` skill alongside this one for severity
calibration, disprove-first discipline, and reporting standards.

## When to Use MCR Tools

Expand Down Expand Up @@ -44,6 +48,20 @@ dotnet_scan_binaries(path="~/workspace/mcr/dotnet_aspnet_8.0") # analyze
| `azure-functions/*` | Azure Functions runtime |
| `appsvc/*` | Azure App Service images |

Use `mcr_search_repositories` to discover repos beyond these — the catalog has
~3,200 entries across Azure services, infrastructure, and tooling.

## Not All MCR Images Are .NET

Many MCR images use Go, Python, TypeScript, or Rust. Extraction will return
"No .NET assemblies found" for these. This is common for infrastructure and
networking components (CNI plugins, proxies, tunnels, AI/ML runtimes).

If extraction fails:
1. Try `dll_only=false` — some images use AOT compilation or non-standard layouts
2. Try a different platform (`linux/arm64` vs `linux/amd64`)
3. Accept that the image may not contain .NET code and move on

## Workflow

### 1. Find the Target Image
Expand Down Expand Up @@ -78,21 +96,71 @@ dotnet_search_references(path="~/workspace/mcr/.../TargetAssembly.dll", search="

For app images (`appsvc/*`, `azure-functions/*`), prioritize assemblies under `/app/` over runtime DLLs. For runtime images (`dotnet/runtime`, `dotnet/aspnet`), target `System.Private.CoreLib.dll` or `Microsoft.AspNetCore.dll` directly.

## MCR-Specific Attack Surface

When analyzing assemblies extracted from MCR images, look for these in addition
to standard .NET vulnerability patterns:

1. **ONNX/ML model loading** — Path traversal in model file paths
2. **ANSI/terminal parsers** — Escape sequence injection breaking HTML context
3. **Protobuf/gRPC handling** — Oversized message DoS, recursive depth bombs
4. **URL parsers** — Scheme bypass, authority confusion, attribute breakout

## Prioritizing MCR Repos for Security Analysis

Not all MCR repos are equally interesting. Prioritize:

**Highest value:**
- New products/services (few tags, v0.x/v1.x — less mature, less audited)
- API gateways and reverse proxies (parse untrusted HTTP — smuggling, injection)
- Auth/identity services (JWT, certificate, token handling)
- Database access layers (SQL injection, query injection)
- AI/ML services (model loading, prompt handling, inference pipelines)

**Medium value:**
- Emulators (often have weaker auth than production counterparts)
- Internal/SRE tools (may rely on network isolation instead of auth)
- Monitoring/observability dashboards (render untrusted telemetry data)

**Lower value:**
- Mature Microsoft runtime images (dotnet/runtime, dotnet/aspnet — heavily audited)
- Helm charts and Bicep modules (infrastructure-as-code, not runtime code)
- Build tools and SDKs (not typically internet-facing)

## Delegating Analysis to Subagents

When dispatching subagents to analyze extracted assemblies:

1. **Load the analysis guidance** — ensure subagents have both the
`dotnet-reversing` and `vuln-assessment-methodology` skills loaded
2. **Tell them what NOT to report** — share known false-positive patterns
from previous analysis of similar codebases
3. **Specify the application assemblies** — list the non-framework DLLs
explicitly so they don't waste time on Microsoft.AspNetCore.* etc.
4. **Set threat model context** — tell them if the target is public-facing,
internal, or a dev tool so they assign severity appropriately
5. **Require disproof attempts** — instruct subagents to try to disprove
each finding before reporting it

## Critical Rules

**DO:**
- Always use `mcr_list_tags` before `mcr_pull_and_extract` to pick the right version
- Use specific version tags (e.g., `8.0.25`) not floating tags (`8.0`, `latest`)
- After extraction, immediately run `dotnet_scan_binaries` on the output directory
- Prioritize `/app/` assemblies over runtime assemblies when analyzing app images
- Prioritize `/app/` or `/emulator/` assemblies over runtime assemblies
- Check tag counts and version numbers to gauge maturity (few tags = newer = less audited)

**DO NOT:**
- Skip the extraction step and try to analyze MCR URLs directly — you must extract first
- Skip the extraction step and try to analyze MCR URLs directly
- Use `latest` tag for security analysis — it changes over time
- Forget to note the output directory path from `mcr_pull_and_extract`
- Assume extraction failure means the image is empty — it may not be .NET
- Dispatch subagents without the analysis guidance loaded

## Tips

- **Version pinning**: Use specific tags like `8.0.25` instead of `8.0` or `latest` for reproducibility
- **Cache reuse**: Repeated extractions of the same image skip the download
- **Large images**: SDK images are huge (~800MB); prefer runtime/aspnet images when possible
- **Parallel extraction**: Extract multiple images simultaneously while waiting for results
- **Cross-reference tags**: Repos with very few tags or only `latest` are brand new — potentially less audited
27 changes: 27 additions & 0 deletions capabilities/vuln-assessment-methodology/capability.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
schema: 1
name: vuln-assessment-methodology
version: "1.0.0"
description: >
Cross-cutting methodology for vulnerability assessment. Provides
source-to-sink tracing discipline, disprove-first analysis,
threat-model-aware severity assignment, three-tier confidence
classification, attack chain analysis, CWE mapping, remediation
quality standards, root-cause deduplication, scope documentation,
and opt-in proof-of-concept validation. Load alongside any
domain-specific security capability to reduce false positives
and severity inflation.

author:
name: Dreadnode
url: https://dreadnode.io
license: MIT
repository: https://github.com/dreadnode/capabilities
keywords:
- vulnerability-assessment
- methodology
- security
- false-positive-prevention
- severity-calibration
- confidence-levels
- cwe
- remediation
Loading
Loading