one_gadget 1.3.4.1 → 1.3.5

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
  SHA1:
3
- metadata.gz: c69447e16b79866cfd608d5b714e65cfa16d2492
4
- data.tar.gz: 2a4ce21e7fb1070845a8fde268e8477b23f2e8da
3
+ metadata.gz: 769666a5afd3ce890eea834682b010137958e50a
4
+ data.tar.gz: 303399584d0b4163058ad74c0e9f80a8fea13694
5
5
  SHA512:
6
- metadata.gz: 3768aa0cd2c00128fe75e232a115ed81b9783efed4de71cdbc28322843c534b25d7da93b731b85f0c22d6b1b5cd592984cd002dce099c05c6ff020060e503f66
7
- data.tar.gz: 72a5b04cc4cfa3dfcaa99c248260bb3e0040a45166fe566405158917ad11a3ed65c943902099a3471fb224a18dd726404650892ca7b239d6699a0dcfd2775cb1
6
+ metadata.gz: bb098f44596a0bd6f9a51ae533fbb2456c66c65a64a11bd7c8bc031bdd08684ccee0a549a7d833d26cfe3314a1caf34bfbd294ed67960d9843ea21b72927c931
7
+ data.tar.gz: 743e95a1efac018fc6e887348b234bd08da77776494bfcd8f793a2b8612e2ccd69fecab26d948ae55525de15fc298179d04c4ff772b7c6c02b3e19120c98d03b
data/README.md CHANGED
@@ -8,9 +8,10 @@
8
8
 
9
9
  ## One Gadget
10
10
 
11
- When playing ctf pwn challenges we usually need the one-gadget of `execve('/bin/sh', NULL, NULL)`.
11
+ When playing ctf pwn challenges we usually need the one-gadget RCE (remote code execution),
12
+ which leads to call `execve('/bin/sh', NULL, NULL)`.
12
13
 
13
- This gem provides such gadget finder, no need to use IDA-pro every time like a fool.
14
+ This gem provides such gadgets finder, no need to use IDA-pro every time like a fool.
14
15
 
15
16
  This work provides the command-line tool `one_gadget` for easy usage.
16
17
 
data/lib/one_gadget.rb CHANGED
@@ -26,8 +26,8 @@ module OneGadget
26
26
  OneGadget::Fetcher.from_build_id(build_id, details: details)
27
27
  elsif file
28
28
  file = OneGadget::Helper.abspath(file)
29
- unless force_file
30
- build_id = OneGadget::Helper.build_id_of(file)
29
+ build_id = OneGadget::Helper.build_id_of(file)
30
+ if !force_file && build_id
31
31
  gadgets = OneGadget::Fetcher.from_build_id(build_id, details: details)
32
32
  return gadgets unless gadgets.empty?
33
33
  end
@@ -3,7 +3,9 @@ module OneGadget
3
3
  module ABI
4
4
  # Define class methods here.
5
5
  module ClassMethods
6
+ # Registers in i386.
6
7
  LINUX_X86_32 = %w(eax ebx ecx edx edi esi ebp esp).freeze
8
+ # Registers in x86_64/
7
9
  LINUX_X86_64 = LINUX_X86_32 + %w(rax rbx rcx rdx rdi rsi rbp rsp) + 7.upto(15).map { |i| "r#{i}" }
8
10
  # Registers' name in amd64.
9
11
  # @return [Array<String>] List of registers.
@@ -6,6 +6,7 @@ module OneGadget
6
6
  # Emulator of amd64 instruction set.
7
7
  class I386 < X86
8
8
  class << self
9
+ # Yap, bits.
9
10
  def bits
10
11
  32
11
12
  end
@@ -3,10 +3,10 @@ require 'one_gadget/helper'
3
3
  module OneGadget
4
4
  module Emulators
5
5
  # A {Lambda} object can be:
6
- # 1. {String} # variable name
7
- # 2. {Numeric}
8
- # 3. {Lambda} + {Numeric}
9
- # 4. dereference {Lambda}
6
+ # 1. +String+ (variable name)
7
+ # 2. +Numeric+
8
+ # 3. {Lambda} + +Numeric+
9
+ # 4. dereferenced {Lambda}
10
10
  class Lambda
11
11
  attr_accessor :obj # @return [String, Lambda] The object currently related to.
12
12
  attr_accessor :immi # @return [Integer] The immidiate value currently added.
@@ -49,6 +49,7 @@ module OneGadget
49
49
 
50
50
  # Decrease dreference count with 1.
51
51
  # @return [void]
52
+ # @raise [ArgumentError] When this object cannot be referenced anymore.
52
53
  def ref!
53
54
  raise ArgumentError, 'Cannot reference anymore!' if @deref_count <= 0
54
55
  @deref_count -= 1
@@ -86,14 +87,18 @@ module OneGadget
86
87
  end
87
88
 
88
89
  class << self
89
- # Target: parse something like +[rsp+0x50]+ into a {Lambda} object.
90
+ # Target: parse things like <tt>[rsp+0x50]</tt> into a {Lambda} object.
90
91
  # @param [String] arg
91
92
  # @param [Hash{String => Lambda}] predefined
93
+ # Predfined values.
92
94
  # @return [OneGadget::Emulators::Lambda, Integer]
93
95
  # If +arg+ contains number only, return it.
94
96
  # Otherwise, return a {Lambda} object.
95
97
  # @example
96
- # parse('[rsp+0x50]') #=> #<Lambda @obj='rsp', @immi=80, @deref_count=1>
98
+ # obj = parse('[rsp+0x50]')
99
+ # #=> #<Lambda @obj='rsp', @immi=80, @deref_count=1>
100
+ # parse('obj+0x30', predefined: { 'obj' => obj }).to_s
101
+ # #=> '[rsp+0x50]+0x30'
97
102
  def parse(arg, predefined: {})
98
103
  deref_count = 0
99
104
  if arg[0] == '[' # a little hack because there should nerver something like +[[rsp+1]+2]+ to parse.
@@ -34,12 +34,12 @@ module OneGadget
34
34
  # contains offset only.
35
35
  # Otherwise, array of gadgets is returned.
36
36
  def from_file(file, details: false)
37
- gadgets = {
37
+ klass = {
38
38
  amd64: OneGadget::Fetcher::Amd64,
39
- i386: OneGadget::Fetcher::I386,
40
- unknown: OneGadget::Fetcher::Base
41
- }[OneGadget::Helper.architecture(file)].new(file).find
42
- gadgets = trim_gadgets(gadgets)
39
+ i386: OneGadget::Fetcher::I386
40
+ }[OneGadget::Helper.architecture(file)]
41
+ raise ArgumentError, 'Unsupported architecture!' if klass.nil?
42
+ gadgets = trim_gadgets(klass.new(file).find)
43
43
  return gadgets if details
44
44
  gadgets.map(&:offset)
45
45
  end
@@ -2,7 +2,7 @@ require 'shellwords'
2
2
 
3
3
  module OneGadget
4
4
  module Fetcher
5
- # define common methods for gadget fetchers.
5
+ # Define common methods for gadget fetchers.
6
6
  class Base
7
7
  # The absolute path of glibc.
8
8
  # @return [String] The filename.
@@ -10,7 +10,7 @@ module OneGadget
10
10
  # Instantiate a fetcher object.
11
11
  # @param [String] file Absolute path of target libc.
12
12
  def initialize(file)
13
- @file = ::Shellwords.escape(file)
13
+ @file = file
14
14
  end
15
15
 
16
16
  # Method need to be implemented in inheritors.
@@ -19,6 +19,12 @@ module OneGadget
19
19
  end
20
20
 
21
21
  # Fetch candidates that end with call exec*.
22
+ #
23
+ # Give a block to filter gadget candidates.
24
+ # @yieldparam [String] cand
25
+ # Is this candidate valid?
26
+ # @yieldreturn [Boolean]
27
+ # True for valid.
22
28
  # @return [Array<String>]
23
29
  # Each +String+ returned is multi-lines of assembly code.
24
30
  def candidates(&block)
@@ -34,7 +40,7 @@ module OneGadget
34
40
  private
35
41
 
36
42
  def objdump_cmd(start: nil, stop: nil)
37
- cmd = %(objdump -w -d -M intel "#{file}")
43
+ cmd = %(objdump -w -d -M intel #{::Shellwords.escape(file)})
38
44
  cmd.concat(" --start-address #{start}") if start
39
45
  cmd.concat(" --stop-address #{stop}") if stop
40
46
  cmd
@@ -55,7 +61,8 @@ module OneGadget
55
61
  end
56
62
 
57
63
  def str_offset(str)
58
- match = `strings -tx #{file} -n #{str.size} | grep " #{::Shellwords.escape(str)}"`.lines.map(&:strip).first
64
+ match = `strings -tx #{::Shellwords.escape(file)} -n #{str.size} | grep #{::Shellwords.escape(' ' + str)}`
65
+ match = match.lines.map(&:strip).first
59
66
  return nil if match.nil?
60
67
  # 17c8c3 /bin/sh
61
68
  match.split.first.to_i(16)
@@ -40,7 +40,9 @@ module OneGadget
40
40
 
41
41
  # Define class methods here.
42
42
  module ClassMethods
43
- BUILDS_PATH = File.join(File.dirname(__FILE__), 'builds').freeze
43
+ # Path to the pre-build files.
44
+ BUILDS_PATH = File.join(__dir__, 'builds').freeze
45
+ # Cache.
44
46
  BUILDS = Hash.new { |h, k| h[k] = [] }
45
47
  # Get gadgets from pre-defined corpus.
46
48
  # @param [String] build_id Desired build id.
@@ -9,6 +9,7 @@ require 'one_gadget/logger'
9
9
  module OneGadget
10
10
  # Define some helpful methods here.
11
11
  module Helper
12
+ # Format of build-id, 40 hex numbers.
12
13
  BUILD_ID_FORMAT = /[0-9a-f]{40}/
13
14
  # Define class methods here.
14
15
  module ClassMethods
@@ -125,15 +126,16 @@ module OneGadget
125
126
  end
126
127
 
127
128
  # Fetch the file archiecture of +file+.
128
- # @param [String] The target ELF filename.
129
+ # @param [String] file The target ELF filename.
129
130
  # @return [String]
130
131
  # Only supports :amd64, :i386 now.
131
132
  def architecture(file)
132
133
  str = ELFTools::ELFFile.new(File.open(file)).machine
133
134
  return :amd64 if str.include?('X86-64')
134
135
  return :i386 if str.include?('Intel 80386')
135
- rescue ELFTools::ELFError # not a valid ELF
136
136
  :unknown
137
+ rescue ELFTools::ELFError # not a valid ELF
138
+ :invalid
137
139
  end
138
140
 
139
141
  # Present number in hex format.
@@ -1,3 +1,4 @@
1
1
  module OneGadget
2
- VERSION = '1.3.4.1'.freeze
2
+ # Current gem version.
3
+ VERSION = '1.3.5'.freeze
3
4
  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.3.4.1
4
+ version: 1.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - david942j
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-22 00:00:00.000000000 Z
11
+ date: 2017-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: elftools
@@ -99,7 +99,7 @@ description: |2
99
99
 
100
100
  This gem provides such gadget finder, no need to use IDA-pro every time like a fool :p.
101
101
 
102
- Also provides the command-line tool +one_gadget+ for easy usage.
102
+ Typing `one_gadget /path/to/libc` in terminal and having fun!
103
103
  email:
104
104
  - david942j@gmail.com
105
105
  executables: