one_gadget 1.7.1 → 1.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +86 -1
- data/bin/one_gadget +3 -84
- data/lib/one_gadget.rb +2 -0
- data/lib/one_gadget/abi.rb +2 -0
- data/lib/one_gadget/builds/libc-2.23-1ca54a6e0d76188105b12e49fe6b8019bf08803a.rb +46 -0
- data/lib/one_gadget/builds/libc-2.23-9a6b57c7a4f93d7e54e61bccb7df996c8bc58141.rb +46 -0
- data/lib/one_gadget/cli.rb +220 -0
- data/lib/one_gadget/emulators/aarch64.rb +2 -7
- data/lib/one_gadget/emulators/amd64.rb +2 -0
- data/lib/one_gadget/emulators/i386.rb +2 -0
- data/lib/one_gadget/emulators/instruction.rb +2 -0
- data/lib/one_gadget/emulators/lambda.rb +12 -4
- data/lib/one_gadget/emulators/processor.rb +2 -0
- data/lib/one_gadget/emulators/x86.rb +2 -0
- data/lib/one_gadget/error.rb +2 -0
- data/lib/one_gadget/fetcher.rb +2 -0
- data/lib/one_gadget/fetchers/aarch64.rb +2 -0
- data/lib/one_gadget/fetchers/amd64.rb +2 -0
- data/lib/one_gadget/fetchers/base.rb +2 -0
- data/lib/one_gadget/fetchers/i386.rb +2 -0
- data/lib/one_gadget/fetchers/x86.rb +2 -0
- data/lib/one_gadget/gadget.rb +2 -0
- data/lib/one_gadget/helper.rb +36 -1
- data/lib/one_gadget/logger.rb +5 -1
- data/lib/one_gadget/one_gadget.rb +3 -1
- data/lib/one_gadget/update.rb +2 -0
- data/lib/one_gadget/version.rb +3 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8408e8896c26b1f1841de6d054d3535f557e9460d0cf888b11d9bf0e84794b92
|
4
|
+
data.tar.gz: 61f4578f7bc943a7bf2914807769285832870af127c615e45635b89dc1a66a19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e8462690bcbdfa1424cc9374f71a027423f544b956153507b9cb6bf0ee4d829656eb559d90016ec399595a4de32dc6475155347cb417b806d10e6b9bf78f010
|
7
|
+
data.tar.gz: 4180279e347d9f1623ece4cd1829da966c9f759062ac787d5910019e10b7eae0f7b46e75b419997e9d8cbf1df8fc4a1aa9f7e4e02ca0557d2fb8973e5a10f2b1
|
data/README.md
CHANGED
@@ -44,13 +44,14 @@ The article introducing how I develop this tool can be found [on my blog](https:
|
|
44
44
|
|
45
45
|
```bash
|
46
46
|
$ one_gadget
|
47
|
-
# Usage: one_gadget
|
47
|
+
# Usage: one_gadget <FILE|-b BuildID> [options]
|
48
48
|
# -b, --build-id BuildID BuildID[sha1] of libc.
|
49
49
|
# -f, --[no-]force-file Force search gadgets in file instead of build id first.
|
50
50
|
# -l, --level OUTPUT_LEVEL The output level.
|
51
51
|
# OneGadget automatically selects gadgets with higher successful probability.
|
52
52
|
# Increase this level to ask OneGadget show more gadgets it found.
|
53
53
|
# Default: 0
|
54
|
+
# -n, --near FUNCTIONS/FILE Order gadgets by their distance to the given functions or to the GOT functions of the given file.
|
54
55
|
# -r, --[no-]raw Output gadgets offset only, split with one space.
|
55
56
|
# -s, --script exploit-script Run exploit script with all possible gadgets.
|
56
57
|
# The script will be run as 'exploit-script $offset'.
|
@@ -98,6 +99,90 @@ $ one_gadget -b aad7dbe330f23ea00ca63daf793b766b51aceb5d
|
|
98
99
|
```
|
99
100
|
![build id](https://github.com/david942j/one_gadget/blob/master/examples/from_build_id.png?raw=true)
|
100
101
|
|
102
|
+
#### Gadgets Near Functions
|
103
|
+
|
104
|
+
##### Why
|
105
|
+
|
106
|
+
Consider this scenario when exploiting:
|
107
|
+
1. Able to write on GOT (Global Offset Table)
|
108
|
+
2. Libc base address is unknown
|
109
|
+
|
110
|
+
In this scenario you can choose to write two low-byte on a GOT entry with one-gadget's two low-byte.
|
111
|
+
If the function offset on GOT is close enough with the one-gadget,
|
112
|
+
you will have at least 1/16 chance of success.
|
113
|
+
|
114
|
+
##### Usage
|
115
|
+
|
116
|
+
Reorder gadgets according to the distance of given functions.
|
117
|
+
|
118
|
+
```bash
|
119
|
+
$ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near exit,mkdir
|
120
|
+
# [OneGadget] Gadgets near exit(0x43120):
|
121
|
+
# 0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
|
122
|
+
# constraints:
|
123
|
+
# rcx == NULL
|
124
|
+
#
|
125
|
+
# 0x4f322 execve("/bin/sh", rsp+0x40, environ)
|
126
|
+
# constraints:
|
127
|
+
# [rsp+0x40] == NULL
|
128
|
+
#
|
129
|
+
# 0x10a38c execve("/bin/sh", rsp+0x70, environ)
|
130
|
+
# constraints:
|
131
|
+
# [rsp+0x70] == NULL
|
132
|
+
#
|
133
|
+
# [OneGadget] Gadgets near mkdir(0x10fbb0):
|
134
|
+
# 0x10a38c execve("/bin/sh", rsp+0x70, environ)
|
135
|
+
# constraints:
|
136
|
+
# [rsp+0x70] == NULL
|
137
|
+
#
|
138
|
+
# 0x4f322 execve("/bin/sh", rsp+0x40, environ)
|
139
|
+
# constraints:
|
140
|
+
# [rsp+0x40] == NULL
|
141
|
+
#
|
142
|
+
# 0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
|
143
|
+
# constraints:
|
144
|
+
# rcx == NULL
|
145
|
+
#
|
146
|
+
|
147
|
+
```
|
148
|
+
![near](https://github.com/david942j/one_gadget/blob/master/examples/near.png?raw=true)
|
149
|
+
|
150
|
+
Regular expression is acceptable.
|
151
|
+
```bash
|
152
|
+
$ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near 'write.*' --raw
|
153
|
+
# [OneGadget] Gadgets near writev(0x1166a0):
|
154
|
+
# 1090444 324386 324293
|
155
|
+
#
|
156
|
+
# [OneGadget] Gadgets near write(0x110140):
|
157
|
+
# 1090444 324386 324293
|
158
|
+
#
|
159
|
+
|
160
|
+
```
|
161
|
+
|
162
|
+
Pass an ELF file as the argument, OneGadget will take all GOT functions for processing.
|
163
|
+
```bash
|
164
|
+
$ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near spec/data/test_near_file.elf --raw
|
165
|
+
# [OneGadget] Gadgets near exit(0x43120):
|
166
|
+
# 324293 324386 1090444
|
167
|
+
#
|
168
|
+
# [OneGadget] Gadgets near puts(0x809c0):
|
169
|
+
# 324386 324293 1090444
|
170
|
+
#
|
171
|
+
# [OneGadget] Gadgets near printf(0x64e80):
|
172
|
+
# 324386 324293 1090444
|
173
|
+
#
|
174
|
+
# [OneGadget] Gadgets near strlen(0x9dc70):
|
175
|
+
# 324386 324293 1090444
|
176
|
+
#
|
177
|
+
# [OneGadget] Gadgets near __cxa_finalize(0x43520):
|
178
|
+
# 324293 324386 1090444
|
179
|
+
#
|
180
|
+
# [OneGadget] Gadgets near __libc_start_main(0x21ab0):
|
181
|
+
# 324293 324386 1090444
|
182
|
+
#
|
183
|
+
|
184
|
+
```
|
185
|
+
|
101
186
|
#### Show All Gadgets
|
102
187
|
|
103
188
|
Sometimes `one_gadget` finds too many gadgets to show them in one screen,
|
data/bin/one_gadget
CHANGED
@@ -1,87 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
require '
|
4
|
+
require 'one_gadget/cli'
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
options = { raw: false }
|
8
|
-
usage = 'Usage: one_gadget [file] [options]'
|
9
|
-
parser = OptionParser.new do |opts|
|
10
|
-
opts.banner = usage
|
11
|
-
|
12
|
-
opts.on('-b', '--build-id BuildID', 'BuildID[sha1] of libc.') do |b|
|
13
|
-
options[:build_id] = b
|
14
|
-
end
|
15
|
-
|
16
|
-
opts.on('-f', '--[no-]force-file', 'Force search gadgets in file instead of build id first.') do |b|
|
17
|
-
options[:force_file] = b
|
18
|
-
end
|
19
|
-
|
20
|
-
opts.on('-l', '--level OUTPUT_LEVEL', Integer, 'The output level.',
|
21
|
-
'OneGadget automatically selects gadgets with higher successful probability.',
|
22
|
-
'Increase this level to ask OneGadget show more gadgets it found.',
|
23
|
-
'Default: 0') do |l|
|
24
|
-
options[:level] = l
|
25
|
-
end
|
26
|
-
|
27
|
-
opts.on('-r', '--[no-]raw', 'Output gadgets offset only, split with one space.') do |v|
|
28
|
-
options[:raw] = v
|
29
|
-
end
|
30
|
-
|
31
|
-
opts.on('-s', '--script exploit-script', 'Run exploit script with all possible gadgets.',
|
32
|
-
'The script will be run as \'exploit-script $offset\'.') do |script|
|
33
|
-
options[:script] = script
|
34
|
-
end
|
35
|
-
|
36
|
-
opts.on('--info BuildID', 'Show version information given BuildID.') do |b|
|
37
|
-
options[:info] = b
|
38
|
-
end
|
39
|
-
|
40
|
-
opts.on('--version', 'Current gem version.') do |v|
|
41
|
-
options[:version] = v
|
42
|
-
end
|
43
|
-
end
|
44
|
-
parser.parse!
|
45
|
-
|
46
|
-
if options[:version]
|
47
|
-
puts "OneGadget Version #{OneGadget::VERSION}"
|
48
|
-
exit(0)
|
49
|
-
end
|
50
|
-
|
51
|
-
def execute(script, offset)
|
52
|
-
pid = fork do
|
53
|
-
exec([script, offset.to_s].join(' '))
|
54
|
-
end
|
55
|
-
Process.wait pid
|
56
|
-
end
|
57
|
-
|
58
|
-
if options[:info]
|
59
|
-
result = OneGadget::Gadget.builds_info(options[:info])
|
60
|
-
exit(1) if result.nil? # error happend
|
61
|
-
OneGadget::Logger.info("Information of #{options[:info]}:\n#{result.join("\n")}\n")
|
62
|
-
exit(0)
|
63
|
-
end
|
64
|
-
|
65
|
-
level = options[:level] || 0
|
66
|
-
if options[:build_id]
|
67
|
-
gadgets = OneGadget.gadgets(build_id: options[:build_id], details: true, level: level)
|
68
|
-
elsif ARGV[0]
|
69
|
-
gadgets = OneGadget.gadgets(file: ARGV[0], details: true, force_file: options[:force_file], level: level)
|
70
|
-
else
|
71
|
-
puts parser.help
|
72
|
-
exit(1)
|
73
|
-
end
|
74
|
-
|
75
|
-
if options[:script]
|
76
|
-
gadgets.map(&:offset).each do |offset|
|
77
|
-
OneGadget::Logger.info("Trying #{OneGadget::Helper.colorize(format('0x%x', offset), sev: :integer)}...\n")
|
78
|
-
execute(options[:script], offset)
|
79
|
-
end
|
80
|
-
exit(0)
|
81
|
-
end
|
82
|
-
|
83
|
-
if options[:raw]
|
84
|
-
puts gadgets.map(&:offset).join(' ')
|
85
|
-
else
|
86
|
-
puts gadgets.map(&:inspect).join("\n")
|
87
|
-
end
|
6
|
+
exit OneGadget::CLI.work(ARGV.dup)
|
data/lib/one_gadget.rb
CHANGED
data/lib/one_gadget/abi.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'one_gadget/gadget'
|
2
|
+
# ubuntu16.04.6-lib-x86_64-linux-gnu-libc-2.23.so
|
3
|
+
#
|
4
|
+
# Advanced Micro Devices X86-64
|
5
|
+
#
|
6
|
+
# GNU C Library (Ubuntu GLIBC 2.23-0ubuntu11) stable release version 2.23, by Roland McGrath et al.
|
7
|
+
# Copyright (C) 2016 Free Software Foundation, Inc.
|
8
|
+
# This is free software; see the source for copying conditions.
|
9
|
+
# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
|
10
|
+
# PARTICULAR PURPOSE.
|
11
|
+
# Compiled by GNU CC version 5.4.0 20160609.
|
12
|
+
# Available extensions:
|
13
|
+
# crypt add-on version 2.1 by Michael Glad and others
|
14
|
+
# GNU Libidn by Simon Josefsson
|
15
|
+
# Native POSIX Threads Library by Ulrich Drepper et al
|
16
|
+
# BIND-8.2.3-T5B
|
17
|
+
# libc ABIs: UNIQUE IFUNC
|
18
|
+
# For bug reporting instructions, please see:
|
19
|
+
# <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
|
20
|
+
|
21
|
+
build_id = File.basename(__FILE__, '.rb').split('-').last
|
22
|
+
OneGadget::Gadget.add(build_id, 283158,
|
23
|
+
constraints: ["rax == NULL"],
|
24
|
+
effect: "execve(\"/bin/sh\", rsp+0x30, environ)")
|
25
|
+
OneGadget::Gadget.add(build_id, 283242,
|
26
|
+
constraints: ["[rsp+0x30] == NULL"],
|
27
|
+
effect: "execve(\"/bin/sh\", rsp+0x30, environ)")
|
28
|
+
OneGadget::Gadget.add(build_id, 839923,
|
29
|
+
constraints: ["[rcx] == NULL || rcx == NULL", "[r12] == NULL || r12 == NULL"],
|
30
|
+
effect: "execve(\"/bin/sh\", rcx, r12)")
|
31
|
+
OneGadget::Gadget.add(build_id, 840136,
|
32
|
+
constraints: ["[rax] == NULL || rax == NULL", "[r12] == NULL || r12 == NULL"],
|
33
|
+
effect: "execve(\"/bin/sh\", rax, r12)")
|
34
|
+
OneGadget::Gadget.add(build_id, 983716,
|
35
|
+
constraints: ["[rsp+0x50] == NULL"],
|
36
|
+
effect: "execve(\"/bin/sh\", rsp+0x50, environ)")
|
37
|
+
OneGadget::Gadget.add(build_id, 983728,
|
38
|
+
constraints: ["[rsi] == NULL || rsi == NULL", "[[rax]] == NULL || [rax] == NULL"],
|
39
|
+
effect: "execve(\"/bin/sh\", rsi, [rax])")
|
40
|
+
OneGadget::Gadget.add(build_id, 987463,
|
41
|
+
constraints: ["[rsp+0x70] == NULL"],
|
42
|
+
effect: "execve(\"/bin/sh\", rsp+0x70, environ)")
|
43
|
+
OneGadget::Gadget.add(build_id, 1009392,
|
44
|
+
constraints: ["[rcx] == NULL || rcx == NULL", "[[rbp-0xf8]] == NULL || [rbp-0xf8] == NULL"],
|
45
|
+
effect: "execve(\"/bin/sh\", rcx, [rbp-0xf8])")
|
46
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'one_gadget/gadget'
|
2
|
+
# ubuntu16.04.06-lib32-libc-2.23.so
|
3
|
+
#
|
4
|
+
# Intel 80386
|
5
|
+
#
|
6
|
+
# GNU C Library (Ubuntu GLIBC 2.23-0ubuntu11) stable release version 2.23, by Roland McGrath et al.
|
7
|
+
# Copyright (C) 2016 Free Software Foundation, Inc.
|
8
|
+
# This is free software; see the source for copying conditions.
|
9
|
+
# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
|
10
|
+
# PARTICULAR PURPOSE.
|
11
|
+
# Compiled by GNU CC version 5.4.0 20160609.
|
12
|
+
# Available extensions:
|
13
|
+
# crypt add-on version 2.1 by Michael Glad and others
|
14
|
+
# GNU Libidn by Simon Josefsson
|
15
|
+
# Native POSIX Threads Library by Ulrich Drepper et al
|
16
|
+
# BIND-8.2.3-T5B
|
17
|
+
# libc ABIs: UNIQUE IFUNC
|
18
|
+
# For bug reporting instructions, please see:
|
19
|
+
# <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
|
20
|
+
|
21
|
+
build_id = File.basename(__FILE__, '.rb').split('-').last
|
22
|
+
OneGadget::Gadget.add(build_id, 239628,
|
23
|
+
constraints: ["esi is the GOT address of libc", "[esp+0x28] == NULL"],
|
24
|
+
effect: "execve(\"/bin/sh\", esp+0x28, environ)")
|
25
|
+
OneGadget::Gadget.add(build_id, 239630,
|
26
|
+
constraints: ["esi is the GOT address of libc", "[esp+0x2c] == NULL"],
|
27
|
+
effect: "execve(\"/bin/sh\", esp+0x2c, environ)")
|
28
|
+
OneGadget::Gadget.add(build_id, 239634,
|
29
|
+
constraints: ["esi is the GOT address of libc", "[esp+0x30] == NULL"],
|
30
|
+
effect: "execve(\"/bin/sh\", esp+0x30, environ)")
|
31
|
+
OneGadget::Gadget.add(build_id, 239641,
|
32
|
+
constraints: ["esi is the GOT address of libc", "[esp+0x34] == NULL"],
|
33
|
+
effect: "execve(\"/bin/sh\", esp+0x34, environ)")
|
34
|
+
OneGadget::Gadget.add(build_id, 239676,
|
35
|
+
constraints: ["esi is the GOT address of libc", "[eax] == NULL || eax == NULL", "[[esp]] == NULL || [esp] == NULL"],
|
36
|
+
effect: "execve(\"/bin/sh\", eax, [esp])")
|
37
|
+
OneGadget::Gadget.add(build_id, 239677,
|
38
|
+
constraints: ["esi is the GOT address of libc", "[[esp]] == NULL || [esp] == NULL", "[[esp+0x4]] == NULL || [esp+0x4] == NULL"],
|
39
|
+
effect: "execve(\"/bin/sh\", [esp], [esp+0x4])")
|
40
|
+
OneGadget::Gadget.add(build_id, 389221,
|
41
|
+
constraints: ["esi is the GOT address of libc", "eax == NULL"],
|
42
|
+
effect: "execl(\"/bin/sh\", eax)")
|
43
|
+
OneGadget::Gadget.add(build_id, 389222,
|
44
|
+
constraints: ["esi is the GOT address of libc", "[esp] == NULL"],
|
45
|
+
effect: "execl(\"/bin/sh\", [esp])")
|
46
|
+
|
@@ -0,0 +1,220 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
require 'one_gadget/logger'
|
6
|
+
require 'one_gadget/one_gadget'
|
7
|
+
require 'one_gadget/version'
|
8
|
+
|
9
|
+
module OneGadget
|
10
|
+
# Methods for command line interface.
|
11
|
+
module CLI
|
12
|
+
# Help message.
|
13
|
+
USAGE = 'Usage: one_gadget <FILE|-b BuildID> [options]'
|
14
|
+
# Default options.
|
15
|
+
DEFAULT_OPTIONS = { raw: false, force_file: false, level: 0 }.freeze
|
16
|
+
|
17
|
+
module_function
|
18
|
+
|
19
|
+
# Main method of CLI.
|
20
|
+
# @param [Array<String>] argv
|
21
|
+
# Command line arguments.
|
22
|
+
# @return [Boolean]
|
23
|
+
# Whether the command execute successfully.
|
24
|
+
# @example
|
25
|
+
# CLI.work(%w[--help])
|
26
|
+
# # usage message
|
27
|
+
# #=> true
|
28
|
+
# CLI.work(%w[--version])
|
29
|
+
# # version message
|
30
|
+
# #=> true
|
31
|
+
# @example
|
32
|
+
# CLI.work([])
|
33
|
+
# # usage message
|
34
|
+
# #=> false
|
35
|
+
# @example
|
36
|
+
# CLI.work(%w[-b b417c0ba7cc5cf06d1d1bed6652cedb9253c60d0 -r])
|
37
|
+
# # 324293 324386 1090444
|
38
|
+
# #=> true
|
39
|
+
def work(argv)
|
40
|
+
@options = DEFAULT_OPTIONS.dup
|
41
|
+
parser.parse!(argv)
|
42
|
+
return show("OneGadget Version #{OneGadget::VERSION}") if @options[:version]
|
43
|
+
return info_build_id(@options[:info]) if @options[:info]
|
44
|
+
|
45
|
+
libc_file = argv.pop
|
46
|
+
build_id = @options[:build_id]
|
47
|
+
level = @options[:level]
|
48
|
+
return error('Either FILE or BuildID can be passed') if libc_file && @options[:build_id]
|
49
|
+
return show(parser.help) && false unless build_id || libc_file
|
50
|
+
|
51
|
+
gadgets = if build_id
|
52
|
+
OneGadget.gadgets(build_id: build_id, details: true, level: level)
|
53
|
+
else # libc_file
|
54
|
+
OneGadget.gadgets(file: libc_file, details: true, force_file: @options[:force_file], level: level)
|
55
|
+
end
|
56
|
+
handle_gadgets(gadgets, libc_file)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Decides how to display fetched gadgets according to options.
|
60
|
+
# @param [Array<OneGadget::Gadget::Gadget>] gadgets
|
61
|
+
# @param [String] libc_file
|
62
|
+
# @return [Boolean]
|
63
|
+
def handle_gadgets(gadgets, libc_file)
|
64
|
+
return false if gadgets.empty? # error occurs when fetching gadgets
|
65
|
+
return handle_script(gadgets, @options[:script]) if @options[:script]
|
66
|
+
return handle_near(libc_file, gadgets, @options[:near]) if @options[:near]
|
67
|
+
|
68
|
+
display_gadgets(gadgets, @options[:raw])
|
69
|
+
end
|
70
|
+
|
71
|
+
# Displays libc information given BuildID.
|
72
|
+
# @param [String] id
|
73
|
+
# @return [Boolean]
|
74
|
+
# +false+ is returned if no information found.
|
75
|
+
# @example
|
76
|
+
# CLI.info_build_id('b417c')
|
77
|
+
# # [OneGadget] Information of b417c:
|
78
|
+
# # spec/data/libc-2.27-b417c0ba7cc5cf06d1d1bed6652cedb9253c60d0.so
|
79
|
+
# #
|
80
|
+
# # Advanced Micro Devices X86-64
|
81
|
+
# #
|
82
|
+
# # GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
|
83
|
+
# # Copyright (C) 2018 Free Software Foundation, Inc.
|
84
|
+
# # This is free software; see the source for copying conditions.
|
85
|
+
# # There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
|
86
|
+
# # PARTICULAR PURPOSE.
|
87
|
+
# # Compiled by GNU CC version 7.3.0.
|
88
|
+
# # libc ABIs: UNIQUE IFUNC
|
89
|
+
# # For bug reporting instructions, please see:
|
90
|
+
# # <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
|
91
|
+
# #=> true
|
92
|
+
def info_build_id(id)
|
93
|
+
result = OneGadget::Gadget.builds_info(id)
|
94
|
+
return false if result.nil? # invalid form or BuildID not found
|
95
|
+
|
96
|
+
OneGadget::Logger.info("Information of #{id}:\n#{result.join("\n")}")
|
97
|
+
true
|
98
|
+
end
|
99
|
+
|
100
|
+
# The option parser.
|
101
|
+
# @return [OptionParser]
|
102
|
+
def parser
|
103
|
+
@parser ||= OptionParser.new do |opts|
|
104
|
+
opts.banner = USAGE
|
105
|
+
|
106
|
+
opts.on('-b', '--build-id BuildID', 'BuildID[sha1] of libc.') do |b|
|
107
|
+
@options[:build_id] = b
|
108
|
+
end
|
109
|
+
|
110
|
+
opts.on('-f', '--[no-]force-file', 'Force search gadgets in file instead of build id first.') do |f|
|
111
|
+
@options[:force_file] = f
|
112
|
+
end
|
113
|
+
|
114
|
+
opts.on('-l', '--level OUTPUT_LEVEL', Integer, 'The output level.',
|
115
|
+
'OneGadget automatically selects gadgets with higher successful probability.',
|
116
|
+
'Increase this level to ask OneGadget show more gadgets it found.',
|
117
|
+
'Default: 0') do |l|
|
118
|
+
@options[:level] = l
|
119
|
+
end
|
120
|
+
|
121
|
+
opts.on('-n', '--near FUNCTIONS/FILE', 'Order gadgets by their distance to the given functions'\
|
122
|
+
' or to the GOT functions of the given file.') do |n|
|
123
|
+
@options[:near] = n
|
124
|
+
end
|
125
|
+
|
126
|
+
opts.on('-r', '--[no-]raw', 'Output gadgets offset only, split with one space.') do |v|
|
127
|
+
@options[:raw] = v
|
128
|
+
end
|
129
|
+
|
130
|
+
opts.on('-s', '--script exploit-script', 'Run exploit script with all possible gadgets.',
|
131
|
+
'The script will be run as \'exploit-script $offset\'.') do |s|
|
132
|
+
@options[:script] = s
|
133
|
+
end
|
134
|
+
|
135
|
+
opts.on('--info BuildID', 'Show version information given BuildID.') do |b|
|
136
|
+
@options[:info] = b
|
137
|
+
end
|
138
|
+
|
139
|
+
opts.on('--version', 'Current gem version.') do |v|
|
140
|
+
@options[:version] = v
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Writes +msg+ to stdout and returns +true+.
|
146
|
+
# @param [String] msg
|
147
|
+
# @return [true]
|
148
|
+
def show(msg)
|
149
|
+
puts msg
|
150
|
+
true
|
151
|
+
end
|
152
|
+
|
153
|
+
# Spawns and waits until the process end.
|
154
|
+
# @param [String] cmd
|
155
|
+
# @return [void]
|
156
|
+
def execute(cmd)
|
157
|
+
Process.wait(spawn(cmd))
|
158
|
+
end
|
159
|
+
|
160
|
+
# Handles the --script feature.
|
161
|
+
# @param [Array<OneGadget::Gadget::Gadget>] gadgets
|
162
|
+
# @param [String] script
|
163
|
+
# @return [true]
|
164
|
+
def handle_script(gadgets, script)
|
165
|
+
gadgets.map(&:offset).each do |offset|
|
166
|
+
OneGadget::Logger.info("Trying #{OneGadget::Helper.colored_hex(offset)}...")
|
167
|
+
execute("#{script} #{offset}")
|
168
|
+
end
|
169
|
+
true
|
170
|
+
end
|
171
|
+
|
172
|
+
# Writes gadgets to stdout.
|
173
|
+
# @param [Array<OneGadget::Gadget::Gadget>] gadgets
|
174
|
+
# @param [Boolean] raw
|
175
|
+
# In raw mode, only the offset of gadgets are printed.
|
176
|
+
# @return [true]
|
177
|
+
def display_gadgets(gadgets, raw)
|
178
|
+
if raw
|
179
|
+
show(gadgets.map(&:offset).join(' '))
|
180
|
+
else
|
181
|
+
show(gadgets.map(&:inspect).join("\n"))
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Logs error.
|
186
|
+
# @param [String] msg
|
187
|
+
# @return [false]
|
188
|
+
def error(msg)
|
189
|
+
OneGadget::Logger.error(msg)
|
190
|
+
false
|
191
|
+
end
|
192
|
+
|
193
|
+
# Implements the --near feature.
|
194
|
+
# @param [String] libc_file
|
195
|
+
# @param [Array<OneGadget::Gadget::Gadget>] gadgets
|
196
|
+
# @param [String] near
|
197
|
+
# This can be name of functions or an ELF file.
|
198
|
+
# - Use one comma without spaces to specify a list of functions: +printf,scanf,free+.
|
199
|
+
# - Path to an ELF file and take its GOT functions to process: +/bin/ls+
|
200
|
+
def handle_near(libc_file, gadgets, near)
|
201
|
+
return error('Libc file must be given when using --near option') unless libc_file
|
202
|
+
|
203
|
+
functions = if File.file?(near) && OneGadget::Helper.valid_elf_file?(near)
|
204
|
+
OneGadget::Helper.got_functions(near)
|
205
|
+
else
|
206
|
+
near.split(',').map(&:strip)
|
207
|
+
end
|
208
|
+
function_offsets = OneGadget::Helper.function_offsets(libc_file, functions)
|
209
|
+
return error('No functions for processing') if function_offsets.empty?
|
210
|
+
|
211
|
+
function_offsets.each do |function, offset|
|
212
|
+
colored_offset = OneGadget::Helper.colored_hex(offset)
|
213
|
+
OneGadget::Logger.warn("Gadgets near #{OneGadget::Helper.colorize(function)}(#{colored_offset}):")
|
214
|
+
display_gadgets(gadgets.sort_by { |gadget| (gadget.offset - offset).abs }, @options[:raw])
|
215
|
+
show("\n")
|
216
|
+
end
|
217
|
+
true
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'one_gadget/abi'
|
2
4
|
require 'one_gadget/emulators/instruction'
|
3
5
|
require 'one_gadget/emulators/processor'
|
@@ -150,13 +152,6 @@ module OneGadget
|
|
150
152
|
register?(reg) && reg.start_with?('x')
|
151
153
|
end
|
152
154
|
|
153
|
-
# Override
|
154
|
-
# def global_var?(obj)
|
155
|
-
# str = obj.is_a?(OneGadget::Emulators::Lambda) ? obj.obj.to_s : obj.to_s
|
156
|
-
# # TODO: check if this assumption usually correct
|
157
|
-
# (%w[x19 x20 x21] << libc_base.obj).any? { |r| str.include?(r) }
|
158
|
-
# end
|
159
|
-
|
160
155
|
def add_writable(lmda)
|
161
156
|
# XXX: Better way is check LOAD segment of the libc ELF.
|
162
157
|
# XXX: Should also checks deref_count, but sometimes [[$base+xx]] is also writable..
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'one_gadget/error'
|
2
4
|
require 'one_gadget/helper'
|
3
5
|
|
@@ -26,7 +28,7 @@ module OneGadget
|
|
26
28
|
def +(other)
|
27
29
|
raise Error::InstructionArgumentError, "Expect other(#{other}) to be numeric." unless other.is_a?(Numeric)
|
28
30
|
|
29
|
-
if deref_count
|
31
|
+
if deref_count.positive?
|
30
32
|
ret = Lambda.new(self)
|
31
33
|
else
|
32
34
|
ret = Lambda.new(obj)
|
@@ -79,13 +81,19 @@ module OneGadget
|
|
79
81
|
str
|
80
82
|
end
|
81
83
|
|
82
|
-
#
|
83
|
-
# Only
|
84
|
+
# Evaluates the value of lambda.
|
85
|
+
# Only supports +rsp+0x30+ form.
|
84
86
|
# @param [Hash{String => Integer}] context
|
85
87
|
# The context.
|
86
88
|
# @return [Integer] Result of evaluation.
|
89
|
+
# @example
|
90
|
+
# l = Lambda.parse('rax+0x30')
|
91
|
+
# l.evaluate('rax' => 2)
|
92
|
+
# #=> 50
|
87
93
|
def evaluate(context)
|
88
|
-
|
94
|
+
if deref_count.positive? || (obj && !context.key?(obj))
|
95
|
+
raise Error::InstructionArgumentError, "Can't eval #{self}"
|
96
|
+
end
|
89
97
|
|
90
98
|
context[obj] + immi
|
91
99
|
end
|
data/lib/one_gadget/error.rb
CHANGED
data/lib/one_gadget/fetcher.rb
CHANGED
data/lib/one_gadget/gadget.rb
CHANGED
data/lib/one_gadget/helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'net/http'
|
2
4
|
require 'openssl'
|
3
5
|
require 'pathname'
|
@@ -125,6 +127,13 @@ module OneGadget
|
|
125
127
|
"#{color}#{str.sub(cc[:esc_m], color)}#{cc[:esc_m]}"
|
126
128
|
end
|
127
129
|
|
130
|
+
# Returns the hexified and colorized integer.
|
131
|
+
# @param [Integer] val
|
132
|
+
# @return [String]
|
133
|
+
def colored_hex(val)
|
134
|
+
colorize(hex(val), sev: :integer)
|
135
|
+
end
|
136
|
+
|
128
137
|
# Fetch the latest release version's tag name.
|
129
138
|
# @return [String] The tag name, in form +vX.X.X+.
|
130
139
|
def latest_tag
|
@@ -200,7 +209,7 @@ module OneGadget
|
|
200
209
|
rescue ELFTools::ELFError # not a valid ELF
|
201
210
|
:invalid
|
202
211
|
ensure
|
203
|
-
f
|
212
|
+
f&.close
|
204
213
|
end
|
205
214
|
|
206
215
|
# Present number in hex format.
|
@@ -312,5 +321,31 @@ module OneGadget
|
|
312
321
|
i386: 'i686-linux-gnu-objdump'
|
313
322
|
}[arch]
|
314
323
|
end
|
324
|
+
|
325
|
+
# Returns the names of functions from the file's global offset table.
|
326
|
+
# @param [String] file
|
327
|
+
# @return [Array<String>]
|
328
|
+
def got_functions(file)
|
329
|
+
arch = architecture(file)
|
330
|
+
objdump_bin = find_objdump(arch)
|
331
|
+
`#{::Shellwords.join([objdump_bin, '-T', file])} | grep -iPo 'GLIBC_.+?\\s+\\K.*'`.split
|
332
|
+
end
|
333
|
+
|
334
|
+
# Returns a dictionary that maps functions to their offsets.
|
335
|
+
# @param [String] file
|
336
|
+
# @param [Array<String>] functions
|
337
|
+
# @return [Hash{String => Integer}]
|
338
|
+
def function_offsets(file, functions)
|
339
|
+
arch = architecture(file)
|
340
|
+
objdump_bin = find_objdump(arch)
|
341
|
+
objdump_cmd = ::Shellwords.join([objdump_bin, '-T', file])
|
342
|
+
functions.map! { |f| '\\b' + f + '\\b' }
|
343
|
+
ret = {}
|
344
|
+
`#{objdump_cmd} | grep -iP '(#{functions.join('|')})'`.lines.map(&:chomp).each do |line|
|
345
|
+
tokens = line.split
|
346
|
+
ret[tokens.last] = tokens.first.to_i(16)
|
347
|
+
end
|
348
|
+
ret
|
349
|
+
end
|
315
350
|
end
|
316
351
|
end
|
data/lib/one_gadget/logger.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'logger'
|
2
4
|
|
3
5
|
require 'one_gadget/helper'
|
@@ -18,7 +20,9 @@ module OneGadget
|
|
18
20
|
when 'INFO' then :reg
|
19
21
|
when 'ERROR' then :error
|
20
22
|
end
|
21
|
-
"[#{OneGadget::Helper.colorize('OneGadget', sev: color)}] #{message.join}"
|
23
|
+
msg = +"[#{OneGadget::Helper.colorize('OneGadget', sev: color)}] #{message.join}"
|
24
|
+
msg << "\n" unless msg.end_with?("\n")
|
25
|
+
msg
|
22
26
|
end
|
23
27
|
|
24
28
|
module_function
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'one_gadget/error'
|
2
4
|
require 'one_gadget/fetcher'
|
3
5
|
require 'one_gadget/helper'
|
@@ -60,7 +62,7 @@ module OneGadget
|
|
60
62
|
# Remove hard-to-reach-constrains gadgets according to level
|
61
63
|
def refine_gadgets(gadgets, level)
|
62
64
|
return [] if gadgets.empty?
|
63
|
-
return gadgets if level
|
65
|
+
return gadgets if level.positive? # currently only supports level > 0 or not
|
64
66
|
|
65
67
|
high, low = gadgets.partition { |g| g.score >= 0.2 }
|
66
68
|
return take_until(low, 3) if high.empty?
|
data/lib/one_gadget/update.rb
CHANGED
data/lib/one_gadget/version.rb
CHANGED
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.7.
|
4
|
+
version: 1.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- david942j
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: elftools
|
@@ -634,6 +634,7 @@ files:
|
|
634
634
|
- lib/one_gadget/builds/libc-2.23-131c254aed46e6a24cb08f3abe802ea0ef50e5f9.rb
|
635
635
|
- lib/one_gadget/builds/libc-2.23-1800a4bdb0c42a7bb7a570ed90724fa04de8a4fe.rb
|
636
636
|
- lib/one_gadget/builds/libc-2.23-1b1d19add6d861e16e04e4b8e9864a7bc16c1327.rb
|
637
|
+
- lib/one_gadget/builds/libc-2.23-1ca54a6e0d76188105b12e49fe6b8019bf08803a.rb
|
637
638
|
- lib/one_gadget/builds/libc-2.23-1e80992437b5e1cb76bf56605ee8991e76e85f69.rb
|
638
639
|
- lib/one_gadget/builds/libc-2.23-1f1cf1c7ff279aa37add352423fd850e06be1098.rb
|
639
640
|
- lib/one_gadget/builds/libc-2.23-233dde1d38ecdc54bef352f1b5ee4e007ec9df26.rb
|
@@ -671,6 +672,7 @@ files:
|
|
671
672
|
- lib/one_gadget/builds/libc-2.23-961068caa1dcd5005b27c7c6abe32e94102eae3f.rb
|
672
673
|
- lib/one_gadget/builds/libc-2.23-96f8c796364693379a2a0c753133fecbd1c52434.rb
|
673
674
|
- lib/one_gadget/builds/libc-2.23-99de357f509368d89f95b0e92b0d5227e8b8addc.rb
|
675
|
+
- lib/one_gadget/builds/libc-2.23-9a6b57c7a4f93d7e54e61bccb7df996c8bc58141.rb
|
674
676
|
- lib/one_gadget/builds/libc-2.23-9e85392b0c4e3e2c8fdc063dfda4c3d0e0156e54.rb
|
675
677
|
- lib/one_gadget/builds/libc-2.23-a594a9c73a6067ab00a0f8db78d665be147acdc1.rb
|
676
678
|
- lib/one_gadget/builds/libc-2.23-a6fe771348e04d552fa1e6dcaf610699719bdd0e.rb
|
@@ -831,6 +833,7 @@ files:
|
|
831
833
|
- lib/one_gadget/builds/libc-2.28-5784a31a1c26f6d2157e585205ebb63dd19ff90f.rb
|
832
834
|
- lib/one_gadget/builds/libc-2.28-5b157f49586a3ca84d55837f97ff466767dd3445.rb
|
833
835
|
- lib/one_gadget/builds/libc-2.28-6ee9454b96efa9e343f9e8105f2fa4529265ea05.rb
|
836
|
+
- lib/one_gadget/cli.rb
|
834
837
|
- lib/one_gadget/emulators/aarch64.rb
|
835
838
|
- lib/one_gadget/emulators/amd64.rb
|
836
839
|
- lib/one_gadget/emulators/i386.rb
|
@@ -867,7 +870,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
867
870
|
requirements:
|
868
871
|
- - ">="
|
869
872
|
- !ruby/object:Gem::Version
|
870
|
-
version: 2.
|
873
|
+
version: 2.3.0
|
871
874
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
872
875
|
requirements:
|
873
876
|
- - ">="
|