Beispiel #1
0
        public FuzzerRunViewModel(FuzzerRunEntity entity)
        {
            id         = entity.id;
            name       = entity.name;
            start_time = entity.start_time;
            end_time   = entity.end_time;

            Generations = new List <FuzzerGenerationViewModel>();
        }
Beispiel #2
0
 public void UpdateFuzzerRunEndTime(FuzzerRunEntity model)
 {
     using (var connection = GetConnection())
     {
         connection.Open();
         connection.Execute(
             @"UPDATE fuzzer_run
               SET end_time = @end_time 
               WHERE id = @id;", model);
     }
 }
Beispiel #3
0
 public void AddFuzzerRun(FuzzerRunEntity model)
 {
     using (var connection = GetConnection())
     {
         connection.Open();
         model.id = connection.Query <int>(
             @"INSERT INTO fuzzer_run
             ( start_time, end_time, name ) VALUES 
             ( @start_time, @end_time, @name )
             RETURNING id;", model).First();
     }
 }
Beispiel #4
0
        public async Task AddRequestSequence(RequestSequence sequence, FuzzerRunEntity run)
        {
            RequestSequenceEntity model = new RequestSequenceEntity();

            model.request_count      = sequence.StageCount();
            model.substitution_count = sequence.SubstitutionCount();
            model.run_id             = run.id.GetValueOrDefault(0);

            using (var connection = GetConnection())
            {
                connection.Open();

                model.id = connection.Query <int>(
                    @"INSERT INTO sequences
                    ( request_count, substitution_count, run_id ) VALUES 
                    ( @request_count, @substitution_count, @run_id )
                    RETURNING id;", model).First();

                foreach (SequenceMetadata meta in sequence.GetDebugMetadata())
                {
                    SequenceMetadataEntity metadata_entity =
                        new SequenceMetadataEntity {
                        sequence_id = model.id, content = meta.Content, type = meta.Type
                    };

                    connection.Execute(@"INSERT INTO sequence_metadata 
                                         ( sequence_id, type, content ) VALUES
                                         ( @sequence_id, @type, @content );", metadata_entity);
                }
            }

            sequence.Id = model.id;

            List <Response>?results = sequence.GetResponses();

            if (results != null && results.Count == sequence.StageCount())
            {
                for (int i = 0; i < sequence.StageCount(); ++i)
                {
                    Request       request      = sequence.Get(i).Request;
                    RequestEntity requestModel = RequestEntity.FromRequest(request);
                    requestModel.sequence_id       = model.id;
                    requestModel.sequence_position = i;
                    AddExecutedRequest(requestModel);
                    request.Id = requestModel.id;

                    Response       response      = results[i];
                    ResponseEntity responseModel = ResponseEntity.FromResponse(response);
                    responseModel.sequence_id       = model.id;
                    responseModel.sequence_position = i;
                    AddResponse(responseModel);
                    response.Id = responseModel.id;

                    foreach (ISubstitution sub in sequence.Get(i).Substitutions)
                    {
                        SubstitutionEntity subModel = SubstitutionEntity.FromSubstitution(sub);
                        subModel.sequence_id       = model.id;
                        subModel.sequence_position = i;
                        AddSubstitution(subModel);
                    }
                }

                if (sequence.GetLastResponse() != null)
                {
                    int statusCode = (int)sequence.GetLastResponse().Status;
                    RequestSequenceLabelEntity labelEntity = new RequestSequenceLabelEntity();
                    labelEntity.sequence_id = model.id.Value;
                    if (statusCode >= 100 && statusCode < 200)
                    {
                        labelEntity.name = "Informational";
                    }
                    else if (statusCode >= 200 && statusCode < 300)
                    {
                        labelEntity.name = "Success";
                    }
                    else if (statusCode >= 300 && statusCode < 400)
                    {
                        labelEntity.name = "Redirection";
                    }
                    else if (statusCode >= 400 && statusCode < 500)
                    {
                        labelEntity.name = "Client Error";
                    }
                    else if (statusCode >= 500 && statusCode < 600)
                    {
                        labelEntity.name = "Server Error";
                    }
                    else
                    {
                        labelEntity.name = "Unknown Status";
                    }
                    await AddRequestSequenceLabel(labelEntity);
                }
            }
            else
            {
                Console.WriteLine("Warning: Truncated request sequence.");
            }
        }
Beispiel #5
0
        public static async Task Fuzz(JObject config)
        {
            // Set up a database connection to store the results.
            // TODO: Move this hardcoded connection string to a config file.
            FuzzerRepository databaseHelper = new FuzzerRepository("Server=db;Database=riverfuzz;Port=5432;User Id=postgres;Password='******';");

            if (config.Value <bool?>("ResetDatabase") ?? false)
            {
                databaseHelper.InitializeDatabase();
            }

            // Set up HttpClient.
            HttpClientHandler handler = new HttpClientHandler();

            handler.UseCookies        = false;
            handler.AllowAutoRedirect = false;
            HttpClient client = new HttpClient(handler);

            client.Timeout = TimeSpan.FromMilliseconds(1000);

            // Load all response tokenizers.
            List <IResponseTokenizer> responseTokenizers = new List <IResponseTokenizer>();

            responseTokenizers.Add(new JsonTokenizer());
            responseTokenizers.Add(new BearerTokenizer());
            responseTokenizers.Add(new HtmlFormTokenizer());
            responseTokenizers.Add(new CookieTokenizer());

            // Load all request tokenizers.
            List <IRequestTokenizer> requestTokenizers = new List <IRequestTokenizer>();

            requestTokenizers.Add(new JsonTokenizer());
            requestTokenizers.Add(new QueryTokenizer());
            requestTokenizers.Add(new BearerTokenizer());
            requestTokenizers.Add(new KnownUrlArgumentTokenizer());
            requestTokenizers.Add(new HtmlFormTokenizer());
            requestTokenizers.Add(new CookieTokenizer());

            TokenCollection startingData = new TokenCollection();

            // Generators take a sequence and modify it.
            List <IGenerator> generators = new List <IGenerator>();

            generators.Add(new BestKnownMatchGenerator());
            generators.Add(new RemoveTokenGenerator(5));

            List <string> dictionary = await databaseHelper.GetAllDictionaryEntries();

            generators.Add(new DictionarySubstitutionGenerator(dictionary, 10));

            // Parse the list of endpoints we should include in this run, then load them.
            DatabaseLoader       databaseParse = new DatabaseLoader(databaseHelper, config.Value <string>("Target"));
            List <int>           endpointIds   = config["TargetEndpoints"].Select(x => (int)x).ToList();
            List <KnownEndpoint> endpoints     = await databaseParse.LoadEndpointsById(endpointIds);

            // Add the endpoints to the population and set up bucketers.
            PopulationManager population = new PopulationManager();

            foreach (KnownEndpoint endpoint in endpoints)
            {
                endpoint.Tokenize(requestTokenizers, responseTokenizers);
                population.AddEndpoint(endpoint, new TokenNameBucketer());

                // If the endpoint is not already in the database, add it.
                if (endpoint.Request.Id == null)
                {
                    databaseHelper.AddEndpoint(KnownEndpointEntity.FromRequest(endpoint.Request));
                }
            }

            // Record the time we started this run.
            FuzzerRunEntity runInfo = new FuzzerRunEntity();

            runInfo.name       = config.Value <string?>("RunName") ?? "Untitled Fuzzer Run";
            runInfo.start_time = DateTime.Now;
            runInfo.end_time   = DateTime.MaxValue;
            databaseHelper.AddFuzzerRun(runInfo);

            // TimeSpan used to stop the fuzzer.
            TimeSpan  timeLimit = TimeSpan.FromMinutes(config.Value <int>("ExecutionTime"));
            Stopwatch runTime   = new Stopwatch();

            runTime.Start();

            // In each generation, we will:
            // 1: Generate a new set of viable sequences by mutating the existing population.
            // 2: Execute each viable sequence and caputure results.
            // 3: Bucket the results.
            // 4: Keep the shortest sequences from each bucket.
            // 5: Repeat with the new population.
            for (int generation = 0; runTime.ElapsedMilliseconds < timeLimit.TotalMilliseconds; generation++)
            {
                Console.WriteLine("\n\n----------------------------------------------------------------------------------");
                Console.WriteLine($"Generation {generation}");
                Console.WriteLine("----------------------------------------------------------------------------------");

                Stopwatch generationStopwatch = new Stopwatch();
                generationStopwatch.Start();

                int popCount     = population.Population.Count; // Store since we will be growing list.
                int requestCount = 0;                           // Used for performance measurement.

                // Loops over each existing seed sequence in the population.
                for (int seed = 0; seed < popCount; ++seed)
                {
                    // Combine the starting dictionary and the results of this request sequence.
                    List <TokenCollection> seedTokens;
                    if (population.Population[seed].GetResults() == null)
                    {
                        seedTokens = new List <TokenCollection>();
                        seedTokens.Add(new TokenCollection(startingData));
                    }
                    else
                    {
                        seedTokens = population.Population[seed].GetResults();
                    }

                    int candidateNumber = 0;
                    // Generate candidate request sequences by mutating that seed.
                    foreach (IGenerator generator in generators)
                    {
                        foreach (RequestSequence candidate in generator.Generate(population.Endpoints, population.Population[seed], seedTokens))
                        {
                            Stopwatch candidateStopwatch = new Stopwatch();
                            candidateStopwatch.Start();

                            // Execute the request sequence.
                            await candidate.Execute(client, responseTokenizers, startingData);

                            // Add a response to the population. If it looks interesting, we will look at it later.
                            population.AddResponse(candidate);

                            List <Response>?responses = candidate.GetResponses();
                            if (responses != null)
                            {
                                requestCount += responses.Count;
                            }

                            candidateStopwatch.Stop();

                            if (candidateStopwatch.ElapsedMilliseconds > 500)
                            {
                                Console.WriteLine($"\tWARNING: Long running candidate {candidateNumber++} completed in {candidateStopwatch.ElapsedMilliseconds}ms");
                            }
                        }
                    }
                }
                // await resetHelper.Reset(client);

                population.MinimizePopulation();

                generationStopwatch.Stop();
                Console.WriteLine($"Generation {generation} completed in {generationStopwatch.ElapsedMilliseconds}ms");

                FuzzerGenerationEntity genEntity = new FuzzerGenerationEntity {
                    population_size   = population.Population.Count,
                    run_position      = generation,
                    execution_time    = generationStopwatch.Elapsed,
                    executed_requests = requestCount,
                    run_id            = runInfo.id.Value
                };
                databaseHelper.AddFuzzerGeneration(genEntity);

                Console.WriteLine($"Population size: {population.Population.Count}");
                Console.WriteLine($"Requests per second: {requestCount / generationStopwatch.Elapsed.TotalSeconds}");
            }

            runInfo.end_time = DateTime.Now;
            databaseHelper.UpdateFuzzerRunEndTime(runInfo);

            foreach (RequestSequence sequence in population.Population)
            {
                Response?finalResponse = sequence.GetLastResponse();
                if (finalResponse != null)
                {
                    await databaseHelper.AddRequestSequence(sequence, runInfo);
                }
            }
        }