one_gadget 1.9.0 → 1.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc7692c2d1de780ad214a4c259f42a06560c664c9ec9e6db55e01ca5856c3a3b
4
- data.tar.gz: ad1d2b9efcc87b69e07e02e3d0a7826174f73b46217e459eeedab881d6d43bf7
3
+ metadata.gz: 115a1008facd6ff265526eb0be8392bca7cd4eab161b549ead9ab6f34a0050b2
4
+ data.tar.gz: 56f21220b1a65fe15ac51b682f95ba52fb108084912570f8208f1ef40eafda52
5
5
  SHA512:
6
- metadata.gz: 7ae80fea1083e6c72672d7b05fc5dbb769c3a53e2974f56f4e8162726dfdf811d677d746ef573c7310fefb382af9eef18a306cdc5431a7c8c1bc877ac4f30f74
7
- data.tar.gz: 6deec0fe4bf09d84ff8e8b93bbdecea02ab69861115222a176b8ff4406163ba1255cdf874d50e9d4d2f3d1707a89f831c8c010f9cd7b73ca89134a87c6cc336a
6
+ metadata.gz: 5c5714e03eda9a982d9d1510ad5f0465e3f11e55155507910df4302e039d92a3a5c35cf5be45c0a8f30709b491fcb301d00e8e9d57638610c1e0042282e87a02
7
+ data.tar.gz: 21ac5b3a5cc316c92e90741bcec4e5efbdc8d97183c3810eba356216c636a9d4d59c3a62784e2395731d72a3c716fa8c10eec8697f04437e3da2a1c41a292c0c
data/README.md CHANGED
@@ -64,18 +64,20 @@ $ one_gadget
64
64
 
65
65
  ```bash
66
66
  $ one_gadget /lib/x86_64-linux-gnu/libc.so.6
67
- # 0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
67
+ # 0xe3afe execve("/bin/sh", r15, r12)
68
68
  # constraints:
69
- # rsp & 0xf == 0
70
- # rcx == NULL
69
+ # [r15] == NULL || r15 == NULL || r15 is a valid argv
70
+ # [r12] == NULL || r12 == NULL || r12 is a valid envp
71
71
  #
72
- # 0x4f322 execve("/bin/sh", rsp+0x40, environ)
72
+ # 0xe3b01 execve("/bin/sh", r15, rdx)
73
73
  # constraints:
74
- # [rsp+0x40] == NULL
74
+ # [r15] == NULL || r15 == NULL || r15 is a valid argv
75
+ # [rdx] == NULL || rdx == NULL || rdx is a valid envp
75
76
  #
76
- # 0x10a38c execve("/bin/sh", rsp+0x70, environ)
77
+ # 0xe3b04 execve("/bin/sh", rsi, rdx)
77
78
  # constraints:
78
- # [rsp+0x70] == NULL
79
+ # [rsi] == NULL || rsi == NULL || rsi is a valid argv
80
+ # [rdx] == NULL || rdx == NULL || rdx is a valid envp
79
81
 
80
82
  ```
81
83
  ![x86_64](https://github.com/david942j/one_gadget/blob/master/examples/x86_64.png?raw=true)
@@ -83,21 +85,17 @@ $ one_gadget /lib/x86_64-linux-gnu/libc.so.6
83
85
  #### Given BuildID
84
86
  ```bash
85
87
  $ one_gadget -b aad7dbe330f23ea00ca63daf793b766b51aceb5d
86
- # 0x45526 execve("/bin/sh", rsp+0x30, environ)
87
- # constraints:
88
- # rax == NULL
89
- #
90
88
  # 0x4557a execve("/bin/sh", rsp+0x30, environ)
91
89
  # constraints:
92
- # [rsp+0x30] == NULL
90
+ # [rsp+0x30] == NULL || {[rsp+0x30], [rsp+0x38], [rsp+0x40], [rsp+0x48], ...} is a valid argv
93
91
  #
94
92
  # 0xf1651 execve("/bin/sh", rsp+0x40, environ)
95
93
  # constraints:
96
- # [rsp+0x40] == NULL
94
+ # [rsp+0x40] == NULL || {[rsp+0x40], [rsp+0x48], [rsp+0x50], [rsp+0x58], ...} is a valid argv
97
95
  #
98
96
  # 0xf24cb execve("/bin/sh", rsp+0x60, environ)
99
97
  # constraints:
100
- # [rsp+0x60] == NULL
98
+ # [rsp+0x60] == NULL || {[rsp+0x60], [rsp+0x68], [rsp+0x70], [rsp+0x78], ...} is a valid argv
101
99
 
102
100
  ```
103
101
  ![build id](https://github.com/david942j/one_gadget/blob/master/examples/from_build_id.png?raw=true)
@@ -120,33 +118,37 @@ Reorder gadgets according to the distance of given functions.
120
118
 
121
119
  ```bash
122
120
  $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near exit,mkdir
123
- # [OneGadget] Gadgets near exit(0x43120):
124
- # 0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
121
+ # [OneGadget] Gadgets near exit(0x46a40):
122
+ # 0xe3afe execve("/bin/sh", r15, r12)
125
123
  # constraints:
126
- # rsp & 0xf == 0
127
- # rcx == NULL
124
+ # [r15] == NULL || r15 == NULL || r15 is a valid argv
125
+ # [r12] == NULL || r12 == NULL || r12 is a valid envp
128
126
  #
129
- # 0x4f322 execve("/bin/sh", rsp+0x40, environ)
127
+ # 0xe3b01 execve("/bin/sh", r15, rdx)
130
128
  # constraints:
131
- # [rsp+0x40] == NULL
129
+ # [r15] == NULL || r15 == NULL || r15 is a valid argv
130
+ # [rdx] == NULL || rdx == NULL || rdx is a valid envp
132
131
  #
133
- # 0x10a38c execve("/bin/sh", rsp+0x70, environ)
132
+ # 0xe3b04 execve("/bin/sh", rsi, rdx)
134
133
  # constraints:
135
- # [rsp+0x70] == NULL
134
+ # [rsi] == NULL || rsi == NULL || rsi is a valid argv
135
+ # [rdx] == NULL || rdx == NULL || rdx is a valid envp
136
136
  #
137
- # [OneGadget] Gadgets near mkdir(0x10fbb0):
138
- # 0x10a38c execve("/bin/sh", rsp+0x70, environ)
137
+ # [OneGadget] Gadgets near mkdir(0x10de70):
138
+ # 0xe3b04 execve("/bin/sh", rsi, rdx)
139
139
  # constraints:
140
- # [rsp+0x70] == NULL
140
+ # [rsi] == NULL || rsi == NULL || rsi is a valid argv
141
+ # [rdx] == NULL || rdx == NULL || rdx is a valid envp
141
142
  #
142
- # 0x4f322 execve("/bin/sh", rsp+0x40, environ)
143
+ # 0xe3b01 execve("/bin/sh", r15, rdx)
143
144
  # constraints:
144
- # [rsp+0x40] == NULL
145
+ # [r15] == NULL || r15 == NULL || r15 is a valid argv
146
+ # [rdx] == NULL || rdx == NULL || rdx is a valid envp
145
147
  #
146
- # 0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
148
+ # 0xe3afe execve("/bin/sh", r15, r12)
147
149
  # constraints:
148
- # rsp & 0xf == 0
149
- # rcx == NULL
150
+ # [r15] == NULL || r15 == NULL || r15 is a valid argv
151
+ # [r12] == NULL || r12 == NULL || r12 is a valid envp
150
152
  #
151
153
 
152
154
  ```
@@ -155,11 +157,11 @@ $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near exit,mkdir
155
157
  Regular expression is acceptable.
156
158
  ```bash
157
159
  $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near 'write.*' --raw
158
- # [OneGadget] Gadgets near writev(0x1166a0):
159
- # 1090444 324386 324293
160
+ # [OneGadget] Gadgets near writev(0x114690):
161
+ # 932612 932609 932606
160
162
  #
161
- # [OneGadget] Gadgets near write(0x110140):
162
- # 1090444 324386 324293
163
+ # [OneGadget] Gadgets near write(0x10e280):
164
+ # 932612 932609 932606
163
165
  #
164
166
 
165
167
  ```
@@ -167,23 +169,23 @@ $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near 'write.*' --raw
167
169
  Pass an ELF file as the argument, OneGadget will take all GOT functions for processing.
168
170
  ```bash
169
171
  $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near spec/data/test_near_file.elf --raw
170
- # [OneGadget] Gadgets near exit(0x43120):
171
- # 324293 324386 1090444
172
+ # [OneGadget] Gadgets near exit(0x46a40):
173
+ # 932606 932609 932612
172
174
  #
173
- # [OneGadget] Gadgets near puts(0x809c0):
174
- # 324386 324293 1090444
175
+ # [OneGadget] Gadgets near puts(0x84420):
176
+ # 932606 932609 932612
175
177
  #
176
- # [OneGadget] Gadgets near printf(0x64e80):
177
- # 324386 324293 1090444
178
+ # [OneGadget] Gadgets near printf(0x61c90):
179
+ # 932606 932609 932612
178
180
  #
179
- # [OneGadget] Gadgets near strlen(0x9dc70):
180
- # 324386 324293 1090444
181
+ # [OneGadget] Gadgets near strlen(0x9f630):
182
+ # 932606 932609 932612
181
183
  #
182
- # [OneGadget] Gadgets near __cxa_finalize(0x43520):
183
- # 324293 324386 1090444
184
+ # [OneGadget] Gadgets near __cxa_finalize(0x46f10):
185
+ # 932606 932609 932612
184
186
  #
185
- # [OneGadget] Gadgets near __libc_start_main(0x21ab0):
186
- # 324293 324386 1090444
187
+ # [OneGadget] Gadgets near __libc_start_main(0x23f90):
188
+ # 932606 932609 932612
187
189
  #
188
190
 
189
191
  ```
@@ -197,89 +199,286 @@ Use option `--level 1` to show all gadgets found instead of only those with high
197
199
 
198
200
  ```bash
199
201
  $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --level 1
200
- # 0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
202
+ # 0x51dfb posix_spawn(rsp+0xc, "/bin/sh", 0, rbp, rsp+0x50, environ)
201
203
  # constraints:
204
+ # address rsp+0x60 is writable
202
205
  # rsp & 0xf == 0
203
- # rcx == NULL
206
+ # {"sh", "-c", rbx, NULL} is a valid argv
207
+ # rbp == NULL || (u16)[rbp] == NULL
204
208
  #
205
- # 0x4f322 execve("/bin/sh", rsp+0x40, environ)
209
+ # 0x51e02 posix_spawn(rsp+0xc, "/bin/sh", 0, rbp, rsp+0x50, environ)
206
210
  # constraints:
207
- # [rsp+0x40] == NULL
211
+ # address rsp+0x60 is writable
212
+ # rsp & 0xf == 0
213
+ # rax == NULL || {"sh", rax, rbx, NULL} is a valid argv
214
+ # rbp == NULL || (u16)[rbp] == NULL
208
215
  #
209
- # 0xe569f execve("/bin/sh", r14, r12)
216
+ # 0x51e09 posix_spawn(rsp+0xc, "/bin/sh", 0, rbp, rsp+0x50, environ)
210
217
  # constraints:
211
- # [r14] == NULL || r14 == NULL
212
- # [r12] == NULL || r12 == NULL
218
+ # address rsp+0x60 is writable
219
+ # rsp & 0xf == 0
220
+ # rcx == NULL || {rcx, rax, rbx, NULL} is a valid argv
221
+ # rbp == NULL || (u16)[rbp] == NULL
213
222
  #
214
- # 0xe5858 execve("/bin/sh", [rbp-0x88], [rbp-0x70])
223
+ # 0x51e10 posix_spawn(rsp+0xc, "/bin/sh", rdx, rbp, rsp+0x50, environ)
215
224
  # constraints:
216
- # [[rbp-0x88]] == NULL || [rbp-0x88] == NULL
217
- # [[rbp-0x70]] == NULL || [rbp-0x70] == NULL
225
+ # address rsp+0x60 is writable
226
+ # rsp & 0xf == 0
227
+ # rcx == NULL || {rcx, (u64)xmm1, rbx, NULL} is a valid argv
228
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
229
+ # rbp == NULL || (u16)[rbp] == NULL
218
230
  #
219
- # 0xe585f execve("/bin/sh", r10, [rbp-0x70])
231
+ # 0x51e15 posix_spawn(rsp+0xc, "/bin/sh", rdx, rbp, rsp+0x50, environ)
220
232
  # constraints:
221
- # [r10] == NULL || r10 == NULL
222
- # [[rbp-0x70]] == NULL || [rbp-0x70] == NULL
233
+ # address rsp+0x60 is writable
234
+ # rsp & 0xf == 0
235
+ # (u64)xmm0 == NULL || {(u64)xmm0, (u64)xmm1, rbx, NULL} is a valid argv
236
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
237
+ # rbp == NULL || (u16)[rbp] == NULL
223
238
  #
224
- # 0xe5863 execve("/bin/sh", r10, rdx)
239
+ # 0x51e25 posix_spawn(rdi, "/bin/sh", rdx, rbp, rsp+0x50, [rax])
225
240
  # constraints:
226
- # [r10] == NULL || r10 == NULL
227
- # [rdx] == NULL || rdx == NULL
241
+ # address rsp+0x60 is writable
242
+ # rsp & 0xf == 0
243
+ # (u64)xmm0 == NULL || {(u64)xmm0, (u64)(xmm0 >> 64), rbx, NULL} is a valid argv
244
+ # [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp
245
+ # rdi == NULL || writable: rdi
246
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
247
+ # rbp == NULL || (u16)[rbp] == NULL
228
248
  #
229
- # 0x10a38c execve("/bin/sh", rsp+0x70, environ)
249
+ # 0x51e2a posix_spawn(rdi, "/bin/sh", rdx, rbp, r8, [rax])
230
250
  # constraints:
231
- # [rsp+0x70] == NULL
251
+ # address rsp+0x60 is writable
252
+ # rsp & 0xf == 0
253
+ # [r8] == NULL || r8 is a valid argv
254
+ # [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp
255
+ # rdi == NULL || writable: rdi
256
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
257
+ # rbp == NULL || (u16)[rbp] == NULL
232
258
  #
233
- # 0x10a398 execve("/bin/sh", rsi, [rax])
259
+ # 0x51e2d posix_spawn(rdi, "/bin/sh", rdx, rcx, r8, [rax])
234
260
  # constraints:
235
- # [rsi] == NULL || rsi == NULL
236
- # [[rax]] == NULL || [rax] == NULL
237
-
238
- ```
239
-
240
- #### Other Architectures
241
-
242
- ##### i386
243
- ```bash
244
- $ one_gadget /lib32/libc.so.6
245
- # 0x3cbea execve("/bin/sh", esp+0x34, environ)
261
+ # address rsp+0x60 is writable
262
+ # rsp & 0xf == 0
263
+ # [r8] == NULL || r8 is a valid argv
264
+ # [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp
265
+ # rdi == NULL || writable: rdi
266
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
267
+ # rcx == NULL || (u16)[rcx] == NULL
268
+ #
269
+ # 0x51e32 posix_spawn(rdi, "/bin/sh", rdx, rcx, r8, [rax])
246
270
  # constraints:
247
- # esi is the GOT address of libc
248
- # [esp+0x34] == NULL
271
+ # address rsp+0x68 is writable
272
+ # rsp & 0xf == 0
273
+ # [r8] == NULL || r8 is a valid argv
274
+ # [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp
275
+ # rdi == NULL || writable: rdi
276
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
277
+ # rcx == NULL || (u16)[rcx] == NULL
249
278
  #
250
- # 0x3cbec execve("/bin/sh", esp+0x38, environ)
279
+ # 0x84135 posix_spawn(rbx+0xe0, "/bin/sh", r12, 0, rsp+0x60, environ)
251
280
  # constraints:
252
- # esi is the GOT address of libc
253
- # [esp+0x38] == NULL
281
+ # address rsp+0x70 is writable
282
+ # rsp & 0xf == 0
283
+ # {"sh", "-c", rbp, NULL} is a valid argv
284
+ # rbx+0xe0 == NULL || writable: rbx+0xe0
285
+ # r12 == NULL || (s32)[r12+0x4] <= 0
254
286
  #
255
- # 0x3cbf0 execve("/bin/sh", esp+0x3c, environ)
287
+ # 0x8413c posix_spawn(rbx+0xe0, "/bin/sh", r12, 0, rsp+0x60, environ)
256
288
  # constraints:
257
- # esi is the GOT address of libc
258
- # [esp+0x3c] == NULL
289
+ # address rsp+0x70 is writable
290
+ # rsp & 0xf == 0
291
+ # rax == NULL || {"sh", rax, rbp, NULL} is a valid argv
292
+ # rbx+0xe0 == NULL || writable: rbx+0xe0
293
+ # r12 == NULL || (s32)[r12+0x4] <= 0
259
294
  #
260
- # 0x3cbf7 execve("/bin/sh", esp+0x40, environ)
295
+ # 0x84143 posix_spawn(rbx+0xe0, "/bin/sh", r12, 0, rsp+0x60, environ)
261
296
  # constraints:
262
- # esi is the GOT address of libc
263
- # [esp+0x40] == NULL
297
+ # address rsp+0x70 is writable
298
+ # rsp & 0xf == 0
299
+ # rcx == NULL || {rcx, rax, rbp, NULL} is a valid argv
300
+ # rbx+0xe0 == NULL || writable: rbx+0xe0
301
+ # r12 == NULL || (s32)[r12+0x4] <= 0
264
302
  #
265
- # 0x6729f execl("/bin/sh", eax)
303
+ # 0x84146 posix_spawn(rbx+0xe0, "/bin/sh", rdx, 0, rsp+0x60, environ)
266
304
  # constraints:
267
- # esi is the GOT address of libc
268
- # eax == NULL
305
+ # address rsp+0x70 is writable
306
+ # rsp & 0xf == 0
307
+ # rcx == NULL || {rcx, rax, rbp, NULL} is a valid argv
308
+ # rbx+0xe0 == NULL || writable: rbx+0xe0
309
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
269
310
  #
270
- # 0x672a0 execl("/bin/sh", [esp])
311
+ # 0x8414b posix_spawn(rbx+0xe0, "/bin/sh", rdx, 0, rsp+0x60, environ)
271
312
  # constraints:
272
- # esi is the GOT address of libc
273
- # [esp] == NULL
313
+ # address rsp+0x78 is writable
314
+ # rsp & 0xf == 0
315
+ # rcx == NULL || {rcx, rax, [rsp+0x70], NULL} is a valid argv
316
+ # rbx+0xe0 == NULL || writable: rbx+0xe0
317
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
318
+ #
319
+ # 0x84150 posix_spawn(rbx+0xe0, "/bin/sh", rdx, 0, rsp+0x60, environ)
320
+ # constraints:
321
+ # address rsp+0x78 is writable
322
+ # rsp & 0xf == 0
323
+ # rcx == NULL || {rcx, (u64)xmm1, [rsp+0x70], NULL} is a valid argv
324
+ # rbx+0xe0 == NULL || writable: rbx+0xe0
325
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
326
+ #
327
+ # 0x8415c posix_spawn(rbx+0xe0, "/bin/sh", rdx, 0, rsp+0x60, [rax])
328
+ # constraints:
329
+ # address rsp+0x78 is writable
330
+ # rsp & 0xf == 0
331
+ # (u64)xmm0 == NULL || {(u64)xmm0, (u64)xmm1, [rsp+0x70], NULL} is a valid argv
332
+ # [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp
333
+ # rbx+0xe0 == NULL || writable: rbx+0xe0
334
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
335
+ #
336
+ # 0x84162 posix_spawn(rbx+0xe0, "/bin/sh", rdx, rcx, rsp+0x60, [rax])
337
+ # constraints:
338
+ # address rsp+0x78 is writable
339
+ # rsp & 0xf == 0
340
+ # (u64)xmm0 == NULL || {(u64)xmm0, (u64)(xmm0 >> 64), [rsp+0x70], NULL} is a valid argv
341
+ # [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp
342
+ # rbx+0xe0 == NULL || writable: rbx+0xe0
343
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
344
+ # rcx == NULL || (u16)[rcx] == NULL
345
+ #
346
+ # 0x84169 posix_spawn(rdi, "/bin/sh", rdx, rcx, rsp+0x60, [rax])
347
+ # constraints:
348
+ # address rsp+0x78 is writable
349
+ # rsp & 0xf == 0
350
+ # (u64)xmm0 == NULL || {(u64)xmm0, (u64)(xmm0 >> 64), [rsp+0x70], NULL} is a valid argv
351
+ # [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp
352
+ # rdi == NULL || writable: rdi
353
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
354
+ # rcx == NULL || (u16)[rcx] == NULL
355
+ #
356
+ # 0x84170 posix_spawn(rdi, "/bin/sh", rdx, rcx, r8, [rax])
357
+ # constraints:
358
+ # address rsp+0x78 is writable
359
+ # rsp & 0xf == 0
360
+ # [r8] == NULL || r8 is a valid argv
361
+ # [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp
362
+ # rdi == NULL || writable: rdi
363
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
364
+ # rcx == NULL || (u16)[rcx] == NULL
365
+ #
366
+ # 0xe3afe execve("/bin/sh", r15, r12)
367
+ # constraints:
368
+ # [r15] == NULL || r15 == NULL || r15 is a valid argv
369
+ # [r12] == NULL || r12 == NULL || r12 is a valid envp
370
+ #
371
+ # 0xe3b01 execve("/bin/sh", r15, rdx)
372
+ # constraints:
373
+ # [r15] == NULL || r15 == NULL || r15 is a valid argv
374
+ # [rdx] == NULL || rdx == NULL || rdx is a valid envp
375
+ #
376
+ # 0xe3b04 execve("/bin/sh", rsi, rdx)
377
+ # constraints:
378
+ # [rsi] == NULL || rsi == NULL || rsi is a valid argv
379
+ # [rdx] == NULL || rdx == NULL || rdx is a valid envp
380
+ #
381
+ # 0xe3cf3 execve("/bin/sh", r10, r12)
382
+ # constraints:
383
+ # address rbp-0x78 is writable
384
+ # [r10] == NULL || r10 == NULL || r10 is a valid argv
385
+ # [r12] == NULL || r12 == NULL || r12 is a valid envp
386
+ #
387
+ # 0xe3cf6 execve("/bin/sh", r10, rdx)
388
+ # constraints:
389
+ # address rbp-0x78 is writable
390
+ # [r10] == NULL || r10 == NULL || r10 is a valid argv
391
+ # [rdx] == NULL || rdx == NULL || rdx is a valid envp
274
392
  #
275
- # 0x13573e execl("/bin/sh", eax)
393
+ # 0xe3d62 execve("/bin/sh", rbp-0x50, r12)
276
394
  # constraints:
395
+ # address rbp-0x48 is writable
396
+ # r13 == NULL || {"/bin/sh", r13, NULL} is a valid argv
397
+ # [r12] == NULL || r12 == NULL || r12 is a valid envp
398
+ #
399
+ # 0xe3d69 execve("/bin/sh", rbp-0x50, r12)
400
+ # constraints:
401
+ # address rbp-0x48 is writable
402
+ # rax == NULL || {rax, r13, NULL} is a valid argv
403
+ # [r12] == NULL || r12 == NULL || r12 is a valid envp
404
+ #
405
+ # 0xe3d70 execve("/bin/sh", rbp-0x50, r12)
406
+ # constraints:
407
+ # address rbp-0x50 is writable
408
+ # rax == NULL || {rax, [rbp-0x48], NULL} is a valid argv
409
+ # [r12] == NULL || r12 == NULL || r12 is a valid envp
410
+ #
411
+ # 0xe3da7 execve("/bin/sh", rbp-0x50, r12)
412
+ # constraints:
413
+ # address rbp-0x50 is writable
414
+ # [rbp-0x68] == NULL || {"/bin/sh", [rbp-0x68], NULL} is a valid argv
415
+ # [r12] == NULL || r12 == NULL || r12 is a valid envp
416
+ #
417
+ # 0xe3db1 execve("/bin/sh", rbp-0x50, r12)
418
+ # constraints:
419
+ # address rbp-0x50 is writable
420
+ # rax == NULL || {rax, [rbp-0x68], NULL} is a valid argv
421
+ # [r12] == NULL || r12 == NULL || r12 is a valid envp
422
+ #
423
+ # 0xe3db5 execve("/bin/sh", r10, r12)
424
+ # constraints:
425
+ # addresses r10+0x10, rbp-0x50 are writable
426
+ # [r10] == NULL || r10 == NULL || r10 is a valid argv
427
+ # [r12] == NULL || r12 == NULL || r12 is a valid envp
428
+ #
429
+ # 0xe3dbd execve("/bin/sh", r10, r12)
430
+ # constraints:
431
+ # addresses r10+0x10, rbp-0x48 are writable
432
+ # [r10] == NULL || r10 == NULL || r10 is a valid argv
433
+ # [r12] == NULL || r12 == NULL || r12 is a valid envp
434
+ #
435
+ # 0x1077ca posix_spawn(rsp+0x64, "/bin/sh", [rsp+0x38], 0, rsp+0x70, [rsp+0xf0])
436
+ # constraints:
437
+ # [rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a valid argv
438
+ # [[rsp+0xf0]] == NULL || [rsp+0xf0] == NULL || [rsp+0xf0] is a valid envp
439
+ # [rsp+0x38] == NULL || (s32)[[rsp+0x38]+0x4] <= 0
440
+ #
441
+ # 0x1077d2 posix_spawn(rsp+0x64, "/bin/sh", [rsp+0x38], 0, rsp+0x70, r9)
442
+ # constraints:
443
+ # [rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a valid argv
444
+ # [r9] == NULL || r9 == NULL || r9 is a valid envp
445
+ # [rsp+0x38] == NULL || (s32)[[rsp+0x38]+0x4] <= 0
446
+ #
447
+ # 0x1077d7 posix_spawn(rsp+0x64, "/bin/sh", rdx, 0, rsp+0x70, r9)
448
+ # constraints:
449
+ # [rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a valid argv
450
+ # [r9] == NULL || r9 == NULL || r9 is a valid envp
451
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
452
+ #
453
+ # 0x1077e1 posix_spawn(rdi, "/bin/sh", rdx, 0, r8, r9)
454
+ # constraints:
455
+ # [r8] == NULL || r8 is a valid argv
456
+ # [r9] == NULL || r9 == NULL || r9 is a valid envp
457
+ # rdi == NULL || writable: rdi
458
+ # rdx == NULL || (s32)[rdx+0x4] <= 0
459
+
460
+ ```
461
+
462
+ #### Other Architectures
463
+
464
+ ##### i386
465
+ ```bash
466
+ $ one_gadget /lib32/libc.so.6
467
+ # 0xc890b execve("/bin/sh", [ebp-0x2c], esi)
468
+ # constraints:
469
+ # address ebp-0x20 is writable
277
470
  # ebx is the GOT address of libc
471
+ # [[ebp-0x2c]] == NULL || [ebp-0x2c] == NULL || [ebp-0x2c] is a valid argv
472
+ # [esi] == NULL || esi == NULL || esi is a valid envp
473
+ #
474
+ # 0x1421b3 execl("/bin/sh", eax)
475
+ # constraints:
476
+ # ebp is the GOT address of libc
278
477
  # eax == NULL
279
478
  #
280
- # 0x13573f execl("/bin/sh", [esp])
479
+ # 0x1421b4 execl("/bin/sh", [esp])
281
480
  # constraints:
282
- # ebx is the GOT address of libc
481
+ # ebp is the GOT address of libc
283
482
  # [esp] == NULL
284
483
 
285
484
  ```
@@ -324,15 +523,15 @@ $ one_gadget ./spec/data/libc-2.19.so -s 'echo "offset ->"'
324
523
  ```ruby
325
524
  require 'one_gadget'
326
525
  OneGadget.gadgets(file: '/lib/x86_64-linux-gnu/libc.so.6')
327
- #=> [324293, 324386, 1090444]
526
+ #=> [932606, 932609, 932612]
328
527
 
329
528
  # or in shorter way
330
529
  one_gadget('/lib/x86_64-linux-gnu/libc.so.6', level: 1)
331
- #=> [324293, 324386, 939679, 940120, 940127, 940131, 1090444, 1090456]
530
+ #=> [335355, 335362, 335369, 335376, 335381, 335397, 335402, 335405, 335410, 540981, 540988, 540995, 540998, 541003, 541008, 541020, 541026, 541033, 541040, 932606, 932609, 932612, 933107, 933110, 933218, 933225, 933232, 933287, 933297, 933301, 933309, 1079242, 1079250, 1079255, 1079265]
332
531
 
333
532
  # from build id
334
533
  one_gadget('b417c0ba7cc5cf06d1d1bed6652cedb9253c60d0')
335
- #=> [324293, 324386, 1090444]
534
+ #=> [324286, 324293, 324386, 1090444]
336
535
 
337
536
  ```
338
537
 
@@ -343,7 +542,7 @@ def one_gadget(filename):
343
542
  return [int(i) for i in subprocess.check_output(['one_gadget', '--raw', filename]).decode().split(' ')]
344
543
 
345
544
  one_gadget('/lib/x86_64-linux-gnu/libc.so.6')
346
- #=> [324293, 324386, 1090444]
545
+ #=> [932606, 932609, 932612]
347
546
 
348
547
  ```
349
548
 
@@ -12,7 +12,7 @@ module OneGadget
12
12
  # Help message.
13
13
  USAGE = 'Usage: one_gadget <FILE|-b BuildID> [options]'
14
14
  # Default options.
15
- DEFAULT_OPTIONS = { raw: false, force_file: false, level: 0, base: 0 }.freeze
15
+ DEFAULT_OPTIONS = { format: :pretty, force_file: false, level: 0, base: 0 }.freeze
16
16
 
17
17
  module_function
18
18
 
@@ -49,9 +49,9 @@ module OneGadget
49
49
  return show(parser.help) && false unless build_id || libc_file
50
50
 
51
51
  gadgets = if build_id
52
- OneGadget.gadgets(build_id: build_id, details: true, level: level)
52
+ OneGadget.gadgets(build_id:, details: true, level:)
53
53
  else # libc_file
54
- OneGadget.gadgets(file: libc_file, details: true, force_file: @options[:force_file], level: level)
54
+ OneGadget.gadgets(file: libc_file, details: true, force_file: @options[:force_file], level:)
55
55
  end
56
56
  gadgets.each { |g| g.base = @options[:base] }
57
57
  handle_gadgets(gadgets, libc_file)
@@ -66,7 +66,7 @@ module OneGadget
66
66
  return handle_script(gadgets, @options[:script]) if @options[:script]
67
67
  return handle_near(libc_file, gadgets, @options[:near]) if @options[:near]
68
68
 
69
- display_gadgets(gadgets, @options[:raw])
69
+ display_gadgets(gadgets, @options[:format])
70
70
  end
71
71
 
72
72
  # Displays libc information given BuildID.
@@ -119,13 +119,18 @@ module OneGadget
119
119
  @options[:level] = l
120
120
  end
121
121
 
122
- opts.on('-n', '--near FUNCTIONS/FILE', 'Order gadgets by their distance to the given functions'\
123
- ' or to the GOT functions of the given file.') do |n|
122
+ opts.on('-n', '--near FUNCTIONS/FILE', 'Order gadgets by their distance to the given functions ' \
123
+ 'or to the GOT functions of the given file.') do |n|
124
124
  @options[:near] = n
125
125
  end
126
126
 
127
- opts.on('-r', '--[no-]raw', 'Output gadgets offset only, split with one space.') do |v|
128
- @options[:raw] = v
127
+ opts.on('-o FORMAT', '--output-format FORMAT', %i[pretty raw json],
128
+ 'Output format. FORMAT should be one of <pretty|raw|json>.', 'Default: pretty') do |o|
129
+ @options[:format] = o
130
+ end
131
+
132
+ opts.on('-r', '--raw', 'Alias of -o raw. Output gadgets offset only, split with one space.') do |_|
133
+ @options[:format] = :raw
129
134
  end
130
135
 
131
136
  opts.on('-s', '--script exploit-script', 'Run exploit script with all possible gadgets.',
@@ -176,14 +181,19 @@ module OneGadget
176
181
 
177
182
  # Writes gadgets to stdout.
178
183
  # @param [Array<OneGadget::Gadget::Gadget>] gadgets
179
- # @param [Boolean] raw
180
- # In raw mode, only the offset of gadgets are printed.
184
+ # @param [Symbol] format
185
+ # :raw - Only the offset of gadgets are printed.
186
+ # :pretty - Colorful and human-readable format.
187
+ # :json - In JSON format.
181
188
  # @return [true]
182
- def display_gadgets(gadgets, raw)
183
- if raw
189
+ def display_gadgets(gadgets, format)
190
+ case format
191
+ when :raw
184
192
  show(gadgets.map(&:value).join(' '))
185
- else
193
+ when :pretty
186
194
  show(gadgets.map(&:inspect).join("\n"))
195
+ when :json
196
+ show(gadgets.to_json)
187
197
  end
188
198
  end
189
199
 
@@ -199,7 +209,7 @@ module OneGadget
199
209
  # @param [String] libc_file
200
210
  # @param [Array<OneGadget::Gadget::Gadget>] gadgets
201
211
  # @param [String] near
202
- # This can be name of functions or an ELF file.
212
+ # Either name of functions or path to an ELF file.
203
213
  # - Use one comma without spaces to specify a list of functions: +printf,scanf,free+.
204
214
  # - Path to an ELF file and take its GOT functions to process: +/bin/ls+
205
215
  def handle_near(libc_file, gadgets, near)
@@ -213,10 +223,19 @@ module OneGadget
213
223
  function_offsets = OneGadget::Helper.function_offsets(libc_file, functions)
214
224
  return error('No functions for processing') if function_offsets.empty?
215
225
 
216
- function_offsets.each do |function, offset|
217
- colored_offset = OneGadget::Helper.colored_hex(offset)
218
- OneGadget::Logger.warn("Gadgets near #{OneGadget::Helper.colorize(function)}(#{colored_offset}):")
219
- display_gadgets(gadgets.sort_by { |gadget| (gadget.offset - offset).abs }, @options[:raw])
226
+ collection = function_offsets.map do |function, offset|
227
+ {
228
+ near: function,
229
+ near_offset: offset,
230
+ gadgets: gadgets.sort_by { |gadget| (gadget.offset - offset).abs }
231
+ }
232
+ end
233
+ return show(collection.to_json) if @options[:format] == :json
234
+
235
+ collection.each do |c|
236
+ colored_offset = OneGadget::Helper.colored_hex(c[:near_offset])
237
+ OneGadget::Logger.warn("Gadgets near #{OneGadget::Helper.colorize(c[:near])}(#{colored_offset}):")
238
+ display_gadgets(c[:gadgets], @options[:format])
220
239
  show("\n")
221
240
  end
222
241
  true
@@ -18,8 +18,8 @@ module OneGadget
18
18
 
19
19
  # @see OneGadget::Emulators::X86#process!
20
20
  def process!(cmd)
21
- inst, args = parse(cmd.gsub(/#-?(0x)?[0-9a-f]+/) { |v| v[1..-1] })
22
- sym = "inst_#{inst.inst}".to_sym
21
+ inst, args = parse(cmd.gsub(/#-?(0x)?[0-9a-f]+/) { |v| v[1..] })
22
+ sym = :"inst_#{inst.inst}"
23
23
  __send__(sym, *args) != :fail
24
24
  end
25
25
 
@@ -31,7 +31,7 @@ module OneGadget
31
31
  idx = cmd.index(inst)
32
32
  cmd = cmd[0...cmd.rindex('//')] if cmd.rindex('//')
33
33
  cmd = cmd[0...cmd.rindex('#')] if cmd.rindex('#')
34
- args = parse_args(cmd[idx + inst.size..-1])
34
+ args = parse_args(cmd[idx + inst.size..])
35
35
  unless argc.include?(args.size)
36
36
  raise OneGadget::Error::InstructionArgumentError, "Incorrect argument number in #{cmd}, expect: #{argc}"
37
37
  end
@@ -43,7 +43,7 @@ module OneGadget
43
43
  # @param [Numeric] other Value to substract.
44
44
  # @return [Lambda] The result.
45
45
  def -(other)
46
- self.+(-other)
46
+ self + -other
47
47
  end
48
48
 
49
49
  # Increase dereference count by 1.
@@ -123,8 +123,8 @@ module OneGadget
123
123
  # nested []
124
124
  if arg[0] == '['
125
125
  ridx = arg.rindex(']')
126
- immi = parse(arg[(ridx + 1)..-1])
127
- lm = parse(arg[1...ridx], predefined: predefined).deref
126
+ immi = parse(arg[(ridx + 1)..])
127
+ lm = parse(arg[1...ridx], predefined:).deref
128
128
  lm += immi unless immi.zero?
129
129
  return lm
130
130
  end
@@ -19,7 +19,7 @@ module OneGadget
19
19
  # @param [String] sp
20
20
  # The stack register.
21
21
  def initialize(registers, sp)
22
- @registers = registers.map { |reg| [reg, to_lambda(reg)] }.to_h
22
+ @registers = registers.to_h { |reg| [reg, to_lambda(reg)] }
23
23
  @sp = sp
24
24
  @constraints = []
25
25
  @sp_based_stack = Hash.new do |h, k|
@@ -36,7 +36,7 @@ module OneGadget
36
36
  # return registers[pc] = args[0] if inst.inst == 'call'
37
37
  return true if inst.inst == 'jmp' # believe the fetcher has handled jmp.
38
38
 
39
- sym = "inst_#{inst.inst}".to_sym
39
+ sym = :"inst_#{inst.inst}"
40
40
  __send__(sym, *args) != :fail
41
41
  end
42
42
 
@@ -20,7 +20,7 @@ module OneGadget
20
20
  # +nil+ is returned if cannot find target id in database.
21
21
  def from_build_id(build_id, remote: true)
22
22
  OneGadget::Helper.verify_build_id!(build_id)
23
- OneGadget::Gadget.builds(build_id, remote: remote)
23
+ OneGadget::Gadget.builds(build_id, remote:)
24
24
  end
25
25
 
26
26
  # Fetch one-gadget offsets from file.
@@ -28,7 +28,7 @@ module OneGadget
28
28
  # use processor to find which can lead to a valid one-gadget call.
29
29
  gadgets = []
30
30
  (lines.size - 2).downto(0) do |i|
31
- processor = emulate(lines[i..-1])
31
+ processor = emulate(lines[i..])
32
32
  options = resolve(processor)
33
33
  next if options.nil? # impossible to be a gadget
34
34
 
@@ -48,7 +48,7 @@ module OneGadget
48
48
  # True for valid.
49
49
  # @return [Array<String>]
50
50
  # Each +String+ returned is multi-lines of assembly code.
51
- def candidates(&block)
51
+ def candidates(&)
52
52
  call_regexp = "#{call_str}.*<(exec[^+]*|posix_spawn[^+]*)>$"
53
53
  cands = []
54
54
  `#{@objdump.command}|grep -E '#{call_regexp}' -B 30`.split('--').each do |cand|
@@ -63,7 +63,7 @@ module OneGadget
63
63
  end
64
64
  # remove all jmps
65
65
  cands = slice_prefix(cands, &method(:branch?))
66
- cands.select!(&block) if block_given?
66
+ cands.select!(&) if block_given?
67
67
  cands
68
68
  end
69
69
 
@@ -81,7 +81,8 @@ module OneGadget
81
81
  call = processor.registers[processor.pc].to_s
82
82
  return resolve_posix_spawn(processor) if call.include?('posix_spawn')
83
83
  return resolve_execve(processor) if call.include?('execve')
84
- return resolve_execl(processor) if call.include?('execl')
84
+
85
+ resolve_execl(processor) if call.include?('execl')
85
86
  end
86
87
 
87
88
  def resolve_execve(processor)
@@ -110,7 +111,7 @@ module OneGadget
110
111
  envp = arg2
111
112
  end
112
113
 
113
- { constraints: cons, envp: envp }
114
+ { constraints: cons, envp: }
114
115
  end
115
116
 
116
117
  def check_argv(processor, arg, allow_null)
@@ -282,7 +283,7 @@ module OneGadget
282
283
  cands.map do |cand|
283
284
  lines = cand.lines
284
285
  to_rm = lines[0...-1].rindex(&block)
285
- lines = lines[to_rm + 1..-1] unless to_rm.nil?
286
+ lines = lines[to_rm + 1..] unless to_rm.nil?
286
287
  lines.join
287
288
  end
288
289
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+
3
5
  require 'one_gadget/abi'
4
6
  require 'one_gadget/emulators/lambda'
5
7
  require 'one_gadget/error'
@@ -28,13 +30,12 @@ module OneGadget
28
30
  @base = 0
29
31
  @offset = offset
30
32
  @constraints = options[:constraints] || []
31
- @effect = options[:effect]
33
+ @effect = options[:effect] || ''
32
34
  end
33
35
 
34
36
  # Show gadget in a pretty way.
35
37
  def inspect
36
- str = OneGadget::Helper.hex(value)
37
- str += effect ? " #{effect}\n" : "\n"
38
+ str = "#{OneGadget::Helper.hex(value)} #{effect}\n"
38
39
  unless constraints.empty?
39
40
  str += "#{OneGadget::Helper.colorize('constraints')}:\n "
40
41
  str += merge_constraints.join("\n ")
@@ -46,6 +47,21 @@ module OneGadget
46
47
  "#{str}\n"
47
48
  end
48
49
 
50
+ # @return [Hash]
51
+ def to_obj
52
+ {
53
+ value:,
54
+ effect:,
55
+ constraints:
56
+ }
57
+ end
58
+
59
+ # To have this class can be serialized in JSON.
60
+ # @return [String]
61
+ def to_json(*)
62
+ to_obj.to_json
63
+ end
64
+
49
65
  # @return [Integer]
50
66
  # Returns +base+ plus +offset+.
51
67
  def value
@@ -112,7 +128,7 @@ module OneGadget
112
128
  w_cons, normal = constraints.partition { |c| c.start_with?(key) }
113
129
  return normal if w_cons.empty?
114
130
 
115
- w_cons.map! { |c| c[key.size..-1] }
131
+ w_cons.map! { |c| c[key.size..] }
116
132
  ["address#{w_cons.size > 1 ? 'es' : ''} #{w_cons.join(', ')} #{w_cons.size > 1 ? 'are' : 'is'} writable"] +
117
133
  normal
118
134
  end
@@ -161,7 +177,7 @@ module OneGadget
161
177
  def builds_info(build_id)
162
178
  raise Error::ArgumentError, "Invalid BuildID #{build_id.inspect}" if build_id =~ /[^0-9a-f]/
163
179
 
164
- files = Dir.glob(File.join(BUILDS_PATH, "*-#{build_id}*.rb")).sort
180
+ files = Dir.glob(File.join(BUILDS_PATH, "*-#{build_id}*.rb"))
165
181
  return OneGadget::Logger.not_found(build_id) && nil if files.empty?
166
182
 
167
183
  if files.size > 1
@@ -189,7 +205,7 @@ module OneGadget
189
205
  def find_build(id)
190
206
  return BUILDS[id] if BUILDS.key?(id)
191
207
 
192
- Dir.glob(File.join(BUILDS_PATH, "*-#{id}.rb")).sort.each do |dic|
208
+ Dir.glob(File.join(BUILDS_PATH, "*-#{id}.rb")).each do |dic|
193
209
  require dic
194
210
  end
195
211
  BUILDS[id] if BUILDS.key?(id)
@@ -13,7 +13,7 @@ module OneGadget
13
13
  # Define some helpful methods here.
14
14
  module Helper
15
15
  # Format of build-id, 40 hex numbers.
16
- BUILD_ID_FORMAT = /[0-9a-f]{40}/.freeze
16
+ BUILD_ID_FORMAT = /[0-9a-f]{40}/
17
17
 
18
18
  module_function
19
19
 
@@ -35,7 +35,7 @@ module OneGadget
35
35
  # @return [Array<String>]
36
36
  # Lines of comments.
37
37
  def comments_of_file(file)
38
- File.readlines(file).map { |s| s[2..-1].rstrip if s.start_with?('# ') }.compact
38
+ File.readlines(file).map { |s| s[2..].rstrip if s.start_with?('# ') }.compact
39
39
  end
40
40
 
41
41
  # Get absolute path from relative path. Support symlink.
@@ -24,14 +24,14 @@ module OneGadget
24
24
  FileUtils.touch(cache_file)
25
25
  OneGadget::Logger.info("Checking for new versions of OneGadget\n" \
26
26
  "To disable this functionality, do\n$ echo never > #{CACHE_FILE}\n\n")
27
- latest = Helper.latest_tag[1..-1] # remove 'v'
27
+ latest = Helper.latest_tag[1..] # remove 'v'
28
28
  if Gem::Version.new(latest) <= Gem::Version.new(OneGadget::VERSION)
29
29
  return OneGadget::Logger.info("You have the latest version of OneGadget (#{latest})!\n\n")
30
30
  end
31
31
 
32
32
  # show update message
33
33
  msg = format('A newer version of OneGadget is available (%s --> %s).', OneGadget::VERSION, latest)
34
- OneGadget::Logger.ask_update(msg: msg)
34
+ OneGadget::Logger.ask_update(msg:)
35
35
  end
36
36
 
37
37
  private
@@ -2,5 +2,5 @@
2
2
 
3
3
  module OneGadget
4
4
  # Current gem version.
5
- VERSION = '1.9.0'
5
+ VERSION = '1.10.0'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: one_gadget
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - david942j
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-29 00:00:00.000000000 Z
11
+ date: 2024-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: elftools
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: 1.0.2
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 1.2.0
22
+ version: 1.4.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: 1.0.2
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 1.2.0
32
+ version: 1.4.0
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: rake
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -1014,14 +1014,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
1014
1014
  requirements:
1015
1015
  - - ">="
1016
1016
  - !ruby/object:Gem::Version
1017
- version: '2.4'
1017
+ version: '3.1'
1018
1018
  required_rubygems_version: !ruby/object:Gem::Requirement
1019
1019
  requirements:
1020
1020
  - - ">="
1021
1021
  - !ruby/object:Gem::Version
1022
1022
  version: '0'
1023
1023
  requirements: []
1024
- rubygems_version: 3.1.6
1024
+ rubygems_version: 3.5.3
1025
1025
  signing_key:
1026
1026
  specification_version: 4
1027
1027
  summary: one_gadget