Skip to content
Snippets Groups Projects
Commit 332580b8 authored by Yang Liu's avatar Yang Liu
Browse files

Done:

1. Finished InputGenerator, now it can generate inputs for all 6 commands.
2. Changed the ascii range to 33 to 126(both inclusive), to avoid errors with some strange symbols
3. Fixed a bug when random arguments are longer than the input buffer size, some spaces between arguments can be ignored, resulting exit due to wrong number of arguments. Now all spaces will be generated within the buffer size range.
4. Some refactor and small bug fix.
parent 34093087
No related branches found
No related tags found
1 merge request!8Yuqiang vulnerabilities
import java.util.*;
import java.util.stream.Collectors;
/**
* A string generator to generate various inputs for the Fuzzer
......@@ -8,7 +7,7 @@ public class InputGenerator {
// the chars range used to generate inputs, left inclusive, right exclusive
// 0 is skipped since it will terminate a c string
private static final int[] ASCII_RANGE = new int[] {1, 128};
private static final int[] ASCII_RANGE = new int[] {33, 127};
// how many args for the put command
private static final int NUM_PUT_ARGS = 3;
......@@ -21,12 +20,20 @@ public class InputGenerator {
private static final int INVALID_NUM_ARGUMENTS_MULTIPLIER = 10;
// how likely the generated commands will have valid number of arguments
// it will be a change of: when random.newInt(rate) != 0 for all nun-valid arg num commands to reroll
// it will be a chance of: when random.newInt(rate) != 0 for all nun-valid arg num commands to reroll
private static final int VALID_NUM_ARGUMENT_SKEW_RATE = 3;
// how likely the generated GET commands will be asking for existing entries generated by PUT
// the probability will be rate/(rate+1)
private static final int GET_EXISTING_ENTRY_SKEW_RATE = 1;
// avoid these chars in the randomly generated strings
private static final int[] AVOIDED_ASCII_IDX = new int[] {9, 10, 13, 32};
// if set to true, will only generate commands with valid number of arguments
// currently it seems incorrect number of arguments will end the passbook, so this is set to true
private static final boolean ALWAYS_USE_CORRECT_NUM_ARGS = true;
// max length of an input line
private int maxInputLineLength;
// random generator instance
......@@ -36,6 +43,10 @@ public class InputGenerator {
// skipped ascii index for symbol not included in the random generated strings
private Set<Integer> avoidedAsciiIndexSet;
/**
* base constructor
* @param maxInputLineLength the size of input buffer for target program
*/
public InputGenerator(int maxInputLineLength) {
this.maxInputLineLength = maxInputLineLength;
this.random = new Random();
......@@ -46,22 +57,183 @@ public class InputGenerator {
}
}
public Map<String, Pair<String, String>> getValidPassbookEntries() {
return validPassbookEntries;
/**
* generate multiple random PUT commands
* @param numCommands number of commands to generate
* @return all the commands generated
*/
public ArrayList<String> generatePut(int numCommands) {
return generateCommands(Instruction.PUT, numCommands);
}
/**
* generate multiple random put commands
* it will generate valid and invalid commands (different number of arguments for the put)
* generate multiple random REM commands
* @param numCommands number of commands to generate
* @return all the put commands generated
* @return all the commands generated
*/
public ArrayList<String> generatePut(int numCommands) {
ArrayList commands = generateCommands(Instruction.PUT, numCommands);
public ArrayList<String> generateRem(int numCommands) {
return generateUrlBasedCommands(Instruction.REM, numCommands);
}
/**
* generate multiple random GET commands
* @param numCommands number of commands to generate
* @return all the commands generated
*/
public ArrayList<String> generateGet(int numCommands) {
return generateUrlBasedCommands(Instruction.GET, numCommands);
}
/**
* generate multiple random LIST commands
* @param numCommands number of commands to generate
* @return all the commands generated
*/
public ArrayList<String> generateList(int numCommands) {
return generateCommands(Instruction.LIST, numCommands);
}
/**
* generate multiple random SAVE commands
* @param numCommands number of commands to generate
* @return all the commands generated
*/
public ArrayList<String> generateSave(int numCommands) {
return generateCommands(Instruction.SAVE, numCommands);
}
/**
* generate multiple random MASTERPW commands
* each 'masterpw password' will be followed by the password itself.
* @param numCommands number of commands to generate
* @return all the commands generated
*/
public ArrayList<String> generateMasterpw(int numCommands) {
ArrayList<String> prompts = generateCommands(Instruction.MASTERPW, numCommands);
// make sure the generate pw is entered after the commands, otherwise the program will exit
ArrayList<String> commands = new ArrayList<>();
for (String prompt : prompts) {
String pw = prompt.split(" ")[1];
// trim a bit in case the pw is too long and only part of it is registered in the buffer
// this has to take into account of the length of 'masterpw ' part in the front
int maxPwLength = maxInputLineLength - Instruction.MASTERPW.getOpcode().length() - 2;
if (pw.length() > maxPwLength) {
pw = pw.substring(0, maxPwLength);
}
commands.add(prompt);
commands.add(pw);
}
return commands;
}
/**
* generate multiple random commands based on url as the first argument, so stored url
* generated by 'put' can be tested
* currently these commands are just 'rem' and 'get'
* @param command the Instruction
* @param numCommands number of commands to generate
* @param noMutateRatio see mutateRandomCmdWithValidUrl()
* @param attachRatio see mutateRandomCmdWithValidUrl()
* @param replaceRatio see mutateRandomCmdWithValidUrl()
* @return generated commands
*/
private ArrayList<String> generateUrlBasedCommands(Instruction command, int numCommands,
int noMutateRatio,
int attachRatio,
int replaceRatio) {
// if no stored entries, generate random ones
if (validPassbookEntries.isEmpty()) {
return generateCommands(command, numCommands);
}
// otherwise, generate a mix 'get' of both stored and random urls
int mode = random.nextInt(1 + GET_EXISTING_ENTRY_SKEW_RATE);
ArrayList<String> commands = new ArrayList<>();
if (mode == 0) {
ArrayList<String> randomCommands = generateCommands(command, numCommands);
return mutateRandomCmdWithValidUrl(randomCommands, noMutateRatio, attachRatio, replaceRatio);
} else {
List<Object> urls = Arrays.asList(validPassbookEntries.keySet().toArray());
for (int i = 0; i < numCommands; i++) {
int idx = random.nextInt(urls.size());
String url = (String) urls.get(idx);
commands.add(command.getOpcode() + " " + url);
}
return commands;
}
}
// overload with default arguments
private ArrayList<String> generateUrlBasedCommands(Instruction command, int numCommands) {
return generateUrlBasedCommands(command, numCommands, 1, 1, 1);
}
/**
* mutate the random commands, make some of them to have part of a stored url
* currently have 3 random cases:
* 0. no change
* 1. attach a stored url to the first argument, e.g. we have a url of --url1--, and the
* random command is 'get abcde ff', the result will be 'get --url1--abcde ff'
* 2. replace the first argument with a stored url. the result of the above example will
* become 'get --url1-- ff'
* used by commands that are based on urls generated by PUT
* @param randomCommands total random commands
* @param noMutateRatio ratio of case 0
* @param attachRatio ratio of case 1
* @param replaceRatio ratio of case 2
* @return the commands, with some of them mutated
*/
private ArrayList<String> mutateRandomCmdWithValidUrl(ArrayList<String> randomCommands,
int noMutateRatio,
int attachRatio,
int replaceRatio) {
int totalRatio = noMutateRatio + attachRatio + replaceRatio;
if (totalRatio == 0) {
return randomCommands;
}
ArrayList<String> mutatedCommands = new ArrayList<>();
for (String cmd : randomCommands) {
int mode = random.nextInt(totalRatio);
if (validPassbookEntries.isEmpty() || mode < noMutateRatio) {
// case 0: no mutation
mutatedCommands.add(cmd);
} else if (mode < noMutateRatio + attachRatio) {
// case 1: attach an valid url to the first argument
String[] cmdArray = cmd.split(" ");
String mutatedCmd = cmd;
if (cmdArray.length > 1) {
cmdArray[1] = getRandomUrlFromStored() + cmdArray[1];
mutatedCmd = String.join(" ", cmdArray);
}
mutatedCommands.add(mutatedCmd);
} else {
// case 2: replace the first argument with valid url
String[] cmdArray = cmd.split(" ");
String mutatedCmd = cmd;
if (cmdArray.length > 1) {
cmdArray[1] = getRandomUrlFromStored();
mutatedCmd = String.join(" ", cmdArray);
}
mutatedCommands.add(mutatedCmd);
}
}
return mutatedCommands;
}
/**
* obtain a random stored url form recorded validPassbookEntries
* @return the url
*/
private String getRandomUrlFromStored() {
if (validPassbookEntries.isEmpty()) {
return "";
}
Object[] urls = validPassbookEntries.keySet().toArray();
int idx = random.nextInt(urls.length);
return (String) urls[idx];
}
/**
* generate multiple random given commands, with randomness in number of arguments and input length
* @param command the command
......@@ -105,6 +277,11 @@ public class InputGenerator {
}
}
// overwrite mode to be valid number of args if set to be.
if (ALWAYS_USE_CORRECT_NUM_ARGS) {
mode = numValidArgs;
}
if (mode == 0) {
return output;
}
......@@ -113,8 +290,9 @@ public class InputGenerator {
}
String randomLengthString = generateRandomLengthString(mode, maxInputLineLength);
ArrayList<String> argumentsList = stringSeparator(randomLengthString, mode);
// retry if failed for some reason
if (argumentsList == null) {
return output;
return generateArgsWithCommand(command, numValidArgs);
}
String arguments = String.join(" ", argumentsList);
output += " ";
......@@ -192,7 +370,8 @@ public class InputGenerator {
// get (numSections - 1) distinct int with the input length as separating points
Set<Integer> separationPointsSet = new HashSet<>();
while (separationPointsSet.size() < numSections - 1) {
int separationPoint = random.nextInt(input.length() - 1) + 1;
// make sure all the separators are within the range of input buffer
int separationPoint = random.nextInt(Math.min(input.length(), maxInputLineLength) - 1) + 1;
separationPointsSet.add(separationPoint);
}
......@@ -212,4 +391,13 @@ public class InputGenerator {
return separatedStrings;
}
/**
* get the stored valid entries
* @return this.validPassbookEntries
*/
Map<String, Pair<String, String>> getValidPassbookEntries() {
return validPassbookEntries;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment