one_gadget 2.0.0 → 2.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +197 -65
  3. data/README.md +96 -22
  4. data/lib/one_gadget/abi.rb +41 -5
  5. data/lib/one_gadget/builds/libc-2.31-93b46e0027747153e336c3fd9431ce9a5d82ad00.rb +563 -0
  6. data/lib/one_gadget/builds/libc-2.35-891c1403437a4e30e684e0c8e34b87a09e4298e5.rb +434 -0
  7. data/lib/one_gadget/builds/libc-2.39-a1d1cf4badf1f5dfe57ff1d17bd692ccc6fcd5c5.rb +531 -0
  8. data/lib/one_gadget/builds/libc-2.39-cd8f5a207dd67aea370d2b471a54c3e56f44ab18.rb +531 -0
  9. data/lib/one_gadget/builds/libc-2.43-b50ceafbd17dc6bceee344a66671c7eaa152bef4.rb +15 -0
  10. data/lib/one_gadget/emulators/aarch64.rb +5 -2
  11. data/lib/one_gadget/emulators/amd64.rb +1 -0
  12. data/lib/one_gadget/emulators/arm.rb +27 -18
  13. data/lib/one_gadget/emulators/arm_family.rb +35 -160
  14. data/lib/one_gadget/emulators/conditional.rb +28 -22
  15. data/lib/one_gadget/emulators/constraints.rb +269 -0
  16. data/lib/one_gadget/emulators/data_processing.rb +167 -0
  17. data/lib/one_gadget/emulators/i386.rb +4 -6
  18. data/lib/one_gadget/emulators/instruction.rb +24 -1
  19. data/lib/one_gadget/emulators/lambda.rb +3 -1
  20. data/lib/one_gadget/emulators/mips.rb +289 -0
  21. data/lib/one_gadget/emulators/processor.rb +33 -455
  22. data/lib/one_gadget/emulators/register_file.rb +19 -10
  23. data/lib/one_gadget/emulators/riscv64.rb +265 -0
  24. data/lib/one_gadget/emulators/safe_calls.rb +9 -3
  25. data/lib/one_gadget/emulators/tracked_memory.rb +209 -0
  26. data/lib/one_gadget/emulators/x86.rb +32 -22
  27. data/lib/one_gadget/fetchers/aarch64.rb +0 -27
  28. data/lib/one_gadget/fetchers/amd64.rb +0 -24
  29. data/lib/one_gadget/fetchers/argument_resolution.rb +340 -0
  30. data/lib/one_gadget/fetchers/arm.rb +99 -44
  31. data/lib/one_gadget/fetchers/base.rb +142 -640
  32. data/lib/one_gadget/fetchers/candidate_walk.rb +150 -0
  33. data/lib/one_gadget/fetchers/disassembly.rb +252 -0
  34. data/lib/one_gadget/fetchers/dynamic_symbols.rb +104 -0
  35. data/lib/one_gadget/fetchers/i386.rb +5 -8
  36. data/lib/one_gadget/fetchers/mips.rb +478 -0
  37. data/lib/one_gadget/fetchers/objdump.rb +24 -2
  38. data/lib/one_gadget/fetchers/riscv64.rb +78 -0
  39. data/lib/one_gadget/fetchers/x86.rb +19 -0
  40. data/lib/one_gadget/fetchers.rb +22 -6
  41. data/lib/one_gadget/gadget.rb +25 -34
  42. data/lib/one_gadget/helper.rb +19 -5
  43. data/lib/one_gadget/one_gadget.rb +6 -0
  44. data/lib/one_gadget/version.rb +1 -1
  45. data/lib/one_gadget.rb +1 -1
  46. metadata +18 -6
  47. data/lib/one_gadget/builds/libc-2.26-2104f3d4ad5cf68603afbe7ba1a17f5ac99c5988.rb +0 -227
  48. data/lib/one_gadget/builds/libc-2.26-ddcc13122ddbfe5e5ef77d4ebe66d124ae5762c2.rb +0 -300
  49. data/lib/one_gadget/builds/libc-2.26-f65648a832414f2144ce795d75b6045a1ec2e252.rb +0 -199
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cce7f8fbd56224d205d4dc7fdd08f8d642ff586da671574ae44f29f4c1fd63d3
4
- data.tar.gz: edb152ef2e3a2cad812a4eb2561854552a40e826ceb770d5aa04d7003d2e20d6
3
+ metadata.gz: db6b57fdce4468596a6c52c7af146c6dafce4d98c2cc0e887f7e9cafee8ddb32
4
+ data.tar.gz: 6fce268e224fd67920694a1fd1ac2ae16f337f10abb3f3206bace11126a1abb7
5
5
  SHA512:
6
- metadata.gz: 10ec07de38a263a7ff7035e6ec97d47b111a12e344d54fef3fa8aa0f41d3cff29e59d688a180e97a1b10eb5f610d24d51a889967299445134785ec631d7274c5
7
- data.tar.gz: 0adecd70607f6054831c155c3ac7f64e19a97db8a772f8265cb0d35b0bedc620d9fb8c5371ceaf5c6f804249c2381ca7dac74eaf6aa5f29f661266fc548d319e
6
+ metadata.gz: cac3e425c402f1f4fc5c1c685f61118492d2a9bd358d2bad56962836d849b077bc70b2781f20b4fe9624e1a532ec4e07803a141667cbc43709d1d9ad84dee766
7
+ data.tar.gz: 0a51d45298fba885dda209ab236c2dac350d6f7abce5dc7137e5fb8994f6ffe2d0a253d835627412c3fd642b46880ce087470bcb098459b65cb9f38041b2bb4d
data/CHANGELOG.md CHANGED
@@ -7,6 +7,59 @@ Notable changes to one_gadget, newest first. The format follows
7
7
  A change worth a user's attention lands with its entry under *Unreleased*;
8
8
  releases are cut by giving that section a version and a date.
9
9
 
10
+ ## v2.1.0 - 2026-09-05
11
+
12
+ Two more architectures, and a libc that ships without section headers -- as an
13
+ embedded one usually does -- can now be searched at all.
14
+
15
+ ### Added
16
+
17
+ - RISC-V (RV64) support, alongside i386, amd64, aarch64 and arm ([#420], [#421],
18
+ [#422], [#423], [#425]). Every gadget it reports has been run under a debugger and
19
+ seen to spawn a shell ([#424]).
20
+ - MIPS (32-bit o32) support, in both byte orders ([#448]), verified the same way.
21
+ - Reads a libc that ships without section headers, as OpenWrt's musl does
22
+ ([#432]). Every architecture reports the same gadgets as the intact file.
23
+ - A terminal `posix_spawn` whose symbol carries no version marker, as musl's
24
+ does not, is no longer passed over ([#432]).
25
+
26
+ ### Changed
27
+
28
+ - The gem no longer carries gadgets for the three glibc 2.26 builds it shipped
29
+ ([#443]) -- no supported Ubuntu LTS ships 2.26. Those BuildIDs now answer from
30
+ the remote database.
31
+ - Searching a MIPS libc takes 0.7s, was 2.3s ([#453]).
32
+ - Searching the same file twice in one process reuses what the first search
33
+ found ([#455]).
34
+ - Further search speedups, gadgets unchanged: objdump is asked what it supports
35
+ once per binary rather than once per command ([#454]), the scan locating calls
36
+ decodes far fewer words ([#456]), and a quarter as much is disassembled around
37
+ each call ([#457]).
38
+ - Requires elftools >= 2.2.0 ([#442], [#465]), which reads a symbol table without
39
+ building an object per symbol. A libc with no section headers searches in 0.24s,
40
+ was 0.44s; one with its sections intact is unchanged.
41
+
42
+ ### Fixed
43
+
44
+ - 67 more gadgets across the test corpus ([#460]): a backward walk threw away any
45
+ path that hit its length limit, so what a libc reported depended on how far
46
+ back it had been disassembled. Every new gadget was run under a debugger.
47
+ - MIPS gadgets that could not work are no longer reported ([#460]). Entering at a
48
+ call leaves the callee without the address o32 requires in `t9`, and six such
49
+ gadgets were verified not to spawn a shell.
50
+ - arm found nothing at all in a libc with no section headers ([#441]): Thumb code
51
+ was read as A32, symbol addresses were off by one, and literal-pool loads went
52
+ unresolved.
53
+ - A libc with no section headers lost the calls at an address its symbol table
54
+ gives more than one name, such as `sigaction`/`__sigaction` -- 20 aarch64
55
+ gadgets ([#440]).
56
+ - A libc with no section headers reported fewer gadgets on aarch64 and RISC-V
57
+ than the same libc intact -- 84 across the corpus ([#439]).
58
+ - amd64 discarded every `execl` candidate before emulating it ([#434]). No fixture
59
+ reports a new gadget as a result, but one could.
60
+ - A search could abort with `TypeError` where it should have dropped the
61
+ candidate ([#434]).
62
+
10
63
  ## v2.0.0 - 2026-08-29
11
64
 
12
65
  Reported gadgets are not offset-for-offset comparable with 1.x: constraints are
@@ -15,145 +68,140 @@ test corpus reports has been run under a debugger and seen to spawn a shell.
15
68
 
16
69
  ### Added
17
70
 
18
- - ARM32 support, alongside the existing amd64, i386 and aarch64 (#316).
71
+ - ARM32 support, alongside the existing amd64, i386 and aarch64 ([#316]).
19
72
  - Output level 2, which lists every gadget including the ones lower levels drop
20
- as duplicate or harder-to-satisfy (#350). `--level` is documented in the
21
- README with what each level shows (#397).
73
+ as duplicate or harder-to-satisfy ([#350]). `--level` is documented in the
74
+ README with what each level shows ([#397]).
22
75
  - Aletheia, a verification harness that loads a libc under gdb (natively or
23
76
  through qemu-user), applies a constraint-satisfying plan, and requires a real
24
- shell to run `ls /` before a gadget counts as real (#399). Run it with
77
+ shell to run `ls /` before a gadget counts as real ([#399]). Run it with
25
78
  `rake "aletheia:verify[level, target]"`. Every gadget the fixtures report is
26
79
  verified this way.
27
80
  - Gadgets say which file descriptors they close on the way to the exec, so a
28
- reader knows when the spawned shell would lose its I/O (#371).
81
+ reader knows when the spawned shell would lose its I/O ([#371]).
29
82
  - `rake builds:refresh` rebuilds the shipped gadget database from what the
30
83
  Ubuntu archive publishes now, and `rake builds:check` fails when a shipped
31
- entry has gone stale -- at most once a week, never on CI (#405, #406).
32
- - posix_spawn gadgets on aarch64 (#317), and the string a gadget reaches
33
- through the GOT is shown rather than left opaque (#372).
84
+ entry has gone stale -- at most once a week, never on CI ([#405], [#406]).
85
+ - posix_spawn gadgets on aarch64 ([#317]), and the string a gadget reaches
86
+ through the GOT is shown rather than left opaque ([#372]).
34
87
 
35
88
  ### Changed
36
89
 
37
- - **The gem ships a curated gadget database.** It carries the glibc of every
38
- Ubuntu LTS in standard support plus every libc the tests cover -- 33 entries,
39
- taking the packaged gem from 3.4MB to 112KB. Any other BuildID is fetched from
40
- this repository on demand, as before, so nothing is unreachable; but an
41
- offline `-b` for an arbitrary libc no longer answers from the gem alone
42
- (#405).
90
+ - **The gem ships a curated gadget database** -- 33 entries, taking the packaged
91
+ gem from 3.4MB to 112KB ([#405]). Any other BuildID is fetched on demand as
92
+ before, so an offline `-b` for an arbitrary libc no longer answers from the gem
93
+ alone.
43
94
  - **An output level means the same thing however a libc is looked up.** `-b`
44
95
  now honours `--level`, where it previously handed back whatever the database
45
96
  stored, and level 1 picks the same gadget however the emulator happened to
46
- find it (#402).
97
+ find it ([#402]).
47
98
  - The database was regenerated; entries had been built before a year of
48
- constraint work and reported gadgets their libc no longer produces (#405).
99
+ constraint work and reported gadgets their libc no longer produces ([#405]).
49
100
  - Constraints read consistently: pointers compare to `NULL` and values to hex,
50
- never a bare `0` (#334), and readability is stated as `readable: <reg>`
51
- (#344). A mask a gadget applies is named rather than given up on (#370), and
52
- a value required to be zero scores the same however it is spelled (#377,
53
- #401).
101
+ never a bare `0` ([#334]), and readability is stated as `readable: <reg>`
102
+ ([#344]). A mask a gadget applies is named rather than given up on ([#370]), and
103
+ a value required to be zero scores the same however it is spelled ([#377],
104
+ [#401]).
54
105
  - Emulation stops at the terminal `exec*` call instead of running past it
55
- (#325), and a candidate whose path cannot hold is rejected (#359, #360).
106
+ ([#325]), and a candidate whose path cannot hold is rejected ([#359], [#360]).
56
107
  - Searching a libc got roughly five times faster: the test corpus at level 0
57
- went from 42.5s to 8.6s (#388, #389, #390, #393, #394, #395, #396).
58
- - Requires Ruby >= 3.3 (#293) and elftools >= 2.0.0.
108
+ went from 42.5s to 8.6s ([#388], [#389], [#390], [#393], [#394], [#395], [#396]).
109
+ - Requires Ruby >= 3.3 ([#293]) and elftools >= 2.0.0.
59
110
 
60
111
  ### Fixed
61
112
 
62
113
  - Gadgets that could not actually spawn a shell, each found by running them:
63
114
  a dereferenced pointer argument of a "safe" libc call went unconstrained
64
- (#323, #340), a writable constraint was lost when its base was reassigned
65
- (#341), frame-pointer stores did not require the frame be writable (#345),
66
- an argv that disables shell execution was reported as usable (#348), an
67
- uncontrolled dereference was not required to be readable (#354), and a slot
115
+ ([#323], [#340]), a writable constraint was lost when its base was reassigned
116
+ ([#341]), frame-pointer stores did not require the frame be writable ([#345]),
117
+ an argv that disables shell execution was reported as usable ([#348]), an
118
+ uncontrolled dereference was not required to be readable ([#354]), and a slot
68
119
  was read back as its entry value rather than what the gadget had put there
69
- (#364).
120
+ ([#364]).
70
121
  - A GOT-base register the window establishes itself was seeded as a
71
- precondition (#385), and the GOT-base constraint is now only stated where a
72
- caller can actually put it -- in a register (#404).
122
+ precondition ([#385]), and the GOT-base constraint is now only stated where a
123
+ caller can actually put it -- in a register ([#404]).
73
124
  - Windowed disassembly lost gadgets whose branch predecessor sits after the
74
- call, and could invent gadgets by falling through a window boundary (#391,
75
- #392).
76
- - The "not glibc" check did not fire for aarch64 files (#311).
125
+ call, and could invent gadgets by falling through a window boundary ([#391],
126
+ [#392]).
127
+ - The "not glibc" check did not fire for aarch64 files ([#311]).
77
128
  - **Certificates are verified again when fetching a gadget database entry.**
78
- Verification had been switched off, and what comes back from that request is
79
- written to a file and required as Ruby, so anyone able to answer it could run
80
- code as the user.
81
- - Shipped entries reported fewer gadgets than reading the same libc as a file,
82
- having been generated before the emulator learned to run `xchg`. They are
83
- regenerated, and `rake builds:audit` now fails when an entry stops matching
129
+ Verification had been off, and the response is written to a file and required
130
+ as Ruby -- so anyone able to answer that request could run code as the user.
131
+ - Shipped entries reported fewer gadgets than reading the same libc as a file.
132
+ They are regenerated, and `rake builds:audit` now fails when one stops matching
84
133
  its libc.
85
134
  - An architecture is recognised by the machine type its ELF header states, not
86
- by the name the reader library prints for it -- the latter is that library's
87
- wording and changed in elftools 2.0.0, which left every aarch64 and amd64 file
88
- reading as an unknown architecture.
135
+ by the name elftools prints for it, whose wording changed in 2.0.0 and left
136
+ every aarch64 and amd64 file reading as unknown.
89
137
 
90
138
  ## v1.10.0 - 2024-10-04
91
139
 
92
- - Added JSON output, `--output-format json` (#225).
93
- - Requires Ruby >= 3.1 (#216).
140
+ - Added JSON output, `--output-format json` ([#225]).
141
+ - Requires Ruby >= 3.1 ([#216]).
94
142
 
95
143
  ## v1.9.0 - 2023-11-30
96
144
 
97
- - Sharper constraints for `argv` and `envp` (#206).
98
- - Added `--dwarf-start=0` so the output carries no local file path (#205).
145
+ - Sharper constraints for `argv` and `envp` ([#206]).
146
+ - Added `--dwarf-start=0` so the output carries no local file path ([#205]).
99
147
 
100
148
  ## v1.8.1 - 2022-03-25
101
149
 
102
150
  - Stack registers score higher on writable constraints, so easier gadgets rank
103
- first (#190).
151
+ first ([#190]).
104
152
 
105
153
  ## v1.8.0 - 2022-03-20
106
154
 
107
- - posix_spawn call sites are treated as one-gadgets (#183).
108
- - amd64: loosened the restriction on gadgets reached by `jmp` (#178).
155
+ - posix_spawn call sites are treated as one-gadgets ([#183]).
156
+ - amd64: loosened the restriction on gadgets reached by `jmp` ([#178]).
109
157
 
110
158
  ## v1.7.4 - 2021-01-13
111
159
 
112
- - Writable constraints on the x86 architectures (#156).
160
+ - Writable constraints on the x86 architectures ([#156]).
113
161
 
114
162
  ## v1.7.3 - 2019-10-25
115
163
 
116
- - Added the `--base` option (#100).
117
- - Constraints for XMM alignment, and stack alignment scores higher (#87).
164
+ - Added the `--base` option ([#100]).
165
+ - Constraints for XMM alignment, and stack alignment scores higher ([#87]).
118
166
 
119
167
  ## v1.7.2 - 2019-05-05
120
168
 
121
- - Added `--near`, ordering gadgets by distance from given functions (#76).
122
- - Introduced the CLI module (#81).
169
+ - Added `--near`, ordering gadgets by distance from given functions ([#76]).
170
+ - Introduced the CLI module ([#81]).
123
171
 
124
172
  ## v1.7.1 - 2019-04-19
125
173
 
126
- - Added gemspec metadata (#75).
174
+ - Added gemspec metadata ([#75]).
127
175
 
128
176
  ## v1.7.0 - 2019-03-07
129
177
 
130
- - AArch64 support (#64).
131
- - Constraints are scored, so the easiest gadgets are reported first (#67).
178
+ - AArch64 support ([#64]).
179
+ - Constraints are scored, so the easiest gadgets are reported first ([#67]).
132
180
 
133
181
  ## v1.6.2 - 2018-10-25
134
182
 
135
- - one_gadget is usable as a library (#47).
183
+ - one_gadget is usable as a library ([#47]).
136
184
 
137
185
  ## v1.6.1 - 2018-09-13
138
186
 
139
- - Improved update checking (#43) and custom error classes (#40).
187
+ - Improved update checking ([#43]) and custom error classes ([#40]).
140
188
 
141
189
  ## v1.6.0 - 2018-04-28
142
190
 
143
- - Added the xmm instructions and glibc 2.27 builds (#27).
144
- - Added `--info`, showing what is known about a BuildID (#25).
191
+ - Added the xmm instructions and glibc 2.27 builds ([#27]).
192
+ - Added `--info`, showing what is known about a BuildID ([#25]).
145
193
 
146
194
  ## v1.5.0 - 2017-11-06
147
195
 
148
- - Emulator rework, and the build database is generated from libc files (#15).
196
+ - Emulator rework, and the build database is generated from libc files ([#15]).
149
197
 
150
198
  ## v1.4.1 - 2017-11-01
151
199
 
152
- - Checks for a newer version automatically (#13).
200
+ - Checks for a newer version automatically ([#13]).
153
201
 
154
202
  ## v1.4.0 - 2017-06-23
155
203
 
156
- - Warns when a BuildID is not found, and added Ubuntu 16.04/17.04 libcs (#9).
204
+ - Warns when a BuildID is not found, and added Ubuntu 16.04/17.04 libcs ([#9]).
157
205
 
158
206
  ## v1.3.8 - 2017-05-26
159
207
 
@@ -166,7 +214,7 @@ test corpus reports has been run under a debugger and seen to spawn a shell.
166
214
  ## v1.3.6 - 2017-04-01
167
215
 
168
216
  - Added builds for glibc >= 2.19; a given libc file is no longer looked up
169
- remotely (#6).
217
+ remotely ([#6]).
170
218
 
171
219
  ## v1.3.5 - 2017-03-27
172
220
 
@@ -215,3 +263,87 @@ test corpus reports has been run under a debugger and seen to spawn a shell.
215
263
  ## v0.1.0 - 2017-02-11
216
264
 
217
265
  - First release.
266
+
267
+ [#6]: https://github.com/david942j/one_gadget/pull/6
268
+ [#9]: https://github.com/david942j/one_gadget/pull/9
269
+ [#13]: https://github.com/david942j/one_gadget/pull/13
270
+ [#15]: https://github.com/david942j/one_gadget/pull/15
271
+ [#25]: https://github.com/david942j/one_gadget/pull/25
272
+ [#27]: https://github.com/david942j/one_gadget/pull/27
273
+ [#40]: https://github.com/david942j/one_gadget/pull/40
274
+ [#43]: https://github.com/david942j/one_gadget/pull/43
275
+ [#47]: https://github.com/david942j/one_gadget/pull/47
276
+ [#64]: https://github.com/david942j/one_gadget/pull/64
277
+ [#67]: https://github.com/david942j/one_gadget/pull/67
278
+ [#75]: https://github.com/david942j/one_gadget/pull/75
279
+ [#76]: https://github.com/david942j/one_gadget/pull/76
280
+ [#81]: https://github.com/david942j/one_gadget/pull/81
281
+ [#87]: https://github.com/david942j/one_gadget/pull/87
282
+ [#100]: https://github.com/david942j/one_gadget/pull/100
283
+ [#156]: https://github.com/david942j/one_gadget/pull/156
284
+ [#178]: https://github.com/david942j/one_gadget/pull/178
285
+ [#183]: https://github.com/david942j/one_gadget/pull/183
286
+ [#190]: https://github.com/david942j/one_gadget/pull/190
287
+ [#205]: https://github.com/david942j/one_gadget/pull/205
288
+ [#206]: https://github.com/david942j/one_gadget/pull/206
289
+ [#216]: https://github.com/david942j/one_gadget/pull/216
290
+ [#225]: https://github.com/david942j/one_gadget/pull/225
291
+ [#293]: https://github.com/david942j/one_gadget/pull/293
292
+ [#311]: https://github.com/david942j/one_gadget/pull/311
293
+ [#316]: https://github.com/david942j/one_gadget/pull/316
294
+ [#317]: https://github.com/david942j/one_gadget/pull/317
295
+ [#323]: https://github.com/david942j/one_gadget/pull/323
296
+ [#325]: https://github.com/david942j/one_gadget/pull/325
297
+ [#334]: https://github.com/david942j/one_gadget/pull/334
298
+ [#340]: https://github.com/david942j/one_gadget/pull/340
299
+ [#341]: https://github.com/david942j/one_gadget/pull/341
300
+ [#344]: https://github.com/david942j/one_gadget/pull/344
301
+ [#345]: https://github.com/david942j/one_gadget/pull/345
302
+ [#348]: https://github.com/david942j/one_gadget/pull/348
303
+ [#350]: https://github.com/david942j/one_gadget/pull/350
304
+ [#354]: https://github.com/david942j/one_gadget/pull/354
305
+ [#359]: https://github.com/david942j/one_gadget/pull/359
306
+ [#360]: https://github.com/david942j/one_gadget/pull/360
307
+ [#364]: https://github.com/david942j/one_gadget/pull/364
308
+ [#370]: https://github.com/david942j/one_gadget/pull/370
309
+ [#371]: https://github.com/david942j/one_gadget/pull/371
310
+ [#372]: https://github.com/david942j/one_gadget/pull/372
311
+ [#377]: https://github.com/david942j/one_gadget/pull/377
312
+ [#385]: https://github.com/david942j/one_gadget/pull/385
313
+ [#388]: https://github.com/david942j/one_gadget/pull/388
314
+ [#389]: https://github.com/david942j/one_gadget/pull/389
315
+ [#390]: https://github.com/david942j/one_gadget/pull/390
316
+ [#391]: https://github.com/david942j/one_gadget/pull/391
317
+ [#392]: https://github.com/david942j/one_gadget/pull/392
318
+ [#393]: https://github.com/david942j/one_gadget/pull/393
319
+ [#394]: https://github.com/david942j/one_gadget/pull/394
320
+ [#395]: https://github.com/david942j/one_gadget/pull/395
321
+ [#396]: https://github.com/david942j/one_gadget/pull/396
322
+ [#397]: https://github.com/david942j/one_gadget/pull/397
323
+ [#399]: https://github.com/david942j/one_gadget/pull/399
324
+ [#401]: https://github.com/david942j/one_gadget/pull/401
325
+ [#402]: https://github.com/david942j/one_gadget/pull/402
326
+ [#404]: https://github.com/david942j/one_gadget/pull/404
327
+ [#405]: https://github.com/david942j/one_gadget/pull/405
328
+ [#406]: https://github.com/david942j/one_gadget/pull/406
329
+ [#420]: https://github.com/david942j/one_gadget/pull/420
330
+ [#421]: https://github.com/david942j/one_gadget/pull/421
331
+ [#422]: https://github.com/david942j/one_gadget/pull/422
332
+ [#423]: https://github.com/david942j/one_gadget/pull/423
333
+ [#424]: https://github.com/david942j/one_gadget/pull/424
334
+ [#425]: https://github.com/david942j/one_gadget/pull/425
335
+ [#432]: https://github.com/david942j/one_gadget/pull/432
336
+ [#434]: https://github.com/david942j/one_gadget/pull/434
337
+ [#439]: https://github.com/david942j/one_gadget/pull/439
338
+ [#440]: https://github.com/david942j/one_gadget/pull/440
339
+ [#441]: https://github.com/david942j/one_gadget/pull/441
340
+ [#442]: https://github.com/david942j/one_gadget/pull/442
341
+ [#443]: https://github.com/david942j/one_gadget/pull/443
342
+ [#448]: https://github.com/david942j/one_gadget/pull/448
343
+ [#453]: https://github.com/david942j/one_gadget/pull/453
344
+ [#454]: https://github.com/david942j/one_gadget/pull/454
345
+ [#455]: https://github.com/david942j/one_gadget/pull/455
346
+ [#456]: https://github.com/david942j/one_gadget/pull/456
347
+ [#457]: https://github.com/david942j/one_gadget/pull/457
348
+ [#460]: https://github.com/david942j/one_gadget/pull/460
349
+ [#465]: https://github.com/david942j/one_gadget/pull/465
data/README.md CHANGED
@@ -11,12 +11,13 @@
11
11
 
12
12
  ## OneGadget
13
13
 
14
- When playing ctf pwn challenges we usually need the one-gadget RCE (remote code execution),
15
- which leads to call `execve('/bin/sh', NULL, NULL)`.
14
+ When solving CTF pwn challenges we usually want a one-gadget RCE: a single address in
15
+ libc that, jumped to, calls `execve("/bin/sh", NULL, NULL)`.
16
16
 
17
- This gem provides such gadgets finder, no need to use objdump or IDA-pro every time like a fool :wink:
17
+ This gem finds them for you, so you don't have to dig through objdump or IDA Pro every
18
+ time :wink:
18
19
 
19
- To use this tool, type `one_gadget /path/to/libc` in command line and enjoy the magic :laughing:
20
+ Point it at a libc -- `one_gadget /path/to/libc` -- and enjoy the magic :laughing:
20
21
 
21
22
  ## Installation
22
23
 
@@ -25,18 +26,19 @@ Available on RubyGems.org!
25
26
  $ gem install one_gadget
26
27
  ```
27
28
 
28
- Note: requires ruby version >= 2.1.0, you can use `ruby --version` to check.
29
-
30
29
  ## Supported Architectures
31
30
 
32
31
  - [x] i386
33
32
  - [x] amd64 (x86-64)
34
33
  - [x] aarch64 (ARMv8)
35
34
  - [x] arm (ARMv7, A32/Thumb-2)
35
+ - [x] riscv64 (RV64GC)
36
+ - [x] mips (MIPS32 o32, big- and little-endian)
36
37
 
37
38
  ## Implementation
38
39
 
39
- OneGadget uses symbolic execution to find the constraints of gadgets to be successful.
40
+ OneGadget symbolically executes the code around each candidate address to work out what
41
+ has to hold for the gadget to work.
40
42
 
41
43
  Gadgets are found by walking the control-flow graph backward from each `exec`/`posix_spawn`
42
44
  call, following conditional branches both ways. When a gadget is only reachable if a branch is
@@ -144,17 +146,17 @@ BuildID is fetched from this repository, which keeps them all.
144
146
 
145
147
  ##### Why
146
148
 
147
- Consider this scenario when exploiting:
148
- 1. Able to write on GOT (Global Offset Table)
149
- 2. Base address of libc is *unknown*
149
+ Consider this situation while exploiting:
150
+ 1. You can write to the GOT (Global Offset Table).
151
+ 2. The base address of libc is *unknown*.
150
152
 
151
- In this scenario you can choose to write two low-byte on a GOT entry with one-gadget's two low-byte.
152
- If the function offset on GOT is close enough with the one-gadget,
153
- you will have at least 1/16 chance of success.
153
+ Here you can overwrite the low two bytes of a GOT entry with the low two bytes of a
154
+ one-gadget. If the function sits close enough to the gadget, only one nibble is left to
155
+ guess -- at least a 1 in 16 chance of success.
154
156
 
155
157
  ##### Usage
156
158
 
157
- Reorder gadgets according to the distance of given functions.
159
+ Sorts the gadgets by how far they are from the functions you name.
158
160
 
159
161
  ```bash
160
162
  $ one_gadget spec/data/libc-2.31-9fdb74e7b217d06c93172a8243f8547f947ee6d1.so --near exit,mkdir
@@ -204,7 +206,7 @@ $ one_gadget spec/data/libc-2.31-9fdb74e7b217d06c93172a8243f8547f947ee6d1.so --n
204
206
  ```
205
207
  ![near](https://github.com/david942j/one_gadget/blob/master/examples/near.png?raw=true)
206
208
 
207
- Regular expression is acceptable.
209
+ Regular expressions work too.
208
210
  ```bash
209
211
  $ one_gadget spec/data/libc-2.31-9fdb74e7b217d06c93172a8243f8547f947ee6d1.so --near 'write.*' --raw
210
212
  # [OneGadget] Gadgets near writev(0x1144a0):
@@ -216,7 +218,7 @@ $ one_gadget spec/data/libc-2.31-9fdb74e7b217d06c93172a8243f8547f947ee6d1.so --n
216
218
 
217
219
  ```
218
220
 
219
- Pass an ELF file as the argument, OneGadget will take all GOT functions for processing.
221
+ Pass an ELF file instead, and OneGadget uses every function in its GOT.
220
222
  ```bash
221
223
  $ one_gadget spec/data/libc-2.31-9fdb74e7b217d06c93172a8243f8547f947ee6d1.so --near spec/data/test_near_file.elf --raw
222
224
  # [OneGadget] Gadgets near exit(0x46a70):
@@ -573,9 +575,81 @@ $ one_gadget spec/data/arm-libc-2.39.so
573
575
 
574
576
  ```
575
577
 
578
+ ##### RISC-V (RV64)
579
+
580
+ ```bash
581
+ $ one_gadget spec/data/riscv64-libc-2.39.so
582
+ # 0x9f73a execve("/bin/sh", s1, a2)
583
+ # constraints:
584
+ # [s1] == NULL || s1 == NULL || s1 is a valid argv
585
+ # [a2] == NULL || a2 == NULL || a2 is a valid envp
586
+ #
587
+ # 0x9f73c execve("/bin/sh", a1, a2)
588
+ # constraints:
589
+ # [a1] == NULL || a1 == NULL || a1 is a valid argv
590
+ # [a2] == NULL || a2 == NULL || a2 is a valid envp
591
+ #
592
+ # 0x9f778 execve("/bin/sh", s1, s2)
593
+ # constraints:
594
+ # [s1] == NULL || s1 == NULL || s1 is a valid argv
595
+ # [s2] == NULL || s2 == NULL || s2 is a valid envp
596
+ #
597
+ # 0xb5adc posix_spawn(sp+0x44, "/bin/sh", [sp+0x30], 0, sp+0x50, environ)
598
+ # constraints:
599
+ # [sp+0x50] == NULL || {[sp+0x50], [sp+0x58], [sp+0x60], [sp+0x68], ...} is a valid argv
600
+ # [sp+0x30] == NULL || (s32)[[sp+0x30]+0x4] <= 0x0
601
+
602
+ ```
603
+
604
+ ##### MIPS
605
+
606
+ Big-endian is as common as little-endian here, and both are read. This one is
607
+ OpenWrt's musl for ath79, which ships with no section headers -- the shape a
608
+ router's libc usually arrives in.
609
+
610
+ ```bash
611
+ $ one_gadget spec/data/mips-musl-1.2.4.so
612
+ # 0x668e8 posix_spawn(sp+0x20, "/bin/sh", 0, s0, sp+0x28, environ)
613
+ # constraints:
614
+ # gp is the GOT address of libc
615
+ # {"sh", "-c", s1, NULL} is a valid argv
616
+ # s0 == NULL || (u16)[s0] == 0x0
617
+ #
618
+ # 0x668ec posix_spawn(sp+0x20, "/bin/sh", 0, s0, sp+0x28, environ)
619
+ # constraints:
620
+ # gp is the GOT address of libc
621
+ # {"sh", "-c", [sp+0x30], NULL} is a valid argv
622
+ # s0 == NULL || (u16)[s0] == 0x0
623
+ #
624
+ # 0x668f0 posix_spawn(sp+0x20, "/bin/sh", 0, a3, sp+0x28, environ)
625
+ # constraints:
626
+ # gp is the GOT address of libc
627
+ # {"sh", "-c", [sp+0x30], NULL} is a valid argv
628
+ # a3 == NULL || (u16)[a3] == 0x0
629
+ #
630
+ # 0x668f4 posix_spawn(sp+0x20, "/bin/sh", 0, a3, sp+0x28, environ)
631
+ # constraints:
632
+ # gp is the GOT address of libc
633
+ # v0-0x7c70 == NULL || {v0-0x7c70, "-c", [sp+0x30], NULL} is a valid argv
634
+ # a3 == NULL || (u16)[a3] == 0x0
635
+ #
636
+ # 0x77b44 posix_spawn(sp+0x20, "/bin/sh", s2, 0, sp+0x2c, environ)
637
+ # constraints:
638
+ # gp is the GOT address of libc
639
+ # {"sh", "-c", s7, NULL} is a valid argv
640
+ # s2 == NULL || (s32)[s2+0x4] <= 0x0
641
+ #
642
+ # 0x77b48 posix_spawn(sp+0x20, "/bin/sh", s2, 0, sp+0x2c, environ)
643
+ # constraints:
644
+ # gp is the GOT address of libc
645
+ # v0-0x7c70 == NULL || {v0-0x7c70, "-c", s7, NULL} is a valid argv
646
+ # s2 == NULL || (s32)[s2+0x4] <= 0x0
647
+
648
+ ```
649
+
576
650
  #### Combine with Script
577
- Pass your exploit script as `one_gadget`'s arguments, it can
578
- try all gadgets one by one, so you don't need to try every possible gadgets manually.
651
+ Pass your exploit script to `one_gadget` and it runs the script once per gadget, so you
652
+ don't have to work through them by hand.
579
653
 
580
654
  ```bash
581
655
  $ one_gadget spec/data/libc-2.31-9fdb74e7b217d06c93172a8243f8547f947ee6d1.so -s 'echo "offset ->"'
@@ -589,7 +663,7 @@ require 'one_gadget'
589
663
  OneGadget.gadgets(file: 'spec/data/libc-2.31-9fdb74e7b217d06c93172a8243f8547f947ee6d1.so')
590
664
  #=> [932657, 932660, 932896, 1080554]
591
665
 
592
- # or in shorter way
666
+ # or, more briefly
593
667
  one_gadget('spec/data/libc-2.31-9fdb74e7b217d06c93172a8243f8547f947ee6d1.so', level: 1)
594
668
  #=> [335352, 335403, 335410, 335417, 335424, 335429, 335445, 335450, 541029, 541036, 541043, 541046, 541051, 541056, 541068, 541074, 541081, 541088, 932657, 932660, 932896, 933158, 933256, 933264, 933266, 933273, 933280, 933335, 933345, 1078759, 1078769, 1080554]
595
669
 
@@ -611,7 +685,7 @@ one_gadget('spec/data/libc-2.31-9fdb74e7b217d06c93172a8243f8547f947ee6d1.so')
611
685
  ```
612
686
 
613
687
  ## Make OneGadget Better
614
- Any suggestion or feature request is welcome! Feel free to send a pull request.
688
+ Any suggestion or feature request is welcome, and pull requests even more so!
615
689
 
616
- Please let me know if you find any libc that make OneGadget fail to find gadgets.
617
- And, if you like this work, I'll be happy to be [starred](https://github.com/david942j/one_gadget/stargazers) :grimacing:
690
+ Please let me know if you come across a libc OneGadget finds nothing in. And if you like
691
+ this work, I'd be happy to be [starred](https://github.com/david942j/one_gadget/stargazers) :grimacing:
@@ -14,6 +14,17 @@ module OneGadget
14
14
  # Registers of AArch64.
15
15
  AARCH64 = %w[xzr wzr sp] + 0.upto(30).map { |i| ["x#{i}", "w#{i}"] }.flatten
16
16
 
17
+ # Registers of RISC-V (RV64), by the ABI names objdump prints: it emits neither
18
+ # the numbered +x0+-+x15+ names nor +fp+ for +s0+, so neither is listed.
19
+ RISCV64 = %w[zero ra sp gp tp] + 0.upto(6).map { |i| "t#{i}" } +
20
+ 0.upto(11).map { |i| "s#{i}" } + 0.upto(7).map { |i| "a#{i}" }
21
+
22
+ # Registers of MIPS (32-bit), by the names objdump prints: it emits the ABI
23
+ # names rather than the numbered +$0+-+$31+, and +fp+ rather than +s8+.
24
+ MIPS = %w[zero at v0 v1 gp sp fp ra] +
25
+ 0.upto(3).map { |i| "a#{i}" } + 0.upto(9).map { |i| "t#{i}" } +
26
+ 0.upto(7).map { |i| "s#{i}" } + 0.upto(1).map { |i| "k#{i}" }
27
+
17
28
  # Registers of ARM (32-bit).
18
29
  # objdump never prints the numbered name of a register that has a role name:
19
30
  # +r10+-+r15+ always appear as +sl+/+fp+/+ip+/+sp+/+lr+/+pc+, so those are
@@ -31,7 +42,12 @@ module OneGadget
31
42
  8.upto(15).map { |i| ["r#{i}d", "r#{i}"] }).to_h,
32
43
  i386: {},
33
44
  aarch64: 0.upto(30).to_h { |i| ["w#{i}", "x#{i}"] }.merge('wzr' => 'xzr'),
34
- arm: {}
45
+ arm: {},
46
+ # RISC-V names no part of a register: its 32-bit operations are instructions
47
+ # of their own (+addiw+, +sext.w+), each writing the whole register.
48
+ riscv64: {},
49
+ # MIPS names no part of a register either.
50
+ mips: {}
35
51
  }.freeze
36
52
 
37
53
  # Registers a call may destroy, per each ABI's calling convention: the return
@@ -49,11 +65,19 @@ module OneGadget
49
65
  aarch64: (0.upto(7).to_a + 9.upto(18).to_a).map { |i| "x#{i}" },
50
66
  # AAPCS: r0-r3 arguments and return, ip (r12) the intra-procedure scratch,
51
67
  # and lr, which the call itself overwrites with the return address.
52
- arm: %w[r0 r1 r2 r3 ip lr]
68
+ arm: %w[r0 r1 r2 r3 ip lr],
69
+ # RISC-V LP64: a0-a7 arguments (a0/a1 also the return), t0-t6 temporaries,
70
+ # and ra, which the call itself overwrites with the return address.
71
+ riscv64: %w[ra] + 0.upto(7).map { |i| "a#{i}" } + 0.upto(6).map { |i| "t#{i}" },
72
+ # o32: v0/v1 the return, a0-a3 arguments, t0-t9 temporaries, at the
73
+ # assembler's scratch, and ra, which the call itself overwrites. gp goes
74
+ # with them: PIC code reloads it from the stack after every call, because
75
+ # the callee establishes its own.
76
+ mips: %w[at v0 v1 gp ra] + 0.upto(3).map { |i| "a#{i}" } + 0.upto(9).map { |i| "t#{i}" }
53
77
  }.freeze
54
78
 
55
79
  # The register each ABI leaves an integer return value in.
56
- RETURN_REGISTER = { amd64: 'rax', i386: 'eax', aarch64: 'x0', arm: 'r0' }.freeze
80
+ RETURN_REGISTER = { amd64: 'rax', i386: 'eax', aarch64: 'x0', arm: 'r0', riscv64: 'a0' }.freeze
57
81
 
58
82
  module_function
59
83
 
@@ -81,10 +105,22 @@ module OneGadget
81
105
  ARM
82
106
  end
83
107
 
108
+ # Registers' name of RISC-V (RV64).
109
+ # @return [Array<String>] List of registers.
110
+ def riscv64
111
+ RISCV64
112
+ end
113
+
114
+ # Registers' name of MIPS (32-bit).
115
+ # @return [Array<String>] List of registers.
116
+ def mips
117
+ MIPS
118
+ end
119
+
84
120
  # Returns all names of registers.
85
121
  # @return [Array<String>] List of registers.
86
122
  def all
87
- amd64 + aarch64 + arm
123
+ amd64 + aarch64 + arm + riscv64 + mips
88
124
  end
89
125
 
90
126
  # Checks if the register is a stack-related pointer.
@@ -92,7 +128,7 @@ module OneGadget
92
128
  # Register's name.
93
129
  # @return [Boolean] +true+ if +reg+ is a stack or frame pointer (e.g. +rsp+, +rbp+, +sp+).
94
130
  def stack_register?(reg)
95
- %w[esp ebp rsp rbp sp x29].include?(reg)
131
+ %w[esp ebp rsp rbp sp x29 s0].include?(reg)
96
132
  end
97
133
  end
98
134
  end