pydbg reverseme solution update

July 8th, 2010 by webstersprodigy

This is an update to http://webstersprodigy.net/2010/07/07/pydbg-reverseme-solution/. I change a register now to circumvent the isdebuggerpresent call.

import sys
import ctypes

from pydbg import *
from pydbg.defines import *

print "This is a very stupid keygen that uses a debug method and grabs the key from memory"
print "prints out the valid key, and writes it to memory"
print "Basically, pydbg 'hello, world'"
print "-------------"

if len(sys.argv) != 2:
    print "Error. USAGE: keygen.py C:\full\path\ice"
    sys.exit(-1)

def handler_breakpoint(mdbg):
    if mdbg.get_register("EIP") == 0x004011F5:
        valid_str = ""
        #the valid serial is at 004030C8
        addr = 0x004030C8
        while 1:
            tmp = mdbg.read(addr, 1)
            addr += 1
            if tmp != "\x00":
                valid_str = valid_str + tmp
            else:
                break
        print "The valid string is: ", valid_str
        print "Writing this to memory..."
        #write this to memory at 004030b4
        #def write (self, address, data, length=0)
        #wdata = ctypes.create_string_buffer(valid_str)
        mdbg.write(0x00403198, valid_str, len(valid_str))
        #checking the write
        #print mdbg.read(0x00403198, len(valid_str) + 1)
    if mdbg.get_register("EIP") == 0x40106e:
        mdbg.set_register("EAX", 0)
    return DBG_CONTINUE

dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, handler_breakpoint)
dbg.load(sys.argv[1])
dbg.debug_event_iteration()
#0x40106e is the point where we can circumvent the isdebugger present call
dbg.bp_set(0x40106e)
#at 004011FF in execution,
#breakpoing for reading writing final compare
dbg.bp_set(0x004011F5)
dbg.debug_event_loop()

pydbg reverseme solution

July 7th, 2010 by webstersprodigy

Last week I wrote a keygen here: http://webstersprodigy.net/2010/06/22/reverseme-windows-keygen/.

This is an almost identical problem, but the binary has been patched to allow debugging (I may do this programmaticly as well, but not yet). I wanted to solve this with programmatic debugging. Here is the exe:
Ice9pch3.

The code simply sets a breakpoint and prints the key to the screen. Also it patches the process memory so that the serial is valid.

import sys
import ctypes

from pydbg import *
from pydbg.defines import *

print "This is a very stupid keygen that uses a debug method and grabs the key from memory"
print "prints out the valid key, and writes it to memory"
print "Basically, pydbg 'hello, world'"
print "-------------"

if len(sys.argv) != 2:
    print "Error. USAGE: keygen.py C:\full\path\ice"
    sys.exit(-1)

def handler_breakpoint(mdbg):
    valid_str = ""
    #the valid serial is at 004030C8
    addr = 0x004030C8
    while 1:
        tmp = mdbg.read(addr, 1)
        addr += 1
        if tmp != "\x00":
            valid_str = valid_str + tmp
        else:
            break
    print "The valid string is: ", valid_str
    print "Writing this to memory..."
    #write this to memory at 004030b4
    #def write (self, address, data, length=0)
    wdata = ctypes.create_string_buffer(valid_str)
    mdbg.write(0x00403198, wdata, len(valid_str))
    #checking the write
    #print mdbg.read(0x00403198, len(valid_str) + 1)
    return DBG_CONTINUE

dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, handler_breakpoint)
dbg.load(sys.argv[1])
dbg.debug_event_iteration()
#at 004011FF in execution,
#def bp_set (self, address, description="", restore=True, handler=None):
dbg.bp_set(0x004011F5)
dbg.debug_event_loop()

Reverseme Windows Keygen

June 22nd, 2010 by webstersprodigy

This one was challenging for me, and took me several hours, but was fun. I got caught up on certain parts that may not have been too difficult, but, yeah…

http://crackmes.de/users/tripletordo/ice9/

You can download the executable here Ice9.zip.

The first thing I noticed is probably the ‘trick’ which was simply a call to isdebuggerpresent. I modified the assembly immediately after from JNE to JE so that it only runs if a debugger is present, allowing me to attach my debugger.

00401071 74 0A JE SHORT Ice9.0040107D

This took a lot of trial and error. My strategy was to replicate the logic. Once I got to the point ‘ecx at 0040119c’ I was home free.

#include <iostream>
#include <string>
using namespace std;

void main (int argc, char *argv[]) {
  if ( argc != 2) {
    cout<<"Bad usage, enter a name > 4 letters"<<endl;
	return;
  }
  string name = argv[1];
  string ostring = name;
  int i;
  //first reverse the string
  for (i=0; i<name.length(); i++) {
    name[i] = ostring [name.length()-i-1];
  }

  if (name.length() < 4) {
    cout << "name must be more than 4 letters chief"<<endl;
	return;
  }

  int v1 = 0;
  int cum = 0;
  for (i=1; i<name.length(); i++) {
    v1 = name[i];
	if (name[i] <= 90) {
	  if (v1 >= 65)
	    v1 += 44;
	}
	cum += v1;
  } //ecx at 0040119C

  cum = 9 * (12345 * (cum + 666) - 23);

  char chr_403119 [122];
  unsigned int v;
  i=0;
  //no bounds checking
  do {
    v = cum;
	cum /= 0xA;
	chr_403119[i++] = v % 10 + 48;
  } while (v / 10);
  chr_403119[i] = '\0';

  printf ("%s", chr_403119);
  string serial = "";

  //reverse the string
  for (; i >= 0; --i) {
    serial += chr_403119[i];
  }
  cout<<serial<<endl;

  //append all chars except the 'first' three to the end
  for (i=3; i< ostring.length(); i++) {
    serial += ostring[i];
  }

  cout<<serial<<endl;

}

My plan on this one, since it was interesting enough and because it’s relatively easy to break at the final value, is to break this a completely different way. I’d like to write a python debugging script that bypasses the isdebuggerpresent and just grabs the final value in the compare at 004011FF. This should be relatively straightforward, and hopefully a good ‘hello, world’ to the world of python debugging. Stay tuned.

Nmap script to detect Debian OpenSSL Random Number Generator Weakness

June 13th, 2010 by webstersprodigy

This relies on HD’s keys, found http://digitaloffense.net/tools/debian-openssl/

description = [[
Debian OpenSSH/OpenSSL Package Random Number Generator Weakness
]]

---
-- @output
-- 22/ssh open  ssh
-- |_ ssh_debian_weak: The following keys are vulnerable: 2048 RSA 1024 RSA

-- SSH Weak Debian Key Script
-- rev 1.0 (2010-02-07)
-- rougly based on ssh_debian_weak.nasl by tennable
-- written by hand

author = "Rich Lundeen <mopey@webstersprodigy.net>"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"websters", "nessus", "act_gather_info"}

dependencies = {"ssh-hostkey"}

require("shortport")
require("ssh1")
require("ssh2")
require("nessus/nessus_conf")
portrule = shortport.port_or_service({22}, {"ssh"})

action = function(host, port)
  local keyval = nmap.registry.sshhostkey[host.ip]
  if keyval == nil then
    return
  end
  local output = ""
  for i,line in ipairs(keyval) do
    --TODO eventually binary search is nicer, but due to formats ready from HD
    --or if wanted later perhaps add the hex version to registry
    local linekey = string.gsub(ssh1.fingerprint_hex(line.fingerprint,
                                line.algorithm, line.bits), ":", "")
    local crimp = pcre.new("^[^\\s]+[\\s]([^\\s]+)[\\s][^\\s]+", 0, "C")
    local s, e, t = crimp:exec(linekey, 0, 0)
    linekey = string.sub(linekey, t[1], t[2])
    local fstring = (nessus_conf.nessus_conf["basedir"] ..
                     "nselib/nessus/data/debian_weak_ssl/" ..
                     line.algorithm:lower() .. "_" ..
                     tostring(line.bits))
    local mfile = io.open(fstring, "r")
    for vulnkey in mfile:lines() do
      --TODO this could be made more efficient
      if string.find(vulnkey, linekey, 0) then
        output = output .. line.algorithm .. " " .. tostring(line.bits)
      end
    end
    mfile:close()
  end
  if output ~= "" then
    return output
  end
end

No computers were harmed in the 0.182 seconds it took to produce this page.