Path: blob/master/modules/encoders/x86/context_stat.rb
21532 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'rex/poly'67class MetasploitModule < Msf::Encoder::XorAdditiveFeedback89# Manual ranking because the stat(2) key is generated and supplied10# manually.1112Rank = ManualRanking1314def initialize15super(16'Name' => 'stat(2)-based Context Keyed Payload Encoder',17'Description' => %q{18This is a Context-Keyed Payload Encoder based on stat(2)19and Shikata Ga Nai.20},21'Author' => 'Dimitris Glynos',22'Arch' => ARCH_X86,23'License' => MSF_LICENSE,24'Decoder' => {25'KeySize' => 4,26'BlockSize' => 427})2829register_options(30[31OptString.new('STAT_KEY', [32true,33'STAT key from target host (see tools/context/stat-key utility)',34'0x00000000'35]),36OptString.new('STAT_FILE', [ true, 'name of file to stat(2)', '/bin/ls' ]),37]38)39end4041def obtain_key(_buf, _badchars, state)42state.key = datastore['STAT_KEY'].hex43return state.key44end4546#47# Generates the shikata decoder stub.48#49def decoder_stub(state)50# If the decoder stub has not already been generated for this state, do51# it now. The decoder stub method may be called more than once.52if state.decoder_stub.nil?53# Shikata will only cut off the last 1-4 bytes of it's own end54# depending on the alignment of the original buffer55cutoff = 4 - (state.buf.length & 3)56block = keygen_stub + generate_shikata_block(state, state.buf.length + cutoff, cutoff) || (raise BadGenerateError)5758# Take the last 1-4 bytes of shikata and prepend them to the buffer59# that is going to be encoded to make it align on a 4-byte boundary.60state.buf = block.slice!(block.length - cutoff, cutoff) + state.buf6162# Cache this decoder stub. The reason we cache the decoder stub is63# because we need to ensure that the same stub is returned every time64# for a given encoder state.65state.decoder_stub = block66end6768state.decoder_stub69end7071protected7273def keygen_stub74fname = datastore['STAT_FILE']75flen = fname.length7677"\xd9\xee" + # fldz78"\xd9\x74\x24\xf4" + # fnstenv -0xc(%esp)79"\x5b" + # pop %ebx80Rex::Arch::X86.jmp_short(flen) + # jmp over81fname + # the filename82"\x83\xc3\x09" + # over: add $9, %ebx83"\x8d\x53" + # lea filelen(%ebx), %edx84Rex::Arch::X86.pack_lsb(flen) +85"\x31\xc0" + # xor %eax,%eax86"\x88\x02" + # mov %al,(%edx)87"\x8d\x4c\x24\xa8" + # lea -0x58(%esp),%ecx88"\xb0\xc3" + # mov $0xc3, %al89"\xcd\x80" + # int $0x8090"\x8b\x41\x2c" + # mov 0x2c(%ecx),%eax91"\x33\x41\x48" # xor 0x48(%ecx),%eax92end9394#95# Returns the set of FPU instructions that can be used for the FPU block of96# the decoder stub.97#98def fpu_instructions99fpus = []1001010xe8.upto(0xee) { |x| fpus << "\xd9" + x.chr }1020xc0.upto(0xcf) { |x| fpus << "\xd9" + x.chr }1030xc0.upto(0xdf) { |x| fpus << "\xda" + x.chr }1040xc0.upto(0xdf) { |x| fpus << "\xdb" + x.chr }1050xc0.upto(0xc7) { |x| fpus << "\xdd" + x.chr }106107fpus << "\xd9\xd0"108fpus << "\xd9\xe1"109fpus << "\xd9\xf6"110fpus << "\xd9\xf7"111fpus << "\xd9\xe5"112113# This FPU instruction seems to fail consistently on Linux114# fpus << "\xdb\xe1"115116fpus117end118119#120# Returns a polymorphic decoder stub that is capable of decoding a buffer121# of the supplied length and encodes the last cutoff bytes of itself.122#123def generate_shikata_block(state, length, cutoff)124# Declare logical registers125key_reg = Rex::Poly::LogicalRegister::X86.new('key', 'eax')126Rex::Poly::LogicalRegister::X86.new('count', 'ecx')127addr_reg = Rex::Poly::LogicalRegister::X86.new('addr')128129# Declare individual blocks130endb = Rex::Poly::SymbolicBlock::End.new131132# FPU blocks133fpu = Rex::Poly::LogicalBlock.new('fpu', *fpu_instructions)134fnstenv = Rex::Poly::LogicalBlock.new('fnstenv', "\xd9\x74\x24\xf4")135136# Get EIP off the stack137popeip = Rex::Poly::LogicalBlock.new('popeip',138proc { |b| (0x58 + b.regnum_of(addr_reg)).chr })139140# Clear the counter register141clear_register = Rex::Poly::LogicalBlock.new('clear_register',142"\x31\xc9",143"\x29\xc9",144"\x33\xc9",145"\x2b\xc9")146147# Initialize the counter after zeroing it148init_counter = Rex::Poly::LogicalBlock.new('init_counter')149150# Divide the length by four but ensure that it aligns on a block size151# boundary (4 byte).152length += 4 + (4 - (length & 3)) & 3153length /= 4154155if (length <= 255)156init_counter.add_perm("\xb1" + [ length ].pack('C'))157else158init_counter.add_perm("\x66\xb9" + [ length ].pack('v'))159end160161# Key initialization block162163# Decoder loop block164loop_block = Rex::Poly::LogicalBlock.new('loop_block')165166xor = proc { |b| "\x31" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr }167xor1 = proc { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') }168xor2 = proc { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') }169add = proc { |b| "\x03" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr }170add1 = proc { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') }171add2 = proc { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') }172sub4 = proc { |b| "\x83" + (0xe8 + b.regnum_of(addr_reg)).chr + "\xfc" }173add4 = proc { |b| "\x83" + (0xc0 + b.regnum_of(addr_reg)).chr + "\x04" }174175loop_block.add_perm(176proc { |b| xor1.call(b) + add1.call(b) + sub4.call(b) },177proc { |b| xor1.call(b) + sub4.call(b) + add2.call(b) },178proc { |b| sub4.call(b) + xor2.call(b) + add2.call(b) },179proc { |b| xor1.call(b) + add1.call(b) + add4.call(b) },180proc { |b| xor1.call(b) + add4.call(b) + add2.call(b) },181proc { |b| add4.call(b) + xor2.call(b) + add2.call(b) }182)183184# Loop instruction block185loop_inst = Rex::Poly::LogicalBlock.new('loop_inst',186"\xe2\xf5")187188# Define block dependencies189fnstenv.depends_on(fpu)190popeip.depends_on(fnstenv)191init_counter.depends_on(clear_register)192loop_block.depends_on(popeip, init_counter)193loop_inst.depends_on(loop_block)194195# Generate a permutation saving the EAX, ECX and ESP registers196loop_inst.generate([197Rex::Arch::X86::EAX,198Rex::Arch::X86::ESP,199Rex::Arch::X86::ECX200], nil, state.badchars)201end202end203204205