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
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
run: dotnet restore ${{ env.SOLUTION_NAME }}

- name: Build (Release)
run: dotnet build ${{ env.SOLUTION_NAME }} --configuration Release --no-restore /p:TreatWarningsAsErrors=true
run: dotnet build ${{ env.SOLUTION_NAME }} --configuration Release --no-restore

- name: Run Tests
run: dotnet test ${{ env.SOLUTION_NAME }} --configuration Release --no-build --verbosity normal --logger "trx;LogFileName=test-results-${{ matrix.os }}.trx"
Expand Down Expand Up @@ -90,7 +90,7 @@ jobs:

# 2. Code Formatting (Enforce Style)
- name: Verify Formatting
run: dotnet format ${{ env.SOLUTION_NAME }} --verbosity diagnostic || echo "⚠️ Formatting issues found, but ignored for now."
run: dotnet format ${{ env.SOLUTION_NAME }} --verify-no-changes --verbosity diagnostic --exclude ./modules

# 3. CodeQL Analysis
- name: Initialize CodeQL
Expand Down
97 changes: 91 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,61 @@
![Architecture](https://img.shields.io/badge/Architecture-Composite-blue?style=for-the-badge)
![Build](https://img.shields.io/github/actions/workflow/status/JVBotelho/RASP.Net/build.yml?style=for-the-badge)
![Coverage](https://img.shields.io/codecov/c/github/JVBotelho/RASP.Net?style=for-the-badge)
[![Threat Model](https://img.shields.io/badge/📄_Threat_Model-Read-orange?style=for-the-badge)](docs/ATTACK_SCENARIOS.md)
[![Reverse Engineering](https://img.shields.io/badge/🕵️_Anti--Debug-Research-blueviolet?style=for-the-badge)](docs/REVERSE_ENGINEERING.md)
> **Runtime Application Self-Protection (RASP) for High-Scale .NET Services**
> *Defense that lives inside your application process, operating at the speed of code.*

> **Runtime Application Self-Protection (RASP) SDK for .NET 10.**
> *Active defense residing inside the application process.*
---

## 🎮 Why This Matters for Gaming Security

**The Problem**: Multiplayer game services process **millions of transactions per second**. Traditional WAFs introduce network latency and cannot see inside the encrypted gRPC payload or understanding game logic context.

**The Solution**: RASP.Net acts as a **last line of defense** inside the game server process. It instruments the runtime to detect attacks that bypass perimeter defenses, detecting logic flaws like item duplication exploits or economy manipulation.

**Key Engineering Goals:**
1. **Zero GC Pressure**: Security checks must NOT trigger Garbage Collection pauses that cause frame drops/lag.
2. **Sub-Microsecond Latency**: Checks happen in nanoseconds, not milliseconds.
3. **Defense in Depth**: Complements kernel-level Anti-Cheat (BattlEye/EAC) by protecting the backend API layer.

---

## ⚡ Performance Benchmarks

**Methodology:** Benchmarks isolate the intrinsic cost of the `SqlInjectionDetectionEngine` using `BenchmarkDotNet`.
**Hardware:** AMD Ryzen 7 7800X3D (4.2GHz) | **Runtime:** .NET 10.0.2

| Payload Size | Scenario | Mean Latency | Allocation | Verdict |
| :--- | :--- | :--- | :--- | :--- |
| **100 Bytes** | ✅ Safe Scan (Hot Path) | **4.3 ns** | **0 Bytes** | **Zero-Alloc** 🚀 |
| | 🛡️ Attack Detected | **202.0 ns** | 232 Bytes | Blocked |
| **1 KB** | ✅ Safe Scan (Hot Path) | **16.4 ns** | **0 Bytes** | **Zero-Alloc** 🚀 |
| | 🛡️ Attack Detected | **1,036 ns** | 232 Bytes | Blocked |
| **10 KB** | ✅ Safe Scan (Hot Path) | **141.0 ns** | **0 Bytes** | **Zero-Alloc** 🚀 |
| | ⚠️ Deep Inspection | **5,871 ns** | 0 Bytes | Suspicious |

> **Key Takeaway:**
> * **Hot Path Optimization:** For 99% of legitimate traffic (Safe Scan), the engine uses vectorized SIMD checks (`SearchValues<T>`), incurring negligible overhead (**~4ns**).
> * **Zero Allocation:** The inspection pipeline uses `stackalloc` and `Span<T>` buffers, ensuring **0 GC Pressure** during routine checks.
> * **Deep Inspection:** Only when suspicious characters (e.g., `'`, `--`) are detected does the engine perform full normalization, costing a few microseconds but protecting the app.

---

## 🛡️ Security Analysis & Threat Modeling

This repository contains professional-grade security documentation demonstrating **Purple Team** capabilities.

### 📄 [Threat Model & Attack Scenarios](docs/ATTACK_SCENARIOS.md)
A comprehensive STRIDE analysis of the Game Economy architecture.
- **Vectors**: gRPC SQL Injection, Protobuf Tampering, GC Pressure DoS.
- **Validation**: Python exploit walkthroughs and mitigation strategies.

### 🕵️ [Reverse Engineering & Anti-Tamper](docs/REVERSE_ENGINEERING.md)
A deep dive into the Native C++ Protection Layer.
- **Internals**: Analysis of `IsDebuggerPresent`, PEB manipulation, and timing checks.
- **Bypasses**: Documentation of known evasion techniques (ScyllaHide, Detours) to demonstrate adversarial thinking.
- **Roadmap**: Advanced heuristics (RDTSC/SEH) for Phase 2.

---

Expand All @@ -29,6 +81,39 @@ It is designed to develop and validate the Security SDK (`Rasp.*`) by instrument

---

## 🛡️ How It Works (Attack Flow)

```mermaid
sequenceDiagram
participant Attacker
participant gRPC as gRPC Gateway
participant RASP as 🛡️ RASP.Net
participant GameAPI as Game Service
participant DB as Database

Note over Attacker,RASP: 🔴 Attack Scenario: Item Duplication
Attacker->>gRPC: POST /inventory/add {item: "Sword' OR 1=1"}
gRPC->>RASP: Intercept Request

activate RASP
RASP->>RASP: ⚡ Zero-Alloc Inspection
RASP-->>Attacker: ❌ 403 Forbidden (Threat Detected)
deactivate RASP

Note over Attacker,DB: 🟢 Legitimate Scenario
Attacker->>gRPC: POST /inventory/add {item: "Legendary Sword"}
gRPC->>RASP: Intercept Request

activate RASP
RASP->>GameAPI: ✅ Clean - Forward Request
deactivate RASP

GameAPI->>DB: INSERT INTO inventory...
DB-->>GameAPI: Success
GameAPI-->>Attacker: 200 OK
```
---

## 🚀 Setup & Build

⚠️ **CRITICAL:** This repository relies on submodules. A standard clone will result in missing projects.
Expand All @@ -37,7 +122,7 @@ It is designed to develop and validate the Security SDK (`Rasp.*`) by instrument

Use the `--recursive` flag to fetch the Target Application code:
```bash
git clone --recursive https://github.com/YOUR_USERNAME/RASP.Net.git
git clone --recursive https://github.com/JVBotelho/RASP.Net.git
```

If you have already cloned without the flag:
Expand Down Expand Up @@ -94,9 +179,9 @@ The Composite Solution allows you to debug the SDK as if it were part of the app

## 🎯 Roadmap

- [ ] **Phase 1**: Setup & Vulnerability injection in Target App
- [ ] **Phase 2**: gRPC Interceptor with payload inspection
- [ ] **Phase 3**: EF Core Interceptor with SQL analysis
- [x] **Phase 1**: Setup & Vulnerability injection in Target App
- [x] **Phase 2**: gRPC Interceptor with payload inspection
- [ ] **Phase 3**: EF Core Interceptor with SQL analysis 🚧 **IN PROGRESS**
- [ ] **Phase 4**: Benchmarks & Documentation

---
Expand Down
48 changes: 48 additions & 0 deletions Rasp.Core.Tests/DependencyInjection/DiSanityTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using FluentAssertions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Rasp.Bootstrapper;

namespace Rasp.Core.Tests.DependencyInjection;

/// <summary>
/// Verifies the integrity of the Dependency Injection (DI) container configuration.
/// Ensures that all services and their dependencies are correctly registered and compatible.
/// </summary>
public class DiSanityTests
{
/// <summary>
/// Ensures that <see cref="RaspDependencyInjection.AddRasp"/> registers all required services
/// without missing dependencies or causing scope violations.
/// </summary>
[Fact]
public void AddRasp_Should_Register_All_Dependencies_Correctly()
{
// 1. Arrange
var services = new ServiceCollection();

var config = new ConfigurationBuilder().Build();

services.AddSingleton<IConfiguration>(config);
services.AddLogging();

services.AddGrpc();

// 2. Act
services.AddRasp(opt =>
{
opt.BlockOnDetection = true;
opt.EnableMetrics = false;
});

var options = new ServiceProviderOptions
{
ValidateOnBuild = true,
ValidateScopes = true
};

Action build = () => services.BuildServiceProvider(options);

build.Should().NotThrow("the RASP dependency graph must be complete and valid");
}
}
23 changes: 23 additions & 0 deletions Rasp.Core.Tests/Engine/Sql/SqlNormalizerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Rasp.Core.Engine.Sql;

namespace Rasp.Core.Tests.Engine.Sql;

public class SqlNormalizerTests
{
[Fact]
public void Normalize_WithSmallBuffer_ShouldTruncateAndNotThrow()
{
// Arrange
const string input = "SELECT * FROM Users WHERE id = 1"; // Length 32
Span<char> smallBuffer = stackalloc char[10]; // Only 10 chars capacity

// Act
// This should strictly fill only 10 chars and return 10, no IndexOutOfRangeException
int written = SqlNormalizer.Normalize(input, smallBuffer);
string result = smallBuffer[..written].ToString();

// Assert
Assert.Equal(10, written);
Assert.Equal("select * f", result); // Truncated result
}
}
43 changes: 43 additions & 0 deletions Rasp.Core.Tests/Engine/SqlInjectionDetectionEngineTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Microsoft.Extensions.Logging.Abstractions;
using Rasp.Core.Engine;
using Rasp.Core.Models;

namespace Rasp.Core.Tests;

public class SqlInjectionDetectionEngineTests
{
private readonly SqlInjectionDetectionEngine _sut; // System Under Test

public SqlInjectionDetectionEngineTests()
{
_sut = new SqlInjectionDetectionEngine(NullLogger<SqlInjectionDetectionEngine>.Instance);
}

[Theory]
[InlineData("O'Reilly")]
[InlineData("D'Angelo")]
[InlineData("L'oreal")]
[InlineData("McDonald's")]
[InlineData("Grand'Mère")]
public void Inspect_ShouldNotFlag_LegitimateNamesWithApostrophes(string safeInput)
{
// Act
var result = _sut.Inspect(safeInput);

// Assert
Assert.False(result.IsThreat, $"Falso positivo detectado! O nome legítimo '{safeInput}' foi bloqueado.");
}

[Theory]
[InlineData("admin' OR '1'='1")]
[InlineData("user' UNION SELECT")]
[InlineData("name'; DROP TABLE users --")]
public void Inspect_ShouldFlag_AttacksWithQuotes(string attackInput)
{
// Act
var result = _sut.Inspect(attackInput);

// Assert
Assert.True(result.IsThreat, $"Falso negativo! O ataque '{attackInput}' passou despercebido.");
}
}
3 changes: 3 additions & 0 deletions Rasp.Core.Tests/Rasp.Core.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4"/>
<PackageReference Include="FluentAssertions" Version="8.8.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1"/>
<PackageReference Include="xunit" Version="2.9.3"/>
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4"/>
Expand All @@ -19,6 +21,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\src\Rasp.Bootstrapper\Rasp.Bootstrapper.csproj" />
<ProjectReference Include="..\src\Rasp.Core\Rasp.Core.csproj" />
</ItemGroup>

Expand Down
Loading
Loading