Deterministic protocol fuzzing core with native TCP/UDP execution and portable JSONL replay
///|
test "named request quick start" {
let request = @moon_boofuzz.CompiledRequest::compile(
@moon_boofuzz.Block::new("packet", [
Leaf("prefix", @moon_boofuzz.Field::simple(b"PING ", [])),
Leaf("value", @moon_boofuzz.Field::simple(b"ok", [b"", b"\x00\xff"])),
]),
)
assert_eq(request.render(), b"PING ok")
let cases = request.cases(limit=1)
assert_eq(cases.next().map(case => case.payload), Some(b"PING "))
assert_eq(cases.next(), None)
assert_eq(cases.state(), Limited)
let resumed = request.cases(start=cases.position())
assert_eq(resumed.next().map(case => case.payload), Some(b"PING \x00\xff"))
}///|
test "group field" {
let field = @moon_boofuzz.Field::group([b"GET", b"POST", b"GET"])
assert_eq(field.default_value(), b"GET")
assert_eq(field.num_mutations(), 2)
assert_eq(field.mutation(0), Some(b"POST"))
assert_eq(field.mutation(1), Some(b"GET"))
}///|
test "minimal byte request" {
let request = @moon_boofuzz.Request::new([
@moon_boofuzz.Static(b"PING "),
@moon_boofuzz.Choice(b"ok", [b"", b"long"]),
])
assert_eq(request.render(), b"PING ok")
assert_eq(request.mutations(), [b"PING ", b"PING long"])
}git clone https://github.com/GuoXBQ-Q/moon-boofuzz.git
cd moon-boofuzz
moon update
moon check --deny-warn
moon build
moon test --deny-warn
moon build --target native
moon test --target native --deny-warn
moon run --target native cmd/boofuzz -- generate examples/offline.json --limit 3moon test --target native --deny-warn -p cmd/boofuzz| 命令 | 输入与用途 | 主要选项 |
|---|---|---|
| generate | JSON 协议定义 → 变异载荷 JSONL,不连接目标 | --limit N、--start N、--id ID(需 --combinatorial false)、--combinatorial true|false、--max-depth N(组合深度上限);组合爆破默认开启(与上游 CLI 一致) |
| run | JSON 协议定义 → 逐例执行并保存实际流量 | 必填 --output FILE;可选 --limit N(缺省无上限,跑完为止)、--combinatorial true|false、--max-depth N、--start N、--end N、--sleep-between-ms N(用例间隔)、--text-dump true|false(逐例实时日志)、--db FILE(缺省自动写 boofuzz-results/run-<UTC时间戳>.db,与上游一致常开)、--record-passes N、--csv-out FILE、--web-port N(缺省 26000,与上游一致常开;0 为随机空闲端口)、--target-cmd CMD |
| open | 结果库/JSONL → 本地只读 Web 视图 | --ui-port N(默认 26000) |
| convert | Web 页面:粘贴原始 HTTP 报文 → 勾选分段并选择变异原语(字符串库/整数/二进制/随机/候选值)→ 自动生成协议定义 JSON(校验、用例数、载荷预览、复制/下载) | --ui-port N(默认 26001) |
| report | JSONL 执行记录 → 分类计数、失败身份和行号 | --max-bytes N |
| replay | JSONL 执行记录 → 按身份重放保存的字节 | 必填 --id ID,可选成对的 --host HOST --port PORT、--max-bytes N |
moon run --target native cmd/boofuzz -- run examples/tcp.json --output _build/tcp-cases.jsonl
moon run --target native cmd/boofuzz -- report _build/tcp-cases.jsonl
moon run --target native cmd/boofuzz -- replay _build/tcp-cases.jsonl --id '["packet"]/v1:packet.data:0'| 需求 | 文档 |
|---|---|
| 编写 JSON 协议、字段与读取策略 | DEFINITIONS.md |
| 用 Web 页面把 HTTP 报文转成定义 | CONVERT.md |
| 运行本地 HTTP fuzz 靶子(httpd) | HTTPD.md |
| 用 MoonBit 代码编写 fuzz 脚本 | 原生 MoonBit 完整示例、CODE.md、可执行 API 示例、MODEL.md |
| 配置前置路径和执行器 | SESSION.md、RUNNER.md |
| 响应检查、故障通知和恢复回调 | MONITORS.md |
| 理解日志、重放和退出码 | RECORDS.md、REPLAY.md、REPORT.md |
| 核对验收、兼容边界与许可 | ACCEPTANCE.md、UPSTREAM.md |
pub struct CaseStream {
request : CompiledRequest
limit : Int
skip : Int
ordinal : Int
emitted : Int
state : EnumerationState
stack : Array[StreamFrame]
combinatorial : Bool
units : Array[StreamUnit]
max_depth : Int?
depth : Int
depth_emitted : Int
frames : Array[CombFrame]
vars : Map[String, Bytes]?
}pub struct ChecksumSpec {
target : String
endian : Endian
mutations : Array[Bytes]
algorithm : ChecksumAlgorithm
}fn CompiledRequest::cases(self : CompiledRequest, start? : Int, limit? : Int, vars? : Map[String, Bytes]?) -> CaseStream raise ModelErrorfn CompiledRequest::cases_with_variables(self : CompiledRequest, vars : Map[String, Bytes]?, start? : Int, limit? : Int) -> CaseStream raise ModelErrorfn CompiledRequest::combinatorial_cases(self : CompiledRequest, start? : Int, limit? : Int, max_depth? : Int) -> CaseStream raise ModelErrorfn CompiledRequest::combinatorial_cases_with_variables(self : CompiledRequest, vars : Map[String, Bytes]?, start? : Int, limit? : Int, max_depth? : Int) -> CaseStream raise ModelErrorfn CompiledRequest::from_request(name : String, request : Request, max_bytes? : Int) -> CompiledRequest raise ModelErrorfn CompiledRequest::raw_prefix_before(self : CompiledRequest, path : String) -> Int64 raise ModelErrorfn CompiledRequest::render_case(self : CompiledRequest, parts : Array[(String, Int)], vars : Map[String, Bytes]?) -> Bytes raise ModelErrorfn CompiledRequest::render_with(self : CompiledRequest, vars : Map[String, Bytes]?) -> Bytes raise ModelErrorpub struct Field {
value : Bytes
count : Int
candidate : (Int) -> Bytes
candidate_length : (Int) -> Int64
}fn Field::binary(value : Bytes, size? : Int, max_len? : Int, padding? : Bytes, fuzzable? : Bool, fuzz_values? : Array[Bytes]) -> Field raise ModelErrorfn Field::float(default_value? : Double, s_format? : String, f_min? : Double, f_max? : Double, max_mutations? : Int, seed? : Int64, encode_as_ieee_754? : Bool, endian? : Endian, fuzzable? : Bool, fuzz_values? : Array[Bytes]) -> Field raise ModelErrorfn Field::from_lines(default_value? : Bytes, lines? : Array[Bytes], max_len? : Int, fuzzable? : Bool, fuzz_values? : Array[Bytes]) -> Field raise ModelErrorfn Field::group(values : Array[Bytes], default_value? : Bytes, fuzzable? : Bool, fuzz_values? : Array[Bytes]) -> Field raise ModelErrorfn Field::integer(value : UInt64, width? : Int, endian? : Endian, fuzzable? : Bool, fuzz_values? : Array[Bytes]) -> Field raise ModelErrorfn Field::random_data(default_value? : Bytes, min_length? : Int, max_length? : Int, max_mutations? : Int, step? : Int, fuzzable? : Bool, fuzz_values? : Array[Bytes]) -> Field raise ModelErrorpub(all) enum Node {
Leaf(String, Field)
Nested(Block)
Repeat(String, String, Int, Int, Int, String?)
Sized(String, SizeSpec)
Checksummed(String, ChecksumSpec)
Mirrored(String, String)
Dynamic(String, String, Field)
}fn Node::checksum(name : String, target : String, endian? : Endian, mutations? : Array[UInt], fuzzable? : Bool, algorithm? : ChecksumAlgorithm) -> Node raise ModelErrorpub struct SessionGraph {
requests : Array[CompiledRequest]
edges : Array[Array[Int]]
names : Map[String, Int]
edge_callbacks : Map[(Int, Int), (StepContext) -> Bytes?]
}fn SessionGraph::connect(self : SessionGraph, from : String, to : String, callback? : (StepContext) -> Bytes?) -> Unit raise ModelErrorfn SessionGraph::paths(self : SessionGraph, targets? : Array[String], max_paths? : Int) -> Array[SessionPath] raise ModelErrorpub struct SessionPath {
requests : Array[CompiledRequest]
transitions : Array[(StepContext) -> Bytes??]
}fn SessionPath::cases(self : SessionPath, start? : Int, limit? : Int, variables? : Map[String, Bytes]?) -> CaseStream raise ModelErrorfn SessionPath::cases_with_variables(self : SessionPath, vars : Map[String, Bytes]?, start? : Int, limit? : Int) -> CaseStream raise ModelErrorfn SessionPath::combinatorial_cases_with_variables(self : SessionPath, vars : Map[String, Bytes]?, start? : Int, limit? : Int, max_depth? : Int) -> CaseStream raise ModelErrorfn adler32(bytes : Bytes) -> UIntfn crc32(bytes : Bytes) -> UIntfn crc32c(bytes : Bytes) -> UIntfn ipv4_checksum(header : Bytes) -> UIntfn udp_checksum(source : Bytes, destination : Bytes, udp_bytes : Bytes) -> UIntInstall
Download zipDeterministic protocol fuzzing core with native TCP/UDP execution and portable JSONL replay