diff --git a/Controller/Controller.cs b/Controller/Controller.cs index c16859f..4a5c1be 100644 --- a/Controller/Controller.cs +++ b/Controller/Controller.cs @@ -2,38 +2,20 @@ using System.Security.Claims; using System.Text; using System.Xml; -using Microsoft.AspNetCore.DataProtection; using Newtonsoft.Json; using System.IdentityModel.Tokens.Jwt; using Microsoft.IdentityModel.Tokens; -using Microsoft.Net.Http.Headers; -using static System.Runtime.InteropServices.JavaScript.JSType; -using System.Net; -using System.Net.Http; using System.Net.Http.Headers; -using System; -using System.Threading; -using Microsoft.AspNetCore.DataProtection.KeyManagement; -using static System.Net.Mime.MediaTypeNames; using System.Diagnostics; using System.Text.RegularExpressions; -using System.Diagnostics.Tracing; using Microsoft.CodeAnalysis.CSharp.Scripting; -using Microsoft.AspNetCore.Http; using System.Security.Cryptography; -using System.Linq.Dynamic.Core; -using static VulnerableWebApplication.VLAController.VLAController; -using Microsoft.AspNetCore.Mvc; using System.Xml.Linq; using System.Xml.Xsl; using VulnerableWebApplication.VLAModel; -using System.IO; using System.Runtime.InteropServices; using System.Web; -using System.Threading; -using System.Collections.Specialized; -using System.Linq.Dynamic.Core.Tokenizer; -using System.Reflection.PortableExecutable; + namespace VulnerableWebApplication.VLAController { @@ -282,18 +264,6 @@ Retourne le résultat de l'opération mathématique sur le chiffre donné en par return Result; } - public static object VulnerableNoSQL(string UserStr, string Token, string Secret) - { - /* - Retourne le résultat de la requête NoSQL fournie en paramètre - */ - if (!VulnerableValidateToken(Token, Secret)) return Results.Unauthorized(); - List Employees = Data.GetEmployees(); - var Query = Employees.AsQueryable(); - - return Results.Ok(Query.Where(UserStr).ToArray().ToString()); - } - public static async Task VulnerableHandleFileUpload(IFormFile UserFile, string Header, string Token, string Secret, string LogFile) { /* diff --git a/Model/Model.cs b/Model/Model.cs index 7c9aa1d..312e0a2 100644 --- a/Model/Model.cs +++ b/Model/Model.cs @@ -1,4 +1,6 @@ -using System.Data; +using GraphQL.Types; +using System.Data; +using GraphQL; namespace VulnerableWebApplication.VLAModel { @@ -29,22 +31,13 @@ public static string GetLogPage() /* Structure des journaux d'événements */ - return @" - - - -Application Logs - - -

Application Logs

- -"; + return @"Application Logs

Application Logs

"; } public static DataSet GetDataSet() { /* - Contenu de la BDD relationnelle + Contenu de la BDD relationnelle (Utilisateurs) */ DataTable table = new DataTable(); table.Columns.Add("User", typeof(string)); @@ -52,23 +45,143 @@ Contenu de la BDD relationnelle table.Rows.Add("root", "ce5ca673d13b36118d54a7cf13aeb0ca012383bf771e713421b4d1fd841f539a"); table.Rows.Add("admin", "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918"); table.Rows.Add("User", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + table.Rows.Add("Alice", "9b510b4af0d9b121f68d5a3400975047cbf38f963963b4c7510842d9d6310e7f"); + table.Rows.Add("Bob", "aed8f2deab14c36eeaa6d9c5c07ac6b586a74c18015dff9ac1cd0fc320f107b2"); + table.Rows.Add("Charlie", "99cdaf24cef97271760d72f0552ff18bb0c53e47d272cc1b3aa2c8b4e7d71b22"); + table.Rows.Add("Diana", "c27ab3e46131d5e15819aa5c919dca2c7d449a13a1293c9963e1a9d6181b51ac"); + table.Rows.Add("Edward", "3b179a52471e65a043a6c2b2dc1cb703165e2f94a8d4d3818b35eb278f730111"); + table.Rows.Add("Fiona", "31b6273952ff5ef238f5ef544a212eb434813782a279de537bf8c02ccc07fa08"); + table.Rows.Add("George", "27730420c3b86d8eb76e568be4e9279f69d5b00d625c2f0742d260ed9cc2ec26"); + table.Rows.Add("Hannah", "dc8fd3ef67d7031e81a8e2d088aceb430972e4ad03bfccafd063b5729ca0a139"); + table.Rows.Add("Ian", "0964e66cc96ed16adb6364caf1d0c80f80b91c9bf49aed3ffc0e51bca4dc0567"); + table.Rows.Add("Julia", "69ccc763a7a99e5ef616c760e8dcc90a96491cfd15ec84d61fbbf222474a9b3d"); var DataSet = new DataSet(); DataSet.Tables.Add(table); return DataSet; } + public static List GetEmployees() { /* - Contenu de la BDD non relationnelle + Contenu de la BDD non relationnelle (Employés) */ List Employees = new List() { - new Employee() { Id = "1", Name = "John", Age = 16, Address = "4 rue jean moulin"}, - new Employee() { Id = "42", Name = "Steve", Age = 21, Address = "3 rue Victor Hugo" }, - new Employee() { Id = "1000", Name = "Bill", Age = 18, Address = "4 place du 18 juin" } + new Employee() { Id = "1", Name = "John", Age = 16, Address = "4 rue jean moulin"}, + new Employee() { Id = "42", Name = "Steve", Age = 21, Address = "3 rue Victor Hugo" }, + new Employee() { Id = "1000", Name = "Bill", Age = 18, Address = "4 place du 18 juin" }, + new Employee() { Id = "1001", Name = "Alice", Age = 25, Address = "123 rue de la Paix" }, + new Employee() { Id = "1002", Name = "Bob", Age = 30, Address = "456 avenue des Champs-Élysées" }, + new Employee() { Id = "1003", Name = "Charlie", Age = 28, Address = "789 boulevard Saint-Germain" }, + new Employee() { Id = "1004", Name = "Diana", Age = 32, Address = "1010 rue du Faubourg Saint-Honoré" }, + new Employee() { Id = "1005", Name = "Edward", Age = 45, Address = "2020 avenue de la République" }, + new Employee() { Id = "1006", Name = "Fiona", Age = 29, Address = "3030 place de la Concorde" }, + new Employee() { Id = "1007", Name = "George", Age = 35, Address = "4040 rue de Rivoli" }, + new Employee() { Id = "1008", Name = "Hannah", Age = 27, Address = "5050 avenue Montaigne" }, + new Employee() { Id = "1009", Name = "Ian", Age = 40, Address = "6060 rue de la Boétie" }, + new Employee() { Id = "1010", Name = "Julia", Age = 22, Address = "7070 rue de Vaugirard" } }; return Employees; } + } + + /* + Classes et Query GraphQL (clients) + */ + public record Client(int Id, string Name, int Country); + public record Country(int Id, string Name); + + public class ClientDetails + { + public int Id { get; set; } + public string Name { get; set; } + public string Country { get; set; } + } + + public class ClientDetailsType : ObjectGraphType + { + public ClientDetailsType() + { + Field(x => x.Id); + Field(x => x.Name); + Field(x => x.Country); + } + } + + public interface IClientService + { + public List GetClients(); + public List GetClient(int empId); + public List GetClientsByCountry(int Country); + } + + public class ClientService : IClientService + { + public ClientService(){} + + private List Clients = new List + { + new Client(1, "NovaSynergy Solutions", 1), + new Client(2, "EcoVerde Innovations", 1), + new Client(3, "AstraTech Dynamics", 2), + new Client(4, "Luminara Creation", 2), + new Client(5, "ZenithWave Enterprises", 3), + }; + + private List Countrys = new List + { + new Country(1, "France"), + new Country(2, "Taïwan"), + new Country(3, "China"), + }; + + public List GetClients() + { + return Clients.Select(emp => new ClientDetails + { + Id = emp.Id, + Name = emp.Name, + Country = Countrys.First(d => d.Id == emp.Country).Name, + }).ToList(); + } + + public List GetClient(int empId) + { + return Clients.Where(emp => emp.Id == empId).Select(emp => new ClientDetails + { + Id = emp.Id, + Name = emp.Name, + Country = Countrys.First(d => d.Id == emp.Country).Name, + }).ToList(); + } + + public List GetClientsByCountry(int Country) + { + return Clients.Where(emp => emp.Country == Country).Select(emp => new ClientDetails + { + Id = emp.Id, + Name = emp.Name, + Country = Countrys.First(d => d.Id == Country).Name, + }).ToList(); + } + } + + public class ClientQuery : ObjectGraphType + { + public ClientQuery(IClientService ClientService) + { + Field>(Name = "Clients", resolve: x => ClientService.GetClients()); + Field>(Name = "Client", arguments: new QueryArguments(new QueryArgument { Name = "id" }), resolve: x => ClientService.GetClient(x.GetArgument("id"))); + } + } + + public class ClientDetailsSchema : Schema + { + public ClientDetailsSchema(IServiceProvider serviceProvider) : base(serviceProvider) + { + Query = serviceProvider.GetRequiredService(); + } } } + diff --git a/Program.cs b/Program.cs index 2ad62be..1dae57b 100644 --- a/Program.cs +++ b/Program.cs @@ -9,15 +9,29 @@ using VulnerableWebApplication.VLAModel; using VulnerableWebApplication.MidlWare; using Microsoft.AspNetCore.OpenApi; +using GraphQL.Types; +using GraphQL; // Configuration : var builder = WebApplication.CreateBuilder(args); + +// Swagger builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddAntiforgery(); +// GraphQL + +builder.Services.AddSingleton(); +builder.Services.AddSingleton(); +builder.Services.AddSingleton(); +builder.Services.AddSingleton(); +builder.Services.AddGraphQL(b => b + .AddAutoSchema() // schema + .AddSystemTextJson()); // serializer + builder.Services.AddHttpLogging(logging => { logging.LoggingFields = HttpLoggingFields.All; @@ -45,7 +59,6 @@ // Endpoints : - app.MapGet("/", async (string? lang) => await Task.FromResult(VLAController.VulnerableHelloWorld(HttpUtility.UrlDecode(lang)))); app.MapPost("/Auth", [ProducesResponseType(StatusCodes.Status200OK)] async (HttpRequest request, [FromBody] VulnerableWebApplication.VLAModel.Creds login) => await Task.FromResult(VLAController.VulnerableQuery(login.User, login.Passwd, Secret, LogFile)).Result).WithOpenApi(); @@ -60,9 +73,10 @@ app.MapGet("/Dns", async (string i, [FromHeader(Name="Authorization")] string t) => await Task.FromResult(VLAController.VulnerableCmd(HttpUtility.UrlDecode(i), t ,Secret))).WithOpenApi(); -app.MapGet("/NoSQL", async (string s, [FromHeader(Name="Authorization")] string t) => await Task.FromResult(VLAController.VulnerableNoSQL(HttpUtility.UrlDecode(s), t, Secret))).WithOpenApi(); +app.MapPatch("/Patch", async ([FromHeader(Name="X-Forwarded-For")] string h, [FromHeader(Name = "Authorization")] string t, [FromForm] IFormFile file) => await VLAController.VulnerableHandleFileUpload(file, h, t, Secret, LogFile)).DisableAntiforgery().WithOpenApi(); + +app.UseGraphQL("/GraphQL"); -app.MapPost("/Patch", async ([FromHeader(Name="X-Forwarded-For")] string h, [FromHeader(Name = "Authorization")] string t, [FromForm] IFormFile file) => await VLAController.VulnerableHandleFileUpload(file, h, t, Secret, LogFile)).DisableAntiforgery().WithOpenApi(); // Arguments : diff --git a/README.md b/README.md index e8fd09c..f61546c 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ | CWE-94 | Code Injection| Hard | 5.000-50.000$ | | CWE-91 | XML Injection | Hard | 0-500$ | | CWE-98 | Remote File Inclusion | Hard | 1.000-10.000$ | -| CWE-184 | Incomplete List of Disallowed Inputs | Hard | 1.000-10.000$| +| CWE-184 | Incomplete List of Disallowed Inputs | Medium | 1.000-10.000$ | | CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | Very Easy | 500-2.000$ | | CWE-284 | Improper Access Control | Medium | 1.000-5.000$ | | CWE-287 | Improper Authentication | Medium | 500-5.000$ | @@ -45,11 +45,13 @@ | CWE-1270 | Generation of Incorrect Security Tokens | Medium | 1.000-20.000$ | | CWE-1395 | Dependency on Vulnerable Third-Party Component | Easy | 0-500$ | + ## 🔑 Write Up * Become a project sponsor and gain access to all the solutions. * Or just buy me a coffee and get an unique Nuclei template (not for my students) +* ## 🏭 Context VLA is designed as a vulnerable backend application, running in the following environment : diff --git a/VulnerableWebApplication.csproj b/VulnerableWebApplication.csproj index 9b555e9..d4f06d1 100644 --- a/VulnerableWebApplication.csproj +++ b/VulnerableWebApplication.csproj @@ -8,12 +8,12 @@ + -