BMP Polyglot - Metasploit


This page contains detailed information about how to use the encoder/x86/bmp_polyglot metasploit module. For list of all metasploit modules, visit the Metasploit Module Library.

Module Overview


Name: BMP Polyglot
Module: encoder/x86/bmp_polyglot
Source code: modules/encoders/x86/bmp_polyglot.rb
Disclosure date: -
Last modification time: 2017-07-24 06:26:21 +0000
Supported architecture(s): x86
Supported platform(s): All
Target service / protocol: -
Target network port(s): -
List of CVEs: -

Encodes a payload in such a way that the resulting binary blob is both valid x86 shellcode and a valid bitmap image file (.bmp). The selected bitmap file to inject into must use the BM (Windows 3.1x/95/NT) header and the 40-byte Windows 3.1x/NT BITMAPINFOHEADER. Additionally the file must use either 24 or 32 bits per pixel as the color depth and no compression. This encoder makes absolutely no effort to remove any invalid characters.

Module Ranking and Traits


Module Ranking:

  • manual: The exploit is unstable or difficult to exploit and is basically a DoS. This ranking is also used when the module has no use unless specifically configured by the user (e.g.: exploit/windows/smb/psexec). More information about ranking can be found here.

Basic Usage


msf > use encoder/x86/bmp_polyglot
msf encoder(bmp_polyglot) > show targets
    ... a list of targets ...
msf encoder(bmp_polyglot) > set TARGET target-id
msf encoder(bmp_polyglot) > show options
    ... show and set options ...
msf encoder(bmp_polyglot) > exploit

Required Options


  • BitmapFile: The .bmp file to inject into

Go back to menu.

Msfconsole Usage


Here is how the encoder/x86/bmp_polyglot module looks in the msfconsole:

msf6 > use encoder/x86/bmp_polyglot

msf6 encoder(x86/bmp_polyglot) > show info

       Name: BMP Polyglot
     Module: encoder/x86/bmp_polyglot
   Platform: All
       Arch: x86
       Rank: Manual

Provided by:
  Spencer McIntyre

Description:
  Encodes a payload in such a way that the resulting binary blob is 
  both valid x86 shellcode and a valid bitmap image file (.bmp). The 
  selected bitmap file to inject into must use the BM (Windows 
  3.1x/95/NT) header and the 40-byte Windows 3.1x/NT BITMAPINFOHEADER. 
  Additionally the file must use either 24 or 32 bits per pixel as the 
  color depth and no compression. This encoder makes absolutely no 
  effort to remove any invalid characters.

Module Options


This is a complete list of options available in the encoder/x86/bmp_polyglot module:

msf6 encoder(x86/bmp_polyglot) > show options

Module options (encoder/x86/bmp_polyglot):

   Name        Current Setting  Required  Description
   ----        ---------------  --------  -----------
   BitmapFile                   yes       The .bmp file to inject into

Advanced Options


Here is a complete list of advanced options supported by the encoder/x86/bmp_polyglot module:

msf6 encoder(x86/bmp_polyglot) > show advanced

Module advanced options (encoder/x86/bmp_polyglot):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   VERBOSE    false            no        Enable detailed status messages
   WORKSPACE                   no        Specify the workspace for this module

Go back to menu.

Error Messages


This module may fail with the following error messages:

Check for the possible causes from the code snippets below found in the module source code. This can often times help in identifying the root cause of the problem.

Bad .bmp, failed to calculate jmp for size


Here is a relevant code snippet related to the "Bad .bmp, failed to calculate jmp for size" error message:

237:	  #   - is also a valid x86 jmp instruction to land on the assembly stub
238:	  def calc_new_size(orig_size, stub_length)
239:	    minimum_jump = BM_HEADER_SIZE + DIB_HEADER_SIZE - 2  # -2 for the offset of the size in the BM header
240:	    calc = SizeCalculator.new(orig_size + stub_length, minimum_jump)
241:	    size = calc.calculate.to_i
242:	    raise EncodingError, 'Bad .bmp, failed to calculate jmp for size' if size < orig_size
243:	
244:	    jump = calc.size_to_jmp(size)
245:	    pre_pad = jump - minimum_jump
246:	    post_pad = size - orig_size - stub_length - pre_pad
247:	    return { :new_size => size, :post_pad => post_pad, :pre_pad => pre_pad }

Bad .bmp, not enough image data for stego operation


Here is a relevant code snippet related to the "Bad .bmp, not enough image data for stego operation" error message:

251:	  # shellcode buffer into the image data
252:	  def calc_required_lsbs(sc_len, data_len)
253:	    return 1 if sc_len * 8 <= data_len
254:	    return 2 if sc_len * 4 <= data_len
255:	    return 4 if sc_len * 2 <= data_len
256:	    raise EncodingError, 'Bad .bmp, not enough image data for stego operation'
257:	  end
258:	
259:	  # asm stub that will extract the payload from the least significant bits of
260:	  # the binary data which directly follows it
261:	  def make_destego_stub(shellcode_size, padding, lsbs = 1)

Invalid number of storage bits


Here is a relevant code snippet related to the "Invalid number of storage bits" error message:

257:	  end
258:	
259:	  # asm stub that will extract the payload from the least significant bits of
260:	  # the binary data which directly follows it
261:	  def make_destego_stub(shellcode_size, padding, lsbs = 1)
262:	    raise RuntimeError, 'Invalid number of storage bits' unless [1, 2, 4].include?(lsbs)
263:	    gen_regs = [ 'eax', 'ebx', 'ecx', 'edx' ].shuffle
264:	    ptr_regs = [ 'edi', 'esi' ].shuffle
265:	    # declare logical registers
266:	    dst_addr_reg = Rex::Poly::LogicalRegister::X86.new('dst_addr', ptr_regs.pop)
267:	    src_addr_reg = Rex::Poly::LogicalRegister::X86.new('src_addr', ptr_regs.pop)

Bad .bmp DIB header, must be 40-byte BITMAPINFOHEADER


Here is a relevant code snippet related to the "Bad .bmp DIB header, must be 40-byte BITMAPINFOHEADER" error message:

373:	    data
374:	  end
375:	
376:	  def validate_dib_header(dib_header)
377:	    size, _, _, _, bbp, compression, _, _, _, _, _ = dib_header.unpack('VVVvvVVVVVV')
378:	    raise EncodingError, 'Bad .bmp DIB header, must be 40-byte BITMAPINFOHEADER' if size != DIB_HEADER_SIZE
379:	    raise EncodingError, 'Bad .bmp DIB header, bits per pixel must be must be either 24 or 32' if bbp != 24 && bbp != 32
380:	    raise EncodingError, 'Bad .bmp DIB header, compression can not be used' if compression != 0
381:	  end
382:	
383:	  def encode(buf, badchars = nil, state = nil, platform = nil)

Bad .bmp DIB header, bits per pixel must be must be either 24 or 32


Here is a relevant code snippet related to the "Bad .bmp DIB header, bits per pixel must be must be either 24 or 32" error message:

374:	  end
375:	
376:	  def validate_dib_header(dib_header)
377:	    size, _, _, _, bbp, compression, _, _, _, _, _ = dib_header.unpack('VVVvvVVVVVV')
378:	    raise EncodingError, 'Bad .bmp DIB header, must be 40-byte BITMAPINFOHEADER' if size != DIB_HEADER_SIZE
379:	    raise EncodingError, 'Bad .bmp DIB header, bits per pixel must be must be either 24 or 32' if bbp != 24 && bbp != 32
380:	    raise EncodingError, 'Bad .bmp DIB header, compression can not be used' if compression != 0
381:	  end
382:	
383:	  def encode(buf, badchars = nil, state = nil, platform = nil)
384:	    in_bmp = File.open(datastore['BitmapFile'], 'rb')

Bad .bmp DIB header, compression can not be used


Here is a relevant code snippet related to the "Bad .bmp DIB header, compression can not be used" error message:

375:	
376:	  def validate_dib_header(dib_header)
377:	    size, _, _, _, bbp, compression, _, _, _, _, _ = dib_header.unpack('VVVvvVVVVVV')
378:	    raise EncodingError, 'Bad .bmp DIB header, must be 40-byte BITMAPINFOHEADER' if size != DIB_HEADER_SIZE
379:	    raise EncodingError, 'Bad .bmp DIB header, bits per pixel must be must be either 24 or 32' if bbp != 24 && bbp != 32
380:	    raise EncodingError, 'Bad .bmp DIB header, compression can not be used' if compression != 0
381:	  end
382:	
383:	  def encode(buf, badchars = nil, state = nil, platform = nil)
384:	    in_bmp = File.open(datastore['BitmapFile'], 'rb')
385:	

Bad .bmp header, must be 0x424D (BM)


Here is a relevant code snippet related to the "Bad .bmp header, must be 0x424D (BM)" error message:

387:	    dib_header = in_bmp.read(DIB_HEADER_SIZE)
388:	    image_data = in_bmp.read
389:	    in_bmp.close
390:	
391:	    header, original_size, _, _, original_offset = header.unpack('vVvvV')
392:	    raise EncodingError, 'Bad .bmp header, must be 0x424D (BM)' if header != 0x4d42
393:	    validate_dib_header(dib_header)
394:	
395:	    lsbs = calc_required_lsbs(buf.length, image_data.length)
396:	
397:	    details = calc_new_size(original_size, DESTEGO_STUB_SIZE)

Bad destego stub size


Here is a relevant code snippet related to the "Bad destego stub size" error message:

397:	    details = calc_new_size(original_size, DESTEGO_STUB_SIZE)
398:	    destego_stub = make_destego_stub(buf.length, details[:post_pad], lsbs)
399:	    if destego_stub.length != DESTEGO_STUB_SIZE
400:	      # this is likely a coding error caused by updating the make_destego_stub
401:	      # method but not the DESTEGO_STUB_SIZE constant
402:	      raise EncodingError, 'Bad destego stub size'
403:	    end
404:	
405:	    pre_image_data = make_pad(details[:pre_pad]) + destego_stub + make_pad(details[:post_pad])
406:	    new_offset = original_offset + pre_image_data.length
407:	

Go back to menu.


Go back to menu.

See Also


Check also the following modules related to this module:

Authors


Spencer McIntyre

Version


This page has been produced using Metasploit Framework version 6.1.24-dev. For more modules, visit the Metasploit Module Library.

Go back to menu.