augure-profiler 0.0.1 → 0.0.2
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 68f4e4a0deb75c047b7a76b09695771e42a28d1b81a36d7ecabf211061022078
|
|
4
|
+
data.tar.gz: 178c357a361d80a14934c4d0fa871f545fbd0c680ab6708f47e0f6e486f5b2df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a78bc1cdb1adf17cc25ca268508d6462b47da49466ffdedd4bfdbaae2be694c2ba74898bc822f949c98ad076ca1071f776b7fe2be6a3bbf6b6ed97484f171729
|
|
7
|
+
data.tar.gz: f99e40af9b29d45c48dc1ae999f4c5b18403b251ce854b78a14b83ab50e58c5812878620c3668501e1357aae7368397838b3e25737516807a7d95ffd7d585c68
|
|
@@ -23,6 +23,7 @@ module AugureProfiler
|
|
|
23
23
|
["int80_ret", "cd 80 c3"], # int 0x80 ; ret
|
|
24
24
|
["pop_rdi_ret", "5f c3"], # pop rdi ; ret
|
|
25
25
|
["pop_rsi_ret", "5e c3"], # pop rsi ; ret
|
|
26
|
+
["pop_rsi_r15_ret", "5e 41 5f c3"], # pop rsi ; pop r15 ; ret (the callme flavor)
|
|
26
27
|
["pop_rdx_ret", "5a c3"], # pop rdx ; ret
|
|
27
28
|
["pop_rax_ret", "58 c3"], # pop rax ; ret
|
|
28
29
|
["JMP_STACK", "ff e4"], # jmp esp/rsp - renamed per arch
|
|
@@ -49,6 +50,34 @@ module AugureProfiler
|
|
|
49
50
|
facts
|
|
50
51
|
end
|
|
51
52
|
|
|
53
|
+
# the csu byte signatures, both known compiler flavors: the popper
|
|
54
|
+
# = pop rbx,rbp,r12,r13,r14,r15 ; ret (the chain re-enters at the
|
|
55
|
+
# pop rbx), the mov block ends in the csu call signature and starts
|
|
56
|
+
# 9 bytes earlier (three 3-byte register movs, REX.W/REX.WR 0x89
|
|
57
|
+
# opcodes - the mov order is the compiler's choice: r15->rdx on
|
|
58
|
+
# recent gcc, r13->rdx on the classic layout)
|
|
59
|
+
CSU_POPPER_BIN = ["5b5d415c415d415e415fc3"].pack("H*").freeze
|
|
60
|
+
CSU_CALL_BIN = ["41ff14dc"].pack("H*").freeze
|
|
61
|
+
|
|
62
|
+
def self.csu_gadget_addrs(bytes, base, extent)
|
|
63
|
+
win = bytes.is_a?(String) ? bytes.b : bytes.pack("C*").b
|
|
64
|
+
win = win.byteslice(0, extent) if extent && extent < win.bytesize
|
|
65
|
+
popper = win.index(CSU_POPPER_BIN)
|
|
66
|
+
mov = find_csu_mov(win)
|
|
67
|
+
{popper: popper ? base + popper : nil, mov: mov ? base + mov : nil}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.find_csu_mov(win)
|
|
71
|
+
off = 0
|
|
72
|
+
while (call = win.index(CSU_CALL_BIN, off))
|
|
73
|
+
start = call - 9
|
|
74
|
+
return start if start >= 0 && [0x4c, 0x44].include?(win.getbyte(start)) && win.getbyte(start + 1) == 0x89
|
|
75
|
+
|
|
76
|
+
off = call + 1
|
|
77
|
+
end
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
|
|
52
81
|
private
|
|
53
82
|
|
|
54
83
|
def emit_checksec(facts)
|
|
@@ -90,6 +119,10 @@ module AugureProfiler
|
|
|
90
119
|
# needs the address, not just the existence.
|
|
91
120
|
@elf.symbols.each do |sym|
|
|
92
121
|
next unless sym.name.to_s.match?(/\Awin\z|win\z|flag\z/)
|
|
122
|
+
# an IMPORT is not a win HERE: the ret2csu shape imports its
|
|
123
|
+
# ret2win from the companion library; the symbol's value is 0
|
|
124
|
+
# and a built [qword win] payload would jump to NULL
|
|
125
|
+
next if sym.shndx.to_s == "UNDEF"
|
|
93
126
|
|
|
94
127
|
facts.add("target_function", "true")
|
|
95
128
|
facts.add("win_symbol", sym.name, sym.value.to_i)
|
|
@@ -189,15 +222,39 @@ module AugureProfiler
|
|
|
189
222
|
hits.map { |(_order, type, addr)| [type, addr] }
|
|
190
223
|
end
|
|
191
224
|
|
|
192
|
-
# Static binaries expose the __libc_csu_init universal gadgets
|
|
193
|
-
#
|
|
225
|
+
# Static binaries expose the __libc_csu_init universal gadgets; their
|
|
226
|
+
# presence IS the gadget fact. The two useful sequences sit at
|
|
227
|
+
# compiler-dependent offsets INSIDE the function (the entry/+0x40
|
|
228
|
+
# guess broke on the newer mov rdx,r15 flavor), so both are located
|
|
229
|
+
# by byte signature within the symbol's extent: the popper fact aims
|
|
230
|
+
# at the pop rbx (the chain entry, the leading add rsp,8 stays one
|
|
231
|
+
# slot earlier for layouts that need it), the mov block by its call
|
|
232
|
+
# signature. The pack teaches the arg mapping for its target.
|
|
194
233
|
def emit_csu_gadgets(facts)
|
|
195
|
-
names = @elf.symbols.map(&:name).compact
|
|
196
|
-
return unless names.include?("__libc_csu_init")
|
|
197
|
-
|
|
198
234
|
sym = @elf.symbols.find { |s| s.name == "__libc_csu_init" }
|
|
199
|
-
|
|
200
|
-
|
|
235
|
+
return unless sym
|
|
236
|
+
|
|
237
|
+
base = sym.value.to_i
|
|
238
|
+
extent = sym.size.to_i
|
|
239
|
+
extent = 0x100 if extent <= 0
|
|
240
|
+
section = executable_sections.find do |s|
|
|
241
|
+
s.addr.to_i <= base && base < s.addr.to_i + s.size.to_i
|
|
242
|
+
end
|
|
243
|
+
return unless section
|
|
244
|
+
|
|
245
|
+
window = bytes_slice(section, base - section.addr.to_i)
|
|
246
|
+
return if window.nil? || window.empty?
|
|
247
|
+
|
|
248
|
+
addrs = self.class.csu_gadget_addrs(window, base, extent)
|
|
249
|
+
facts.add("gadget", "csu_popper", addrs[:popper]) if addrs[:popper]
|
|
250
|
+
facts.add("gadget", "csu_mov", addrs[:mov]) if addrs[:mov]
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def bytes_slice(section, from)
|
|
254
|
+
bytes = section_bytes(section)
|
|
255
|
+
return nil if bytes.nil?
|
|
256
|
+
|
|
257
|
+
bytes[from, bytes.size - from] || []
|
|
201
258
|
end
|
|
202
259
|
end
|
|
203
260
|
end
|