one_gadget 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 469c960b795a87ce7f7e02b91c46b2f8e75f4a7d
4
+ data.tar.gz: c05c6387725951eaee40a2733f33909aa7d81daa
5
+ SHA512:
6
+ metadata.gz: fa08575754ee8a545db7cc1f60ba307670eadcb2df17750d0504b4a6ac8eb55897bdb2b77aeff6e0ceb207fbe6e15a58b975bee6aed0411b0bfd10beabe00b63
7
+ data.tar.gz: 92e091b662abf384bd4cc791a27d9478e3bd17c8b9c6fe7f75aa314479b8e50738ba40da8ec40c554fbb166a05e071147999911bd63f6cc21b3445b4a902fb76
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ [![Build Status](https://travis-ci.org/david942j/one_gadget.svg?branch=master)](https://travis-ci.org/david942j/one_gadget)
2
+ [![Code Climate](https://codeclimate.com/github/david942j/one_gadget/badges/gpa.svg)](https://codeclimate.com/github/david942j/one_gadget)
3
+ [![Issue Count](https://codeclimate.com/github/david942j/one_gadget/badges/issue_count.svg)](https://codeclimate.com/github/david942j/one_gadget)
4
+ [![Test Coverage](https://codeclimate.com/github/david942j/one_gadget/badges/coverage.svg)](https://codeclimate.com/github/david942j/one_gadget/coverage)
5
+ [![Inline docs](https://inch-ci.org/github/david942j/one_gadget.svg?branch=master)](https://inch-ci.org/github/david942j/one_gadget)
6
+ [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](http://choosealicense.com/licenses/mit/)
7
+
8
+ ## One Gadget
9
+
10
+ When playing ctf pwn challenges we usually needs the one-gadget of `execve('/bin/sh', NULL, NULL)`.
11
+
12
+ This gem provides such gadget finder, no need to use IDA-pro every time like a fool.
13
+
14
+ Also provides the command-line tool `one_gadget` for easy usage.
15
+
16
+ Note: only supports x86-64 now.
17
+
18
+ ## Install
19
+
20
+ I'll push to rubygems.org..
21
+
22
+ ## Usage
23
+
24
+ ### Command Line Tool
25
+
26
+ ```bash
27
+ one_gadget
28
+ # Usage: one_gadget [file] [options]
29
+ # -b, --build-id BuildID BuildID[sha1] of libc
30
+ # -r, --[no-]raw Output gadgets offset only, split with one space
31
+ # -s, --script exploit-script Run exploit script with all possible gadgets
32
+ # The script will be run as 'exploit-script $offset'.
33
+
34
+ one_gadget -b 60131540dadc6796cab33388349e6e4e68692053
35
+ # offset: 0x4526a
36
+ # constraints:
37
+ # [rsp+0x30] == NULL
38
+ #
39
+ # offset: 0xef6c4
40
+ # constraints:
41
+ # [rsp+0x50] == NULL
42
+ #
43
+ # offset: 0xf0567
44
+ # constraints:
45
+ # [rsp+0x70] == NULL
46
+ ```
47
+
48
+ #### Combine with exploit script
49
+ Pass your exploit script as `one_gadget`'s arguments, it can
50
+ try all gadgets one by one, so you don't need to try every possible gadgets manually.
51
+
52
+ ```bash
53
+ one_gadget ./spec/data/libc-2.19.so -s 'echo "offset ->"'
54
+ ```
55
+
56
+ ![--script](https://github.com/david942j/one_gadget/blob/master/examples/script.png?raw=true)
57
+
58
+ ### Directly use in script
59
+ ```ruby
60
+ require 'one_gadget'
61
+ OneGadget.gadgets(file: '/lib/x86_64-linux-gnu/libc.so.6')
62
+ # => [283242, 980676, 984423]
63
+ ```
64
+
65
+ ## Screenshots
66
+
67
+ ### Search gadgets from file
68
+ ![from file](https://github.com/david942j/one_gadget/blob/master/examples/from_file.png?raw=true)
69
+
70
+ ### Fetch gadgets from database
71
+ ![build id](https://github.com/david942j/one_gadget/blob/master/examples/from_build_id.png?raw=true)
72
+
data/bin/one_gadget ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bun/env ruby
2
+ require 'one_gadget'
3
+ require 'optionparser'
4
+
5
+ options = { raw: false }
6
+ usage = 'Usage: one_gadget [file] [options]'
7
+ parser = OptionParser.new do |opts|
8
+ opts.banner = usage
9
+
10
+ opts.on('-b', '--build-id BuildID', 'BuildID[sha1] of libc') do |b|
11
+ options[:build_id] = b
12
+ end
13
+
14
+ opts.on('-r', '--[no-]raw', 'Output gadgets offset only, split with one space') do |v|
15
+ options[:raw] = v
16
+ end
17
+
18
+ opts.on('-s', '--script exploit-script', 'Run exploit script with all possible gadgets.',
19
+ 'The script will be run as \'exploit-script $offset\'.') do |script|
20
+ options[:script] = script
21
+ end
22
+ end
23
+ parser.parse!
24
+
25
+ def execute(script, offset)
26
+ pid = fork do
27
+ exec([script, offset.to_s].join(' '))
28
+ end
29
+ Process.wait pid
30
+ end
31
+
32
+ if options[:build_id]
33
+ gadgets = OneGadget.gadgets(build_id: options[:build_id], details: true)
34
+ elsif ARGV[0]
35
+ gadgets = OneGadget.gadgets(file: ARGV[0], details: true)
36
+ else
37
+ puts parser.help
38
+ exit(1)
39
+ end
40
+
41
+ extend OneGadget::Helper::ClassMethods
42
+ if options[:script]
43
+ gadgets.map(&:offset).each do |offset|
44
+ puts "[#{colorize('OneGadget', sev: :reg)}] Trying #{colorize(format('0x%x', offset), sev: :integer)}..."
45
+ execute(options[:script], offset)
46
+ end
47
+ exit(0)
48
+ end
49
+
50
+ if options[:raw]
51
+ puts gadgets.map(&:offset).join(' ')
52
+ else
53
+ puts gadgets.map(&:inspect).join("\n")
54
+ end
data/lib/one_gadget.rb ADDED
@@ -0,0 +1,35 @@
1
+ # OneGadget - To find the execve(/bin/sh, 0, 0) in glibc.
2
+ #
3
+ # @author david942j
4
+ module OneGadget
5
+ class << self
6
+ # The man entry of gem +one_gadget+.
7
+ # If want to find gadgets from file, it will search gadgets by its
8
+ # build id first.
9
+ #
10
+ # @param [String] file
11
+ # The relative path of libc.so.6.
12
+ # @param [String] build_id
13
+ # The BuildID of target libc.so.6.
14
+ # @return [Array<OneGadget::Gadget::Gadget>, Array<Integer>]
15
+ # The gadgets found.
16
+ # @example
17
+ # OneGadget.gadgets(file: './libc.so.6')
18
+ # OneGadget.gadgets(build_id: '60131540dadc6796cab33388349e6e4e68692053')
19
+ def gadgets(file: nil, build_id: nil, details: false)
20
+ if build_id
21
+ OneGadget::Fetcher.from_build_id(build_id, details: details)
22
+ elsif file
23
+ file = OneGadget::Helper.abspath(file)
24
+ build_id = OneGadget::Helper.build_id_of(file)
25
+ gadgets = OneGadget::Fetcher.from_build_id(build_id, details: details)
26
+ return gadgets unless gadgets.empty?
27
+ OneGadget::Fetcher.from_file(file, details: details)
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ require 'one_gadget/fetcher'
34
+ require 'one_gadget/helper'
35
+ require 'one_gadget/version'
@@ -0,0 +1,15 @@
1
+ module OneGadget
2
+ # define the abi of different architecture.
3
+ module ABI
4
+ # Define class methods here.
5
+ module ClassMethods
6
+ LINUX_X86_32 = %w(eax ebx ecx edx edi esi ebp esp).freeze
7
+ LINUX_X86_64 = LINUX_X86_32 + %w(rax rbx rcx rdx rdi rsi rbp rsp) + 7.upto(15).map { |i| "r#{i}" }
8
+ # Only support x86-64 now.
9
+ def registers
10
+ LINUX_X86_64
11
+ end
12
+ end
13
+ extend ClassMethods
14
+ end
15
+ end
@@ -0,0 +1,8 @@
1
+ require 'one_gadget/gadget'
2
+ # Ubuntu GLIBC 2.23-0ubuntu5
3
+ # ELF 64-bit LSB shared object, x86-64
4
+ build_id = File.basename(__FILE__, '.rb').split('-').last
5
+ OneGadget::Gadget.add(build_id, 0x4526a, constraints: ['[rsp+0x30] == NULL'])
6
+ OneGadget::Gadget.add(build_id, 0xef6c4, constraints: ['[rsp+0x50] == NULL'])
7
+ OneGadget::Gadget.add(build_id, 0xf0567, constraints: ['[rsp+0x70] == NULL'])
8
+ OneGadget::Gadget.add(build_id, 0xf5b10, constraints: ['[rbp-0xf8] == NULL', 'rcx == NULL'])
@@ -0,0 +1,75 @@
1
+ require 'one_gadget/helper'
2
+ require 'one_gadget/gadget'
3
+
4
+ module OneGadget
5
+ # To find gadgets.
6
+ module Fetcher
7
+ # Define class methods here.
8
+ module ClassMethods
9
+ # Fetch one-gadget offsets of this build id.
10
+ # @param [String] build_id The targets' BuildID.
11
+ # @param [Boolean] details
12
+ # If needs to return the gadgets' constraints.
13
+ # @return [Array<Integer>, Array<OneGadget::Gadget::Gadget>]
14
+ # If +details+ is +false+, +Array<Integer>+ is returned, which
15
+ # contains offset only.
16
+ # Otherwise, array of gadgets is returned.
17
+ def from_build_id(build_id, details: false)
18
+ if (build_id =~ /\A#{OneGadget::Helper::BUILD_ID_FORMAT}\Z/).nil?
19
+ raise ArgumentError, format('invalid BuildID format: %p', build_id)
20
+ end
21
+ gadgets = OneGadget::Gadget.builds(build_id)
22
+ return gadgets if details
23
+ gadgets.map(&:offset)
24
+ end
25
+
26
+ # Fetch one-gadget offsets from file.
27
+ # @param [String] file The absolute path of libc file.
28
+ # @param [Boolean] details
29
+ # If needs to return the gadgets' constraints.
30
+ # @return [Array<Integer>, Array<OneGadget::Gadget::Gadget>]
31
+ # If +details+ is +false+, +Array<Integer>+ is returned, which
32
+ # contains offset only.
33
+ # Otherwise, array of gadgets is returned.
34
+ def from_file(file, details: false)
35
+ bin_sh_hex = str_offset(file, '/bin/sh').to_s(16)
36
+ candidates = `objdump -d -M intel #{file}|egrep '<execve[^+]*>$' -B 10`.split('--').select do |candidate|
37
+ next false unless candidate.include?(bin_sh_hex)
38
+ next false unless candidate.lines.last.include?('call') # last line must be +call execve+
39
+ true
40
+ end
41
+ candidates.map! do |candidate|
42
+ # remove other calls
43
+ lines = candidate.lines
44
+ to_rm = lines[0...-1].rindex { |c| c.include?('call') }
45
+ lines = lines[to_rm + 1..-1] unless to_rm.nil?
46
+ lines.map! { |s| s.gsub(/#\s+#{bin_sh_hex}\s+<.*>$/, "# #{bin_sh_hex} \"/bin/sh\"") }
47
+ lines.join
48
+ end
49
+ gadgets = candidates.map { |c| convert_to_gadget(c) }
50
+ return gadgets if details
51
+ gadgets.map(&:offset)
52
+ end
53
+
54
+ private
55
+
56
+ def str_offset(file, str)
57
+ match = `strings -tx #{file} | grep '#{str}'`.lines.map(&:strip).first
58
+ return nil if match.nil?
59
+ # 17c8c3 /bin/sh
60
+ match.split.first.to_i(16)
61
+ end
62
+
63
+ def convert_to_gadget(assembly)
64
+ lines = assembly.lines.map(&:strip)
65
+ offset = lines.first.scan(/^([\da-f]+):/)[0][0].to_i(16)
66
+ # fetch those might be constraints lines.
67
+ important_lines = lines.select { |line| ['rsi'].any? { |r| line.include?(r) } }.map do |line|
68
+ line.split("\t").last.gsub(/\s+/, ' ')
69
+ end
70
+ OneGadget::Gadget::Gadget.new(offset, constraints: important_lines)
71
+ end
72
+ end
73
+ extend ClassMethods
74
+ end
75
+ end
@@ -0,0 +1,77 @@
1
+ require 'one_gadget/abi'
2
+
3
+ module OneGadget
4
+ # Module for define gadgets.
5
+ module Gadget
6
+ # Information of a gadget.
7
+ class Gadget
8
+ # @return [Integer] The gadget's address offset.
9
+ attr_accessor :offset
10
+ # @return [Array<String>] The constraints need for this gadget.
11
+ attr_accessor :constraints
12
+
13
+ # Initialize method of {Gadget} instance.
14
+ # @param [Integer] offset The relative address offset of this gadget.
15
+ # @option options [Array<String>] :constraints
16
+ # The constraints need for this gadget. Defaults to +[]+.
17
+ # @example
18
+ # OneGadget::Gadget::Gadget.new(0x12345, constraints: ['rax == 0'])
19
+ def initialize(offset, **options)
20
+ @offset = offset
21
+ @constraints = options[:constraints] || []
22
+ end
23
+
24
+ # Show gadget in a pretty way.
25
+ def inspect
26
+ str = format("#{OneGadget::Helper.colorize('offset', sev: :sym)}: 0x%x\n", offset)
27
+ unless constraints.empty?
28
+ str += "#{OneGadget::Helper.colorize('constraints')}:\n "
29
+ str += constraints.join("\n ")
30
+ end
31
+ str.gsub!(/0x[\da-f]+/) { |s| OneGadget::Helper.colorize(s, sev: :integer) }
32
+ OneGadget::ABI.registers.each { |reg| str.gsub!(reg, OneGadget::Helper.colorize(reg, sev: :reg)) }
33
+ str + "\n"
34
+ end
35
+ end
36
+
37
+ # Define class methods here.
38
+ module ClassMethods
39
+ BUILDS_PATH = File.join(File.dirname(__FILE__), 'builds').freeze
40
+ BUILDS = Hash.new { |h, k| h[k] = [] }
41
+ # Get gadgets from pre-defined corpus.
42
+ # @param [String] build_id Desired build id.
43
+ # @return [Array<Gadget::Gadget>] Gadgets.
44
+ def builds(build_id)
45
+ require_all if BUILDS.empty?
46
+ return BUILDS[build_id] if BUILDS.key?(build_id)
47
+ # fetch remote builds
48
+ table = OneGadget::Helper.remote_builds.find { |c| c.include?(build_id) }
49
+ return [] if table.nil? # remote doesn't have this one either.
50
+ # builds found in remote! Ask update gem and download remote gadgets.
51
+ OneGadget::Helper.ask_update(msg: 'The desired one-gadget can be found in lastest version!')
52
+ tmp_file = OneGadget::Helper.download_build(table)
53
+ require tmp_file.path
54
+ tmp_file.unlink
55
+ BUILDS[build_id]
56
+ end
57
+
58
+ # Add a gadget, for scripts in builds/ to use.
59
+ # @param [String] build_id The target's build id.
60
+ # @param [Integer] offset The relative address offset of this gadget.
61
+ # @param [Hash] options See {Gadget::Gadget#initialize} for more information.
62
+ # @return [void]
63
+ def add(build_id, offset, **options)
64
+ BUILDS[build_id] << OneGadget::Gadget::Gadget.new(offset, **options)
65
+ end
66
+
67
+ private
68
+
69
+ def require_all
70
+ Dir.glob(File.join(BUILDS_PATH, '**', '*.rb')).each do |dic|
71
+ require dic
72
+ end
73
+ end
74
+ end
75
+ extend ClassMethods
76
+ end
77
+ end
@@ -0,0 +1,128 @@
1
+ require 'pathname'
2
+ require 'shellwords'
3
+ require 'net/http'
4
+ require 'openssl'
5
+ require 'tempfile'
6
+
7
+ module OneGadget
8
+ # Define some helpful methods here.
9
+ module Helper
10
+ BUILD_ID_FORMAT = /[0-9a-f]{40}/
11
+ # Define class methods here.
12
+ module ClassMethods
13
+ # Get absolute path from relative path. Support symlink.
14
+ # @param [String] path Relative path.
15
+ # @return [String] Absolute path, with symlink resolved.
16
+ # @example
17
+ # abspath('/lib/x86_64-linux-gnu/libc.so.6')
18
+ # #=> '/lib/x86_64-linux-gnu/libc-2.23.so'
19
+ def abspath(path)
20
+ Pathname.new(File.expand_path(path)).realpath.to_s
21
+ end
22
+
23
+ # Get the Build ID of target ELF.
24
+ # @param [String] path Absolute file path.
25
+ # @return [String] Target build id.
26
+ # @example
27
+ # build_id_of('/lib/x86_64-linux-gnu/libc-2.23.so')
28
+ # #=> '60131540dadc6796cab33388349e6e4e68692053'
29
+ def build_id_of(path)
30
+ cmd = 'readelf -n ' + ::Shellwords.escape(path)
31
+ bid = `#{cmd}`.scan(/Build ID: (#{BUILD_ID_FORMAT})$/).first
32
+ return nil if bid.nil?
33
+ bid.first
34
+ end
35
+
36
+ # Disable colorize
37
+ def color_off!
38
+ @disable_color = true
39
+ end
40
+
41
+ # Enable colorize
42
+ def color_on!
43
+ @disable_color = false
44
+ end
45
+
46
+ # Color codes for pretty print
47
+ COLOR_CODE = {
48
+ esc_m: "\e[0m",
49
+ normal_s: "\e[38;5;1m", # red
50
+ integer: "\e[38;5;12m", # light blue
51
+ fatal: "\e[38;5;197m", # dark red
52
+ reg: "\e[38;5;120m", # light green
53
+ sym: "\e[38;5;229m", # pry like
54
+ }.freeze
55
+
56
+ # Wrapper color codes for pretty inspect.
57
+ # @param [String] str Contents to colorize.
58
+ # @option [Symbol] sev Specific which kind of color want to use, valid symbols are defined in +COLOR_CODE+.
59
+ # @return [String] Wrapper with color codes.
60
+ def colorize(str, sev: :normal_s)
61
+ return str if @disable_color
62
+ cc = COLOR_CODE
63
+ color = cc.key?(sev) ? cc[sev] : ''
64
+ "#{color}#{str.sub(cc[:esc_m], color)}#{cc[:esc_m]}"
65
+ end
66
+
67
+ # Fetch the latest release version's tag name.
68
+ # @return [String] The tag name, in form +vx.x.x+.
69
+ def latest_tag
70
+ latest = url_request('https://github.com/david942j/one_gadget/releases').scan(%r{/tree/v([\d.]+)"}).map do |tag|
71
+ Gem::Version.new(tag.first)
72
+ end.max.to_s
73
+ 'v' + latest
74
+ end
75
+
76
+ # Get the url which can fetch +filename+ from remote repo.
77
+ # @param [String] filename
78
+ # @return [String] The url.
79
+ def url_of_file(filename)
80
+ raw_file_url = 'https://raw.githubusercontent.com/david942j/one_gadget/@tag/@file'
81
+ raw_file_url.gsub('@tag', latest_tag).gsub('@file', filename)
82
+ end
83
+
84
+ # Download the latest version of +file+ in +lib/one_gadget/builds/+ from remote repo.
85
+ #
86
+ # @param [String] file The filename desired.
87
+ # @return [Tempfile] The temp file be created.
88
+ def download_build(file)
89
+ temp = Tempfile.new(['gadgets', file + '.rb'])
90
+ url_request(url_of_file(File.join('lib', 'one_gadget', 'builds', file + '.rb')))
91
+ temp.write url_request(url_of_file(File.join('lib', 'one_gadget', 'builds', file + '.rb')))
92
+ temp.close
93
+ temp
94
+ end
95
+
96
+ # Get the latest builds list from repo.
97
+ # @return [Array<String>] List of build ids.
98
+ def remote_builds
99
+ url_request(url_of_file('builds_list')).lines.map(&:strip)
100
+ end
101
+
102
+ # Get request.
103
+ # @param [String] url The url.
104
+ # @return [String] The request response body.
105
+ def url_request(url)
106
+ # TODO: add timeout to handle github crashed or in no network environment.
107
+ uri = URI.parse(url)
108
+ http = Net::HTTP.new(uri.host, uri.port)
109
+ http.use_ssl = true
110
+ http.verify_mode = ::OpenSSL::SSL::VERIFY_NONE
111
+
112
+ request = Net::HTTP::Get.new(uri.request_uri)
113
+
114
+ response = http.request(request)
115
+ response.body
116
+ end
117
+
118
+ # Show the message of ask user to update gem.
119
+ # @return [void]
120
+ def ask_update(msg: '')
121
+ name = 'one_gadget'
122
+ cmd = colorize("gem update #{name}")
123
+ STDERR.puts msg + "\n" + "Update with: $ #{cmd}"
124
+ end
125
+ end
126
+ extend ClassMethods
127
+ end
128
+ end
@@ -0,0 +1,3 @@
1
+ module OneGadget
2
+ VERSION = '1.0.0'.freeze
3
+ end
Binary file
Binary file
@@ -0,0 +1,22 @@
1
+ require 'one_gadget/gadget'
2
+ require 'one_gadget/helper'
3
+ describe OneGadget::Gadget do
4
+ before(:all) do
5
+ @build_id = 'fake_id'
6
+ OneGadget::Helper.color_off! # disable colorize for easy testing.
7
+ OneGadget::Gadget.add(@build_id, 0x1234, constraints: ['[rsp+0x30] == NULL', 'rax == 0'])
8
+ end
9
+
10
+ after(:all) do
11
+ OneGadget::Gadget::ClassMethods::BUILDS.delete @build_id
12
+ end
13
+
14
+ it 'inspect' do
15
+ expect(OneGadget::Gadget.builds(@build_id).map(&:inspect).join).to eq <<-EOS
16
+ offset: 0x1234
17
+ constraints:
18
+ [rsp+0x30] == NULL
19
+ rax == 0
20
+ EOS
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ require 'one_gadget/helper'
2
+
3
+ describe OneGadget::Helper do
4
+ before(:all) do
5
+ OneGadget::Helper.color_on!
6
+ @libcpath = File.join(File.dirname(__FILE__), 'data', 'libc-2.23.so')
7
+ end
8
+ it 'abspath' do
9
+ expect(OneGadget::Helper.abspath('./spec/data/libc-2.23.so')).to eq @libcpath
10
+ end
11
+
12
+ it 'build_id_of' do
13
+ expect(OneGadget::Helper.build_id_of(@libcpath)).to eq '60131540dadc6796cab33388349e6e4e68692053'
14
+ end
15
+
16
+ it 'colorize' do
17
+ expect(OneGadget::Helper.colorize('123', sev: :integer)).to eq "\e[38;5;12m123\e[0m"
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ require 'one_gadget'
2
+
3
+ describe 'one_gadget' do
4
+ before(:each) do
5
+ @build_id = '60131540dadc6796cab33388349e6e4e68692053'
6
+ @libcpath = File.join(File.dirname(__FILE__), 'data', 'libc-2.19.so')
7
+ end
8
+
9
+ it 'from file' do
10
+ expect(OneGadget.gadgets(file: @libcpath)).to eq [0x4647c, 0xe5765, 0xe66bd]
11
+ end
12
+
13
+ describe 'from build id' do
14
+ it 'normal' do
15
+ # only check not empty because the gadgets might add frequently.
16
+ expect(OneGadget.gadgets(build_id: @build_id)).not_to be_empty
17
+ end
18
+
19
+ it 'invalid' do
20
+ expect { OneGadget.gadgets(build_id: '^_^') }.to raise_error(ArgumentError, 'invalid BuildID format: "^_^"')
21
+ end
22
+
23
+ it 'fetch from remote' do
24
+ entry = OneGadget::Gadget::ClassMethods::BUILDS.delete(@build_id)
25
+ OneGadget::Gadget::ClassMethods::BUILDS[:a] = 1
26
+ expect(OneGadget.gadgets(build_id: @build_id)).not_to be_empty
27
+ OneGadget::Gadget::ClassMethods::BUILDS.delete(:a)
28
+ OneGadget::Gadget::ClassMethods::BUILDS[@build_id] = entry unless entry.nil?
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,8 @@
1
+ require 'codeclimate-test-reporter'
2
+ require 'simplecov'
3
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
4
+ [SimpleCov::Formatter::HTMLFormatter, CodeClimate::TestReporter::Formatter]
5
+ )
6
+ SimpleCov.start do
7
+ add_filter '/spec/'
8
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: one_gadget
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - david942j
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.46'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.46'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '12.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '12.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.13.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.13.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: codeclimate-test-reporter
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.6'
83
+ description: |2
84
+ When playing ctf pwn challenges we usually needs the one-gadget of `execve('/bin/sh', NULL, NULL)`.
85
+ This gem provides such gadget finder, no need to use IDA-pro every time like a fool.
86
+ Also provides the command-line tool `one_gadget` for easy usage.
87
+ email:
88
+ - david942j@gmail.com
89
+ executables:
90
+ - one_gadget
91
+ extensions: []
92
+ extra_rdoc_files: []
93
+ files:
94
+ - README.md
95
+ - bin/one_gadget
96
+ - lib/one_gadget.rb
97
+ - lib/one_gadget/abi.rb
98
+ - lib/one_gadget/builds/libc-2.23-60131540dadc6796cab33388349e6e4e68692053.rb
99
+ - lib/one_gadget/fetcher.rb
100
+ - lib/one_gadget/gadget.rb
101
+ - lib/one_gadget/helper.rb
102
+ - lib/one_gadget/version.rb
103
+ - spec/data/libc-2.19.so
104
+ - spec/data/libc-2.23.so
105
+ - spec/gadget_spec.rb
106
+ - spec/helper_spec.rb
107
+ - spec/one_gadget_spec.rb
108
+ - spec/spec_helper.rb
109
+ homepage: https://github.com/david942j/one_gadget
110
+ licenses:
111
+ - MIT
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: 2.1.0
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubyforge_project:
129
+ rubygems_version: 2.5.2
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: one_gadget
133
+ test_files:
134
+ - spec/data/libc-2.19.so
135
+ - spec/data/libc-2.23.so
136
+ - spec/spec_helper.rb
137
+ - spec/helper_spec.rb
138
+ - spec/one_gadget_spec.rb
139
+ - spec/gadget_spec.rb