Reverseme: Namegenme

This guy is here: http://crackmes.de/users/moofy/moofys_namegenme/

namegenme.zip

I had a fairly hard time with this one for some reason, although the solution was right in front of my face…

Most the logic for calculating the generation is in the function 00401852. The Serial is stored in a global variable, and the name is generated by taking certain bytes from the serial and doing addition on them.

Here is all the relevant logic, although finding it was sort of a pain.


.text:004018FD                 lea     eax, [ebp+var_10]
.text:00401900                 add     dword ptr [eax], 4
.text:00401903                 lea     eax, [ebp+var_14]
.text:00401906                 sub     dword ptr [eax], 3
.text:00401909                 lea     eax, [ebp+var_18]
.text:0040190C                 sub     dword ptr [eax], 2
.text:0040190F                 lea     eax, [ebp+var_1C]
.text:00401912                 add     dword ptr [eax], 2
.text:00401915                 lea     eax, [ebp+var_20]
.text:00401918                 dec     dword ptr [eax]
.text:0040191A                 lea     eax, [ebp+var_24]
.text:0040191D                 add     dword ptr [eax], 3
.text:00401920                 lea     eax, [ebp+var_28]
.text:00401923                 sub     dword ptr [eax], 2
.text:00401926                 lea     eax, [ebp+var_2C]
.text:00401929                 sub     dword ptr [eax], 4
.text:0040192C                 lea     eax, [ebp+var_30]
.text:0040192F                 add     dword ptr [eax], 3
.text:00401932                 lea     eax, [ebp+var_34]
.text:00401935                 inc     dword ptr [eax]

Here is a keygen written in C

void main(int argc, char* argv[]) {

  char Name [10];
  char* ser = argv[1];
  if (argc != 2 || strlen(argv[1]) < 21) {
    printf("Invalid serialn");
	return (-1);
  }

  Name[0] = ser[0] + 4;
  Name[1] = ser[1] - 3;
  Name[2] = ser[2] - 2;
  Name[3] = ser[6] + 2;
  Name[4] = ser[7] - 1;
  Name[5] = ser[8] + 3;
  Name[6] = ser[13] - 2;
  Name[7] = ser[14] - 4;
  Name[8] = ser[15] + 3;
  Name[9] = ser[20] + 1;
  Name[10] = "\0";

  printf("Name: %sn", Name);
}

Reverseme: Easy Windows Using Reflector

http://crackmes.de/users/d0min4ted/keygenme_by_d0min4ted/

In case the link goes away, here is a zip of the executable. crackme

I cheated on this one and used reflector. This was an excuse for me to try reflector out… so I started with that in mind.

The Checking code ends up being in crackme->WindowsFormsApplication4->Form1. You can deduce what most the buttons do. The relevant one turns out to be in asd. The keygen is basically straight from the verifying function found there, written in C#.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace keygen
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Name: ");
            string Name = Console.ReadLine();
            if (Name.Length < 4)
            {
                Console.WriteLine("Name must be 4 characters");
                Environment.Exit(0);
            }

            string str3 = "";
            char[] chArray = Name.ToCharArray();
            foreach (char ch in chArray)
            {
                int num2 = Convert.ToInt32(ch);
                string str4 = string.Format("{0:X}", num2);
                str3 = str3 + str4;
            }
            char[] array = str3.ToCharArray();
            Array.Reverse(array);
            string str5 = new string(array);
            if (str5.Length > 9)
            {
                str5 = str5.Remove(9, str5.Length - 9);
            }
            decimal num4 = Convert.ToDecimal(Convert.ToInt32(str5));
            double num5 = Math.Pow((double)Name.Length, 3.0);
            decimal num6 = Math.Round((decimal)(num4 * Convert.ToDecimal(num5)), 0);
            Console.WriteLine(num6);
        }
    }
}

Reverseme: Easy Windows

To get back into the groove, I decided to try a crackme. After searching far and wide, I can’t seem to find where I got this from, other than crackmes.de.  One of my favorite sites.

Crackme.zip <– here it is in case it’s deleted.

And the solution is, with no analysis:


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

int add_name_chars(string name) {
  int total = 0;
  for (int i=0; i<name.length(); i++) {
    total += name[i];
  }
  return total;
}

int main() {
  string name;
  cout<<"Name: ";
  cin>>name;

  unsigned int ser1 = 31 * add_name_chars(name) / 629u + 44431400;
  while (ser1 > 0x3b9ac9ff) {
    ser1 /= 10;
  }
  cout<<"Serial 1: "<<ser1<<endl;

  unsigned int ser2 = 82 * ser1 - 3;
  while (ser2 > 0x1869f)  {
    ser2 /= 10;
  }

  cout<<"Serial 2: "<<ser2<<endl;
  return 0;
}

Ok, one hint. All the logic is at 004013BC. This was rated as 1, for newbies, but it still took me awhile to figure out. I thought it was fun.

nmap script to try and detect login pages

The title sort of explains it.

description = [[
Attempts to check if a login page exists on the port.
]]

---
-- @output
-- 80/tcp open  http
-- |_ http-login-form: HTTP login detected

-- HTTP authentication information gathering script
-- rev 1.0 (2010-02-06)

author = "Rich Lundeen <mopey@webstersprodigy.net>"

license = "Same as Nmap--See http://nmap.org/book/man-legal.html"

categories = {"ioactive"}

require("shortport")
require("http")
require("pcre")

portrule = shortport.port_or_service({80, 443, 8080}, {"http","https"})

parse_url = function(url)
  local re = pcre.new("^([^:]*):[/]*([^/]*)", 0, "C")
  local s, e, t = re:exec(url, 0, 0)
  local proto = string.sub(url, t[1], t[2])
  local host = string.sub(url, t[3], t[4])
  local path = string.sub(url, t[4] + 1)
  local port = string.find(host, ":")
  if port ~= nil then
    --TODO check bounds, sanity, cast port to an int
    local thost = string.sub(host, 0, port-1)
    port = string.sub(host, port+1)
    host = thost
  else
    if proto == "http" then
      port = 80
    elseif proto == "https" then
      port = 443
    end
  end
  return host, port, path
end

--attempting to be compatible with nessus function in http.inc
--in this case, host is a url - it should use get_http_page
--get_http_page = function(port, host, redirect)
  

--port and url are objects passed to the action function
--redirect an integer to prohibit loops
get_http_page_nmap = function(port, host, redirect, path)
  if path == nil then
    path = "/"
  end
  if redirect == nil then
    redirect = 2
  end
  local answer = http.get(host, port, path)
  if ((answer.header.location ~= nil) and (redirect > 0) and 
      (answer.status >=300) and (answer.status < 400)) then
    nhost, nport, npath = parse_url(answer.header.location)
    if (((nhost ~= host.targetname) and (nhost ~= host.ip) and 
        (nhost ~= host.name)) or nport ~= port.number ) then
      --cannot redirect more, different service
      return answer, path
    else
      return get_http_page_nmap(port, host, redirect-1, npath)
    end
  end
  return answer, path
end

action = function(host, port)
  local result, path = get_http_page_nmap(port, host, 3)
  --seems to be a bug in the matching
  local loginflags = pcre.flags().CASELESS + pcre.flags().MULTILINE
  local loginre = {
     pcre.new("<script>[^>]*login"    , loginflags, "C"),
     pcre.new("<[^>]*login"           , loginflags, "C"),
     pcre.new("<script>[^>]*password" , loginflags, "C"),
     pcre.new("<script>[^>]*user"     , loginflags, "C"),
     pcre.new("<input[^>)]*user"      , loginflags, "C"),
     pcre.new("<input[^>)]*pass"      , loginflags, "C"),
     pcre.new("<input[^>)]*pwd"       , loginflags, "C") }

  local loginform = false
  for i,v in ipairs(loginre) do
    local ismatch, j = v:match(result.body, 0)
    if ismatch then
      loginform = true
      break
      end
  end
  if loginform then
    return "Login Form Detected at " .. path
  end
end

Nessus Grep

The code is pretty self explanatory. It searches through a .nessus file and spits out matching hosts.

#!/usr/bin/python

def usage():
  print """
This program takes a regular expression for a problem and returns the
affected hosts. It iterates through all reports saved in a .nessus file
making no attempt at uniqueness, (eg if you scanned a host more than once) 
searching through titles, data, port, and IDs for matches.

It prints one host per line, relying on tools like wc, tr, sort, uniq

USAGE:
arg[0] [--dns]  myfile.nessus regex

For a regex reference, see http://docs.python.org/library/re.html

The --dns flag will print out the dns name in addition to what was given for 
the scan

EXAMPLES:

#search for hosts that ran the nikto plugin
python nessus_grep.py scan.nessus nikto

#case insensitive search for nikto
python nessus_grep.py scan.nessus "(?i)nikto"

#it's usually probably ok to just check for id, but be careful
#as an added precaution I give it the beginning end of lines
python nessus_grep.py scan.nessus "^10386$" 

#find all hosts with either the SSL Cipher "bug" or running SSL Version 2
python nessus_grep.py scan.nessus "(SSL Weak Cipher Suites Supported|SSL 
Version 2 (v2) Protocol Detection)"
"""

import sys
import re
from lxml import etree

def regexsearch(regex, *strings):
  for i in strings:
    try:
      if re.search(regex, i):
        return True
    except TypeError:
      pass

"""
Although there is some repeating logic in dotnessusparse
and dotxmlparse, they are two different formats and are
kept separate in case of changes to only one
"""
def dotnessusparse(nessus_xml, hostprint=False):
  for report in nessus_xml.getroot():
    if "Report" in repr(report.tag):
      for host in report:
        if "ReportHost" in host.tag:
          hostname = (host.find("HostName").text)
          dnsname = host.find("dns_name").text.rstrip(".\n")
          if ("(unknown)" in dnsname):
            dnsname = ""
          reptitem = (host.findall("ReportItem"))
          for issue in reptitem:
            data = issue.find("data").text
            pluginname = issue.find("pluginName").text
            pluginid = issue.find("pluginID").text
            port = issue.find("port").text
            if regexsearch(regex, data, pluginname, pluginid, port):
              if hostprint:
                hostname = hostname + " (" + dnsname + ")"
              print hostname
              break

def dotxmlparse(nessus_xml, hostprint=False):
  for report in nessus_xml.getroot():
    if "Report" in repr(report.tag):
      for host in report:
        if "ReportHost" in host.tag:
          hostname = host.get("name")
          dnsname = ""
          hostprops = host.find("HostProperties").findall("tag")
          for prop in hostprops:
            if prop.get("name") == "host-fqdn":
              dnsname = prop.text
          reptitem = (host.findall("ReportItem"))
          for issue in reptitem:
            data = sol = syn = plugout = None
            if issue.find("description") is not None:
              data = issue.find("description").text
            if issue.find("solution") is not None:
              sol = issue.find("solution").text
            if issue.find("synopsis") is not None:
              syn = issue.find("synopsis").text
            if issue.find("plugin_output") is not None:
              plugout = issue.find("plugin_output").text
            pluginname = issue.get("pluginName")
            pluginId = issue.get("pluginID")
            if regexsearch(regex, sol, syn, plugout, pluginname, pluginId):
              if hostprint:
                hostname = hostname + " (" + dnsname + ")"
              print hostname
              break

if __name__ == "__main__":
  re.IGNORECASE
  if len(sys.argv) < 3:
    usage()
    sys.exit(0)
  filelist = sys.argv[1:-1]
  try:
    filelist.remove("--dns")
    hostprint = True
  except ValueError:
    hostprint = False
  regex = sys.argv[-1]
  for nessusfile in filelist:
    nessus_xml = etree.parse(nessusfile)
    if nessusfile.endswith(".nessus"):
      dotnessusparse(nessus_xml, hostprint)          
    if nessusfile.endswith(".xml"):
      dotxmlparse(nessus_xml, hostprint) 

calling convention cheat sheet

cdecl, stdcall, fastcall, c++

Overgeneralization, but may be helpful.

  • cdecl: parameters right to left on the stack, caller places parameters and removes parameters. gcc uses this.
  • stdcall: similar to cdecl, but callee removes function parameters from the stack when finished. Advantage, clean up code doesn’t need to be rewritten for each function. disadvantage, unknown number of parameters are impossible (printf) Microsoft compilers use this
  • fastcall stdcall, but uses two parameters in cpu registers (ecx and then edx)
  • c++ ‘this’ is passed in ecx (ms visual c++) or passed as first parameter (g++)

More handy is this: http://en.wikipedia.org/wiki/X86_calling_conventions
awesome

Follow

Get every new post delivered to your Inbox.