rex-ole 0.1.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: 96d83d1e258c69844bac338287ba147f27e79092
4
+ data.tar.gz: 7b939852df46e093e63355d852b5860178bdefc9
5
+ SHA512:
6
+ metadata.gz: 450d8312a1b4a2846999802543eab21bdae5894649195aa53d8f72a7e99fa8077df6a1b5414f2ff1adcfbcce3dfeb4c1e57c0419b4ccbf0c5ea81a87e8d97983
7
+ data.tar.gz: 9578bb85804856ee572f3d2f9f6c18b74363ac86694526de63f0bf34b2825be6759bf882a0d6150dde94463854e575e0a3841fb827b45744bcf9492fb337e7fe
checksums.yaml.gz.sig ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.12.5
@@ -0,0 +1,52 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This Code of Conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting the project maintainers at msfdev@metasploit.com. If
39
+ the incident involves a committer, you may report directly to
40
+ egypt@metasploit.com or todb@metasploit.com.
41
+
42
+ All complaints will be reviewed and investigated and will result in a
43
+ response that is deemed necessary and appropriate to the circumstances.
44
+ Maintainers are obligated to maintain confidentiality with regard to the
45
+ reporter of an incident.
46
+
47
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
48
+ version 1.3.0, available at
49
+ [http://contributor-covenant.org/version/1/3/0/][version]
50
+
51
+ [homepage]: http://contributor-covenant.org
52
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rex-ole.gemspec
4
+ gemspec
5
+
6
+ gem 'rex-text'
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (C) 2012-2013, Rapid7, Inc.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ * Neither the name of Rapid7 LLC nor the names of its contributors
15
+ may be used to endorse or promote products derived from this software
16
+ without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # Rex::OLE
2
+
3
+ Ruby Exploitation(rex) Library for reading/writing Object-Linking-and-Embedding (OLE) files and streams. Ported over from Joshua Drake's original code inside Metasploit Framework.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'rex-ole'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install rex-ole
20
+
21
+
22
+
23
+ ## Development
24
+
25
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
26
+
27
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
28
+
29
+ ## Contributing
30
+
31
+ Bug reports and pull requests are welcome on GitHub at https://github.com/rapid7/rex-ole. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
32
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rex/ole"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,44 @@
1
+ # -*- coding: binary -*-
2
+
3
+ ##
4
+ # Rex::OLE - an OLE implementation
5
+ # written in 2010 by Joshua J. Drake <jduck [at] metasploit.com>
6
+ ##
7
+
8
+
9
+ module Rex
10
+ module OLE
11
+
12
+ class CLSID
13
+
14
+ def initialize(buf=nil)
15
+ @buf = buf
16
+ @buf ||= "\x00" * 16
17
+ end
18
+
19
+ def pack
20
+ @buf
21
+ end
22
+
23
+ def to_s
24
+ ret = ""
25
+ ret << "%08x" % Util.get32(@buf, 0)
26
+ ret << "-"
27
+ ret << "%04x" % Util.get16(@buf, 4)
28
+ ret << "-"
29
+ ret << "%04x" % Util.get16(@buf, 6)
30
+ ret << "-"
31
+ idx = 0
32
+ last8 = @buf[8,8]
33
+ last8.unpack('C*').each { |byte|
34
+ ret << [byte].pack('C').unpack('H*')[0]
35
+ ret << "-" if (idx == 1)
36
+ idx += 1
37
+ }
38
+ ret
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,138 @@
1
+ # -*- coding: binary -*-
2
+
3
+ ##
4
+ # Rex::OLE - an OLE implementation
5
+ # written in 2010 by Joshua J. Drake <jduck [at] metasploit.com>
6
+ ##
7
+
8
+ module Rex
9
+ module OLE
10
+
11
+ class DIFAT
12
+
13
+ def initialize stg
14
+ @stg = stg
15
+ @entries = []
16
+ end
17
+
18
+ #
19
+ # convenience access to entries
20
+ #
21
+ def []=(idx,expr)
22
+ @entries[idx] = expr
23
+ end
24
+
25
+ def [](idx)
26
+ @entries[idx]
27
+ end
28
+
29
+ def +(expr)
30
+ @entries += expr
31
+ self
32
+ end
33
+
34
+ def <<(expr)
35
+ @entries << expr
36
+ end
37
+
38
+ def length
39
+ @entries.length
40
+ end
41
+
42
+ def slice!(start,stop)
43
+ @entries.slice!(start,stop)
44
+ end
45
+
46
+ def reset
47
+ @entries = []
48
+ end
49
+
50
+ def each
51
+ @entries.each { |el|
52
+ yield el
53
+ }
54
+ end
55
+
56
+ #
57
+ # woop
58
+ #
59
+ def to_s
60
+ ret = "{ "
61
+ @entries.each { |el|
62
+ ret << ", " if (ret.length > 2)
63
+ case el
64
+ when SECT_END
65
+ ret << "END"
66
+ when SECT_DIF
67
+ ret << "DIF"
68
+ when SECT_FAT
69
+ ret << "FAT"
70
+ when SECT_FREE
71
+ ret << "FREE"
72
+ else
73
+ ret << "0x%x" % el
74
+ end
75
+ }
76
+ ret << " }"
77
+ ret
78
+ end
79
+
80
+ #
81
+ # low-level functions
82
+ #
83
+ def read
84
+ @entries = []
85
+
86
+ # start with the header part
87
+ @entries += @stg.header._sectFat
88
+
89
+ # double indirect fat
90
+ sect = @stg.header._sectDifStart
91
+ while (sect != SECT_END)
92
+ if (@entries.include?(sect))
93
+ raise RuntimeError, 'Sector chain loop detected (0x%08x)' % sect
94
+ end
95
+
96
+ @entries << sect
97
+ buf = @stg.read_sector(sect, @stg.header.sector_size)
98
+
99
+ # the last sect ptr in the block becomes the next entry
100
+ sect = Util.get32(buf, ((@stg.header.idx_per_sect)-1) * 4)
101
+ end
102
+
103
+ # don't need these free ones, but it doesn't hurt to keep them.
104
+ #@difat.delete(SECT_FREE)
105
+ end
106
+
107
+ def write
108
+ len = @entries.length
109
+ first109 = @entries.dup
110
+
111
+ rest = nil
112
+ if (len > 109)
113
+ rest = first109.slice!(109,len)
114
+ end
115
+
116
+ @stg.header._sectFat = []
117
+ @stg.header._sectFat += first109
118
+ if (len < 109)
119
+ need = 109 - len
120
+ need.times {
121
+ @stg.header._sectFat << SECT_FREE
122
+ }
123
+ end
124
+
125
+ if (rest and rest.length > 0)
126
+ raise RuntimeError, 'TODO: support writing DIF properly!'
127
+ # may require adding more fat sectors :-/
128
+ #@stg.header._csectDif = rest.length
129
+ #@stg.header._sectDifStart = idx
130
+ end
131
+
132
+ @stg.header._csectFat = len
133
+ end
134
+
135
+ end
136
+
137
+ end
138
+ end
@@ -0,0 +1,228 @@
1
+ # -*- coding: binary -*-
2
+
3
+ ##
4
+ # Rex::OLE - an OLE implementation
5
+ # written in 2010 by Joshua J. Drake <jduck [at] metasploit.com>
6
+ ##
7
+
8
+ module Rex
9
+ module OLE
10
+
11
+ require 'rex/ole/direntry'
12
+
13
+ #
14
+ # This class serves as the root directory entry in addition to
15
+ # an abstraction around the concept of a directory as a whole.
16
+ #
17
+ class Directory < DirEntry
18
+
19
+ # XXX: num_entries is not maintained once a stream/storage is added!
20
+ attr_accessor :num_entries
21
+
22
+ def initialize(stg)
23
+ super
24
+
25
+ @num_entries = 1
26
+ end
27
+
28
+
29
+ # woop, recursive each
30
+ def yield_entries(de, &block)
31
+ block.call(de)
32
+ de.each { |el|
33
+ yield_entries(el, &block)
34
+ }
35
+ end
36
+ def each_entry(&block)
37
+ yield_entries(self, &block)
38
+ end
39
+
40
+
41
+ def set_ministream_params(start, size)
42
+ @_sectStart = start
43
+ @_ulSize = size
44
+ end
45
+
46
+ def link_item(parent, child)
47
+ # set sid, advance count
48
+ child.sid = @num_entries
49
+ @num_entries += 1
50
+
51
+ # link item to siblings and/or parent
52
+ if (parent._sidChild == DIR_NOSTREAM)
53
+ parent._sidChild = child.sid
54
+ dlog("Linking #{child.name} as THE child of #{parent.name} as sid #{child.sid}", 'rex', LEV_3)
55
+ else
56
+ sib = nil
57
+ parent.each { |el|
58
+ if (el._sidLeftSib == DIR_NOSTREAM)
59
+ sib = el
60
+ el._sidLeftSib = child.sid
61
+ dlog("Linking #{child.name} as the LEFT sibling of #{sib.name} as sid #{child.sid}", 'rex', LEV_3)
62
+ break
63
+ end
64
+ if (el._sidRightSib == DIR_NOSTREAM)
65
+ sib = el
66
+ el._sidRightSib = child.sid
67
+ dlog("Linking #{child.name} as the RIGHT sibling of #{sib.name} as sid #{child.sid}", 'rex', LEV_3)
68
+ break
69
+ end
70
+ }
71
+ if (not sib)
72
+ raise RuntimeError, 'Unable to find a sibling to link to in the directory'
73
+ end
74
+ end
75
+ parent << child
76
+ end
77
+
78
+
79
+ #
80
+ # low-level functions
81
+ #
82
+ def from_s(sid, buf)
83
+ super
84
+
85
+ if (@_sidRightSib != DIR_NOSTREAM)
86
+ raise RuntimeError, 'Root Entry is invalid! (has right sibling)'
87
+ end
88
+ if (@_sidLeftSib != DIR_NOSTREAM)
89
+ raise RuntimeError, 'Root Entry is invalid! (has left sibling)'
90
+ end
91
+ end
92
+
93
+ def read
94
+ @children = []
95
+ visited = []
96
+ entries = []
97
+ root_node = nil
98
+ sect = @stg.header._sectDirStart
99
+ while (sect != SECT_END)
100
+
101
+ if (visited.include?(sect))
102
+ raise RuntimeError, 'Sector chain loop detected (0x%08x)' % sect
103
+ end
104
+ visited << sect
105
+
106
+ sbuf = @stg.read_sector(sect, @stg.header.sector_size)
107
+ while (sbuf.length >= DIRENTRY_SZ)
108
+ debuf = sbuf.slice!(0, DIRENTRY_SZ)
109
+
110
+ type = Util.get8(debuf, 0x42)
111
+ case type
112
+ when STGTY_ROOT
113
+ if (entries.length != 0)
114
+ raise RuntimeError, 'Root Entry found, but not first encountered!'
115
+ end
116
+ if (root_node)
117
+ raise RuntimeError, 'Multiple root directory sectors detected (0x%08x)' % sect
118
+ end
119
+ de = self
120
+ root_node = de
121
+
122
+ when STGTY_STORAGE
123
+ de = SubStorage.new @stg
124
+
125
+ when STGTY_STREAM
126
+ de = Stream.new @stg
127
+
128
+ when STGTY_INVALID
129
+ # skip invalid entries
130
+ next
131
+
132
+ else
133
+ raise RuntimeError, 'Unsupported directory entry type (0x%02x)' % type
134
+ end
135
+
136
+ # read content
137
+ de.from_s(entries.length, debuf)
138
+ entries << de
139
+ end
140
+ sect = @stg.next_sector(sect)
141
+ end
142
+
143
+ @num_entries = entries.length
144
+
145
+ # sort out the tree structure, starting with the root
146
+ if (@_sidChild != DIR_NOSTREAM)
147
+ populate_children(entries, root_node, @_sidChild)
148
+ end
149
+ end
150
+
151
+
152
+ # recursively add entries to their proper parents :)
153
+ def populate_children(entries, parent, sid)
154
+ node = entries[sid]
155
+ dlog("populate_children(entries, \"#{parent.name}\", #{sid}) - node: #{node.name}", 'rex', LEV_3)
156
+ parent << node
157
+ if (node.type == STGTY_STORAGE) and (node._sidChild != DIR_NOSTREAM)
158
+ populate_children(entries, node, node._sidChild)
159
+ end
160
+ if (node._sidLeftSib != DIR_NOSTREAM)
161
+ populate_children(entries, parent, node._sidLeftSib)
162
+ end
163
+ if (node._sidRightSib != DIR_NOSTREAM)
164
+ populate_children(entries, parent, node._sidRightSib)
165
+ end
166
+ end
167
+
168
+ # NOTE: this may not be necessary if we were to use each_entry
169
+ def flatten_tree(entries, parent)
170
+ entries << parent
171
+ parent.each { |el|
172
+ flatten_tree(entries, el)
173
+ }
174
+ end
175
+
176
+
177
+ def write
178
+ # flatten the directory again
179
+ entries = []
180
+ flatten_tree(entries, self)
181
+ dlog("flattened tree has #{entries.length} entries...", 'rex', LEV_3)
182
+
183
+ # count directory sectors
184
+ ds_count = entries.length / 4
185
+ if ((entries.length % 4) > 0)
186
+ # one more sector to hold the rest
187
+ ds_count += 1
188
+ end
189
+
190
+ # put the root entry first
191
+ sbuf = self.pack
192
+
193
+ # add the rest
194
+ prev_sect = nil
195
+ dir_start = nil
196
+ entries.each { |de|
197
+ # we already got the root entry, no more!
198
+ next if (de.type == STGTY_ROOT)
199
+
200
+ dir = de.pack
201
+ dlog("writing dir entry #{de.name}", 'rex', LEV_3)
202
+ sbuf << dir
203
+
204
+ if (sbuf.length == @stg.header.sector_size)
205
+ # we have a full sector, add it!
206
+ sect = @stg.write_sector(sbuf, nil, prev_sect)
207
+ prev_sect = sect
208
+ dir_start ||= sect
209
+ # reset..
210
+ sbuf = ""
211
+ end
212
+ }
213
+
214
+ # still a partial sector left?
215
+ if (sbuf.length > 0)
216
+ # add it! (NOTE: it will get padded with nul bytes if its not sector sized)
217
+ sect = @stg.write_sector(sbuf, nil, prev_sect)
218
+ prev_sect = sect
219
+ dir_start ||= sect
220
+ end
221
+
222
+ @stg.header._sectDirStart = dir_start
223
+ end
224
+
225
+ end
226
+
227
+ end
228
+ end