본문 바로가기
정보보안/fuzzing

[TheFuzzingBook] Breaking Things with Random Inputs

by meanjung 2022. 1. 28.

Runner 클래스

  • PUT 자체라고 볼 수 있음.
  • 어떤 랜덤값을 실행하기 위해 임의로 뭔가 동작을 하는 프로그램

 

Fuzzer 클래스

  • 랜덤한 문자열을 생성해서 fuzz()
  • Runner 클래스에서 실행시키기
from typing import Dict, Tuple, Union, List, Any
import random, os, tempfile, subprocess

Outcome = str

#################################################
### Runner ######################################
#################################################
class Runner:

    PASS = "PASS"
    FAIL = "FAIL"
    UNRESOLVED = "UNRESOLVED"

    def __init__(self) -> None:
        pass
    def run(self, inp: str) -> Any:
        return (inp, Runner.UNRESOLVED)


class PrintRunner(Runner):
    
    def run(self, inp) -> Any:
        print(inp)
        return (inp, Runner.UNRESOLVED)


class ProgramRunner(Runner):

    def __init__(self, program: Union[str, List[str]]) -> None:
        self.program = program

    def run_process(self, inp: str = "") -> subprocess.CompletedProcess:
        return subprocess.run(self.program,
                              input=inp,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE,
                              universal_newlines=True)

    def run(self, inp: str = "") -> Tuple[subprocess.CompletedProcess, Outcome]:
        result = self.run_process(inp)

        if result.returncode == 0:
            outcome = self.PASS
        elif result.returncode < 0:
            outcome = self.FAIL
        else:
            outcome = self.UNRESOLVED

        return (result, outcome)

class BinaryProgramRunner(ProgramRunner):
    def run_process(self, inp: str = "") -> subprocess.CompletedProcess:
        return subprocess.run(self.program,
                              input=inp.encode(),
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)

cat = ProgramRunner(program="cat")


#################################################
### Fuzzer ######################################
#################################################

class Fuzzer:
    def __init__(self) -> None:
        pass

    # 랜덤한 문자열 생성
    def fuzz(self) -> str:
        return ""

    # fuzz()에서 생성한 랜덤한 문자열 Runner에서 실행
    def run(self, runner: Runner = Runner()) -> Tuple[subprocess.CompletedProcess, Outcome]:
        return runner.run(self.fuzz())

    def runs(self, runner: Runner = PrintRunner(), trials: int = 10)-> List[Tuple[subprocess.CompletedProcess, Outcome]]:
        outcomes = []
        for i in range(trials):
            outcomes.append(self.run(runner))
        return outcomes

class RandomFuzzer(Fuzzer):
    def __init__(self, min_length: int = 10, max_length: int = 100,
                 char_start: int = 32, char_range: int = 32) -> None:
        self.min_length = min_length
        self.max_length = max_length
        self.char_start = char_start
        self.char_range = char_range

    def fuzz(self) -> str:
        string_length = random.randrange(self.min_length, self.max_length + 1)
        out = ""
        for i in range(0, string_length):
            out += chr(random.randrange(self.char_start,
                                        self.char_start + self.char_range))
        return out

random_fuzzer = RandomFuzzer(min_length=20, max_length=20)

# for i in range(10):
#     inp = random_fuzzer.fuzz()
#     result, outcome = cat.run(inp)
#     assert result.stdout == inp
#     assert outcome == Runner.PASS

random_fuzzer.runs(cat, 10)

댓글