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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5bb9760cff1de2c7868863e0ffa6d095e40952a16067d1b7e9fb665930c0304b
4
- data.tar.gz: 2d129e1e021b4d69f4a780716e3b6bfbb3c09c2950809f8804f09e6de93e1758
3
+ metadata.gz: 8408e8896c26b1f1841de6d054d3535f557e9460d0cf888b11d9bf0e84794b92
4
+ data.tar.gz: 61f4578f7bc943a7bf2914807769285832870af127c615e45635b89dc1a66a19
5
5
  SHA512:
6
- metadata.gz: 2250eb2a38fedb482306695b51a1eb099d77aac6ec614b7fd03b2f3f84334fde485372fd1f60ba6287f4b83d6d17afafa783c4ecf49d18e127ade70f845ec4b7
7
- data.tar.gz: c4ad302c436c7132ddbc080bfa4f3a80fd4d77d01e0e51876eac84b3ca8ceedf7feaca2ed62c1cb957af6d101d842d6277f11369c02b50eacc36caf8919bd42c
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 [file] [options]
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,
@@ -1,87 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require 'optparse'
4
+ require 'one_gadget/cli'
4
5
 
5
- require 'one_gadget'
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)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # OneGadget - To find the execve(/bin/sh, 0, 0) in glibc.
2
4
  #
3
5
  # @author david942j
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OneGadget
2
4
  # Defines the abi of different architectures.
3
5
  module ABI
@@ -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/abi'
2
4
  require 'one_gadget/emulators/x86'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'one_gadget/abi'
2
4
  require 'one_gadget/emulators/x86'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'one_gadget/error'
2
4
 
3
5
  module OneGadget
@@ -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 > 0
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
- # Eval the value of lambda.
83
- # Only support those like +rsp+0x30+.
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
- raise Error::InstructionArgumentError, "Can't eval #{self}" if deref_count > 0 || (obj && !context.key?(obj))
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'one_gadget/emulators/lambda'
2
4
  require 'one_gadget/error'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'one_gadget/emulators/instruction'
2
4
  require 'one_gadget/emulators/lambda'
3
5
  require 'one_gadget/emulators/processor'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OneGadget
2
4
  # OneGadget errors.
3
5
  module Error
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'one_gadget/error'
2
4
  require 'one_gadget/fetchers/aarch64'
3
5
  require 'one_gadget/fetchers/amd64'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'one_gadget/emulators/aarch64'
2
4
  require 'one_gadget/fetchers/base'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'one_gadget/emulators/amd64'
2
4
  require 'one_gadget/fetchers/x86'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'shellwords'
2
4
 
3
5
  module OneGadget
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools'
2
4
 
3
5
  require 'one_gadget/emulators/i386'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'one_gadget/fetchers/base'
2
4
 
3
5
  module OneGadget
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'one_gadget/abi'
2
4
  require 'one_gadget/emulators/lambda'
3
5
  require 'one_gadget/error'
@@ -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.close if 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
@@ -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 > 0 # currently only supports level > 0 or not
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?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fileutils'
2
4
 
3
5
  require 'one_gadget/helper'
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OneGadget
2
4
  # Current gem version.
3
- VERSION = '1.7.1'.freeze
5
+ VERSION = '1.7.2'
4
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.7.1
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-04-19 00:00:00.000000000 Z
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.1.0
873
+ version: 2.3.0
871
874
  required_rubygems_version: !ruby/object:Gem::Requirement
872
875
  requirements:
873
876
  - - ">="