
                                TRAITOR OUTLOOK
                                ---------------

  Write   your   mails,   send'em   via  proxies,  trust m$, feel safe... Here
  comes   the   analysis  of  the  OUTLOOK's  algorithm  of  "Message-ID"  and
  "boundary" fields generation. Are you scared? ;)

  So, these fields are generated by INETCOMM.DLL.
  After some disasm, the following stuff were found:

  boundary (generated before Message-ID)
  --------

    GetLocalTime(&lt); // SYSTEMTIME lt
    SystemTimeToFileTime(&lt, &ft); // FILETIME ft
    wsprintfA( boundary,
               "----=_NextPart_%03d_%04X_%08.8lX.%08.8lX",
               part_n,                  // part # of the multipart msg, 0-based
               N,                       // (*)
               ft.dwHighDateTime,
               ft.dwLowDateTime );

  Message-ID
  ----------

    // DWORD ip := current ip || 0x0100007F if error
    GetSystemTime(&lt);
    SystemTimeToFileTime(&lt, &ft);
    wsprintfA( MessageID,
               "%04x%08.8lx$%08.8lx$%08x@%s",
             // ^^^^ can be absent, depending on outlook version
               N+3,                      // (*)
               ft.dwHighDateTime,
               ft.dwLowDateTime,
               ip,
               get_perverted_hostname()  // (**)
             );

  (*)

    N is some number, which is increased by 11..13 when new message is
    generated/sent, and probably in other cases.

  (**)

    1. gethostname()
    2. remove all characters except ['A'..'Z', 'a'..'z', '0'..'9', '.']
    3. while (last char == '.') remove last char
    4. if empty string, return "LocalHost"

  EXAMPLE
  -------

  Lets use google to find some outlook msg containing headers.
  http://www.rational.com/HyperMail/uml_feedback/mailfiles/uml_feedback.9904

      From uml_feedback-owner@Rational.Com  Wed Apr 14 09:01:42 1999
      Received: (from majordom@localhost)
              by mailhub.rational.com (8.8.7/8.8.7/RATIONAL-mailhub) id JAA19138
              for uml_feedback-outgoing; Wed, 14 Apr 1999 09:01:41 -0700 (PDT)
      From: "Dendelphi" <dendelphi@lanet.com.pe>
      To: <uml_feedback@Rational.Com>
      Cc: <yurirenzo@hotmail.com>
      Date: Wed, 14 Apr 1999 10:00:33 -0500
      Message-ID: <01be8687$8b98b3a0$29e084a1@misti.abaco.edu.pe>
      MIME-Version: 1.0
      Content-Type: multipart/alternative;
              boundary="----=_NextPart_000_0004_01BE865D.A2C2ABA0"
      X-Priority: 3
      X-MSMail-Priority: Normal
      X-Mailer: Microsoft Outlook Express 4.71.1712.3
      X-MimeOLE: Produced By Microsoft MimeOLE V4.71.1712.3
      Sender: owner-uml_feedback@Rational.Com
      Precedence: first-class
      Reply-To: "Dendelphi" <dendelphi@lanet.com.pe>
      X-Majordomo-Taboo: uml_feedback
      ...

  Here is our fields:

    boundary    ----=_NextPart_000_0004_01BE865D.A2C2ABA0
    Message-ID  01be8687$8b98b3a0$29e084a1@misti.abaco.edu.pe

  Now, lets use the following program:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#pragma hdrstop

void main(int argc, char* argv[])
{
  char *boundary, *messageid, *hostname;
  DWORD part_n, ip;
  int tz, n1, n2;
  FILETIME ft1, ft2;
  SYSTEMTIME st, lt;

  if (argc != 3)
  {
    printf("syntax:\n");
    printf("  outlookx <boundary> <messageid>\n");
    exit(0);
  }

  boundary  = argv[1];
  messageid = argv[2];

  assert(!strncmp(boundary, "----=_NextPart_", 15));

  assert(sscanf(boundary+15, "%03d", &part_n));
  assert(sscanf(boundary+19, "%04X", &n1));
  assert(sscanf(boundary+24, "%08X", &ft1.dwHighDateTime));
  assert(sscanf(boundary+33, "%08X", &ft1.dwLowDateTime));
  FileTimeToSystemTime(&ft1, &st);

  if (messageid[8] == '$')
  {
    n2 = -1;
    assert(sscanf(messageid+ 0, "%08x", &ft2.dwHighDateTime));
    assert(sscanf(messageid+ 9, "%08x", &ft2.dwLowDateTime));
    assert(sscanf(messageid+18, "%08x", &ip));
    hostname = messageid+27;
  }
  else
  {
    assert(sscanf(messageid+ 0, "%04x", &n2));
    assert(sscanf(messageid+ 4, "%08x", &ft2.dwHighDateTime));
    assert(sscanf(messageid+13, "%08x", &ft2.dwLowDateTime));
    assert(sscanf(messageid+22, "%08x", &ip));
    hostname = messageid+31;
  }
  FileTimeToSystemTime(&ft2, &lt);

  tz = (*(__int64*)&ft1 - *(__int64*)&ft2) / 10000000 / 3600;

  printf("boundary   = %s\n", boundary);
  printf("  part_n   = %d\n", part_n);
  printf("  n1       = %d\n", n1);
  printf("  time     = %04d/%02d/%02d %02d:%02d:%02d.%d GMT%s%d\n",
    st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
    st.wMilliseconds,
    tz > 0 ? "+" : "", tz);
  printf("  hostname = %s\n", hostname);

  printf("messageid  = %s\n", messageid);
  if (n2 != -1)
  printf("  n2       = %d  # delta=%d\n", n2, n2-n1);
  printf("  time     = %04d/%02d/%02d %02d:%02d:%02d.%d GMT\n",
    lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond,
    lt.wMilliseconds);
  printf("  IP       = %s\n", inet_ntoa(*(struct in_addr*)&ip));
  printf("  hostname = %s\n", hostname);

}

  c:\>outlookx ----=_NextPart_000_0004_01BE865D.A2C2ABA0 01be8687$8b98b3a0$29e084a1@misti.abaco.edu.pe

  Program output:

  boundary   = ----=_NextPart_000_0004_01BE865D.A2C2ABA0
    part_n   = 0
    n1       = 4
    time     = 1999/04/14 10:00:33.370 GMT-5
    hostname = misti.abaco.edu.pe
  messageid  = 01be8687$8b98b3a0$29e084a1@misti.abaco.edu.pe
    time     = 1999/04/14 15:00:33.370 GMT
    IP       = 161.132.224.41
    hostname = misti.abaco.edu.pe

  As you can see, original IP and timezone of message creation can be found.

  Except that, we can check if delta between N numbers is the same
  as should be produced by the corresponding outlook version;
  this can be used by some spam tests ("forged" headers).

  Also, using initial N number we estimate how many messages were sent
  before our one, in the current outlook session.

  Also, there is time delta between datetime stored in the boundary
  and messageid. This delta is a sum of local timezone plus some milliseconds,
  passed between boundary and messageid generation. In some outlook versions,
  there is only timezone delta, while in other versions we can estimate
  cpu speed; for example on my machine delta is equal to
  timezone + 40..1000 milliseconds.

  Imagine some hacker who contact's you (or some support group); they reply;
  and now he knows IP address(es) of the machines in the local network;
  even if NAT's and/or proxies are used to send messages.

  As such, using outlook is unsafe, since it leads to original IP and
  other local information disclosure.

  On other hand, knowing this all, original IP could be forged. ;-)

  P.S.
  Probably, eudora and other m$, ole and other shit -related mailers
  do the same.

                                     * * *
