augure 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +136 -0
- data/LICENSE +21 -0
- data/README.md +217 -0
- data/exe/augure +181 -0
- data/exe/augure-benchmark +67 -0
- data/home/runner/work/augure/augure/docs/agent-snippet.md +31 -0
- data/home/runner/work/augure/augure/docs/auditability.md +160 -0
- data/home/runner/work/augure/augure/docs/build-format.md +119 -0
- data/home/runner/work/augure/augure/docs/explanation-architecture.md +74 -0
- data/home/runner/work/augure/augure/docs/how-to-swap-solver.md +73 -0
- data/home/runner/work/augure/augure/docs/how-to-write-rules.md +71 -0
- data/home/runner/work/augure/augure/docs/pack-format.md +137 -0
- data/home/runner/work/augure/augure/docs/reference.md +293 -0
- data/home/runner/work/augure/augure/docs/tutorial.md +108 -0
- data/home/runner/work/augure/augure/examples/ret2win.facts +11 -0
- data/home/runner/work/augure/augure/examples/split.facts +12 -0
- data/home/runner/work/augure/augure/exe/augure +181 -0
- data/home/runner/work/augure/augure/exe/augure-benchmark +67 -0
- data/home/runner/work/augure/augure/lib/augure/bandit.rb +118 -0
- data/home/runner/work/augure/augure/lib/augure/coverage.rb +56 -0
- data/home/runner/work/augure/augure/lib/augure/ctf_corpus.json +773 -0
- data/home/runner/work/augure/augure/lib/augure/engine.rb +128 -0
- data/home/runner/work/augure/augure/lib/augure/facts.rb +194 -0
- data/home/runner/work/augure/augure/lib/augure/kb_corpus.json +345 -0
- data/home/runner/work/augure/augure/lib/augure/knowledge_base.rb +109 -0
- data/home/runner/work/augure/augure/lib/augure/mcts.rb +178 -0
- data/home/runner/work/augure/augure/lib/augure/pack.rb +244 -0
- data/home/runner/work/augure/augure/lib/augure/pack_loader.rb +93 -0
- data/home/runner/work/augure/augure/lib/augure/parity.rb +69 -0
- data/home/runner/work/augure/augure/lib/augure/pipeline.rb +107 -0
- data/home/runner/work/augure/augure/lib/augure/priors.rb +32 -0
- data/home/runner/work/augure/augure/lib/augure/rules.rb +300 -0
- data/home/runner/work/augure/augure/lib/augure/smt_process.rb +48 -0
- data/home/runner/work/augure/augure/lib/augure/verifier.rb +40 -0
- data/home/runner/work/augure/augure/lib/augure/version.rb +5 -0
- data/home/runner/work/augure/augure/lib/augure.rb +25 -0
- data/home/runner/work/augure/augure/packs/banner_leak.yml +46 -0
- data/home/runner/work/augure/augure/packs/brop.yml +46 -0
- data/home/runner/work/augure/augure/packs/fastbin_hook.yml +45 -0
- data/home/runner/work/augure/augure/packs/got_partial_overwrite.yml +45 -0
- data/home/runner/work/augure/augure/packs/got_partial_overwrite_deref.yml +39 -0
- data/home/runner/work/augure/augure/packs/house_botcake.yml +38 -0
- data/home/runner/work/augure/augure/packs/house_force.yml +37 -0
- data/home/runner/work/augure/augure/packs/house_of_apple2.yml +45 -0
- data/home/runner/work/augure/augure/packs/house_orange.yml +38 -0
- data/home/runner/work/augure/augure/packs/jop.yml +39 -0
- data/home/runner/work/augure/augure/packs/large_bin_attack.yml +39 -0
- data/home/runner/work/augure/augure/packs/one_gadget.yml +38 -0
- data/home/runner/work/augure/augure/packs/orw.yml +55 -0
- data/home/runner/work/augure/augure/packs/ret2csu_v2.yml +55 -0
- data/home/runner/work/augure/augure/packs/ret2dlresolve_x86.yml +39 -0
- data/home/runner/work/augure/augure/packs/ret2partial_overwrite.yml +38 -0
- data/home/runner/work/augure/augure/packs/ret2vdso.yml +39 -0
- data/home/runner/work/augure/augure/packs/setcontext_srop.yml +46 -0
- data/home/runner/work/augure/augure/packs/uaf_tcache.yml +45 -0
- data/home/runner/work/augure/augure/packs/unsorted_bin_attack.yml +38 -0
- metadata +103 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Augure
|
|
4
|
+
# Thompson-sampling bandit over Beta posteriors. The prior table encodes the
|
|
5
|
+
# AG weight inversions ("humans overweight X, the data says underweight"):
|
|
6
|
+
# ret2plt (15, 5) vs the human prior that anchored on ROP chains.
|
|
7
|
+
class Bandit
|
|
8
|
+
# Beta(alpha, beta) arm. Sampling uses Marsaglia-Tsang gamma draws: if
|
|
9
|
+
# X ~ Gamma(a) and Y ~ Gamma(b) then X / (X + Y) ~ Beta(a, b). Ruby's
|
|
10
|
+
# stdlib has no Beta sampler; this is the standard construction.
|
|
11
|
+
class Arm
|
|
12
|
+
attr_reader :alpha, :beta
|
|
13
|
+
|
|
14
|
+
def initialize(alpha, beta, rng: Random.new)
|
|
15
|
+
@alpha = alpha.to_f
|
|
16
|
+
@beta = beta.to_f
|
|
17
|
+
@rng = rng
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def mean
|
|
21
|
+
@alpha / (@alpha + @beta)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def sample
|
|
25
|
+
x = gamma(@alpha)
|
|
26
|
+
y = gamma(@beta)
|
|
27
|
+
x / (x + y)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def record(success)
|
|
31
|
+
success ? @alpha += 1 : @beta += 1
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# Marsaglia-Tsang, shape >= 1 handled directly; shape < 1 via the
|
|
37
|
+
# boost transform.
|
|
38
|
+
def gamma(shape)
|
|
39
|
+
if shape < 1.0
|
|
40
|
+
u = non_zero
|
|
41
|
+
gamma(shape + 1.0) * u**(1.0 / shape)
|
|
42
|
+
else
|
|
43
|
+
d = shape - 1.0 / 3.0
|
|
44
|
+
c = 1.0 / Math.sqrt(9.0 * d)
|
|
45
|
+
loop do
|
|
46
|
+
x = gauss
|
|
47
|
+
v = (1.0 + c * x)**3
|
|
48
|
+
next if v <= 0
|
|
49
|
+
|
|
50
|
+
u = non_zero
|
|
51
|
+
return d * v if Math.log(u) < 0.5 * x * x + d * (1.0 - v + Math.log(v))
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def non_zero
|
|
57
|
+
u = @rng.rand until u && u > 0.0
|
|
58
|
+
u
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Box-Muller transform.
|
|
62
|
+
def gauss
|
|
63
|
+
loop do
|
|
64
|
+
u1 = non_zero
|
|
65
|
+
u2 = @rng.rand
|
|
66
|
+
r = Math.sqrt(-2.0 * Math.log(u1))
|
|
67
|
+
theta = 2.0 * Math::PI * u2
|
|
68
|
+
return r * Math.sin(theta)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
attr_reader :arms, :rng, :history
|
|
74
|
+
|
|
75
|
+
def initialize(priors: {}, rng: Random.new)
|
|
76
|
+
@rng = rng
|
|
77
|
+
@arms = {}
|
|
78
|
+
priors.each { |tech, (a, b)| @arms[tech] = Arm.new(a, b, rng: @rng) }
|
|
79
|
+
@history = []
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def arm(technique)
|
|
83
|
+
@arms[technique] ||= Arm.new(1, 1, rng: @rng)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def mean(technique)
|
|
87
|
+
arm(technique).mean
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Thompson sample, restricted to the verified techniques. Deterministic
|
|
91
|
+
# for a fixed rng seed.
|
|
92
|
+
def select(verified)
|
|
93
|
+
return nil if verified.empty?
|
|
94
|
+
|
|
95
|
+
verified.max_by { |t| arm(t).sample }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def rankings
|
|
99
|
+
@arms.keys.sort_by { |t| [-arm(t).mean, t] }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Prior-mean ranking restricted to the given techniques, stable order.
|
|
103
|
+
# This is the deterministic contract the corpus freezes; Thompson draws
|
|
104
|
+
# (select) are the online behavior on top of it.
|
|
105
|
+
def ranking_of(techniques)
|
|
106
|
+
techniques.each_with_index
|
|
107
|
+
.map { |t, i| [t, arm(t).mean, i] }
|
|
108
|
+
.sort_by { |(_, m, i)| [-m, i] }
|
|
109
|
+
.map { |(t, m, _)| [t, m] }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def feedback(technique, success)
|
|
113
|
+
arm(technique).record(success)
|
|
114
|
+
@history << {technique: technique, success: success}
|
|
115
|
+
self
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Augure
|
|
4
|
+
# The corpus read backwards (the defender side): re-decide every
|
|
5
|
+
# entry against a HARDENED fact set and report which techniques die,
|
|
6
|
+
# which survive. The auditability doc's "the model read backwards"
|
|
7
|
+
# as a command: flip nx/relro/canary/pie, watch the rules die, and
|
|
8
|
+
# the remaining applicable techniques are the attacker's next moves.
|
|
9
|
+
module Coverage
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# entries: corpus-shaped ({suite:, name:, facts:}). flips: {predicate
|
|
13
|
+
# => value-or-nil} - a value REPLACES every existing fact of that
|
|
14
|
+
# predicate (hardening is an override); nil REMOVES them (the
|
|
15
|
+
# speculative turn-off).
|
|
16
|
+
def report(entries, flips:, priors: nil)
|
|
17
|
+
priors ||= Pipeline.default_priors
|
|
18
|
+
out = {entries: [], died: {}, gained: {}, survived_count: 0}
|
|
19
|
+
Array(entries).each do |entry|
|
|
20
|
+
facts = Facts.parse(entry["facts"])
|
|
21
|
+
before = Pipeline.analyze(facts: facts, priors: priors, plan: false)[:applicable]
|
|
22
|
+
hardened = with_flips(facts, flips)
|
|
23
|
+
after = Pipeline.analyze(facts: hardened, priors: priors, plan: false)[:applicable]
|
|
24
|
+
lost = before - after
|
|
25
|
+
found = after - before
|
|
26
|
+
lost.each { |t| out[:died][t] = out[:died].fetch(t, 0) + 1 }
|
|
27
|
+
found.each { |t| out[:gained][t] = out[:gained].fetch(t, 0) + 1 }
|
|
28
|
+
out[:survived_count] += 1 if before == after
|
|
29
|
+
out[:entries] << {suite: entry["suite"], name: entry["name"], before: before,
|
|
30
|
+
after: after, lost: lost, gained: found,
|
|
31
|
+
hardened_facts: hardened.to_s}
|
|
32
|
+
end
|
|
33
|
+
out
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Replace-or-remove every fact of a flipped predicate. The flip is
|
|
37
|
+
# the HARDENING decision: one value per predicate, decided by the
|
|
38
|
+
# operator, not appended noise.
|
|
39
|
+
def with_flips(facts, flips)
|
|
40
|
+
return facts if flips.nil? || flips.empty?
|
|
41
|
+
|
|
42
|
+
dropped = Facts.new
|
|
43
|
+
kept = Facts.new
|
|
44
|
+
facts.each do |(name, tuple)|
|
|
45
|
+
(flips.key?(name) ? dropped : kept).add(name, *tuple)
|
|
46
|
+
end
|
|
47
|
+
flips.each do |name, value|
|
|
48
|
+
next if value.nil?
|
|
49
|
+
|
|
50
|
+
arity = Facts::SCHEMA.fetch(name)
|
|
51
|
+
kept.add(name, *([value] * arity))
|
|
52
|
+
end
|
|
53
|
+
kept
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|