Лаборатория [ASIS CTF Quals 2016] - Leaked License [64]

Groke
, 09 May 2016

I have borrowed this software license and library from Big Brother of a friend of a friend! It would be nice if I could have forged a license for the ID of this years competition computer.

Нам дана Leaked_Lisence.dll и файлик admin@nsa.gov.us_license

groke@MacBook-Air-groke:~/ctf/asis/Leaked_Lisence$ cat admin\@nsa.gov.us_license
7e43ecf0b4e27dacfb5e613437b17acb46e8deab2c70510dc71844b492a691ec

В dll экспортируется один метод verify аргументы которого занимают 48 байт. Если немного посмотреть на файл можно заметить, что исходники были на с++:

"ios_base::eofbit set"
"ios_base::failbit set"
"ios_base::badbit set"

После чего появилось предположение что аргументом является std::string. По коду восстанавливаем следующий вид строки:

struct magic{
    union{
        char *s1;
        char s2[16];
    };
    int size;
    int real_length;
};

После того как добавили в иду эту структурку становится понятно, что функция verify принимает 2 таких строки по значению.

Cобственно сам алгоритм работы следующий(псевдо Python):

def verify(id, license):
    with open("secret.key") as secret_file:
        secret = secret_file.read()
    checkString = sha256(secret).decode('hex')
    while len(id) < 32:
        id = id+id
    secretFromUser = ""
    license = license.decode('hex')
    for i in xrange(32):
        secretFromUser += chr(ord(id[i]) ^ ord(license[i]))
    check2 = sha256(secretFromUser).decode('hex')
    if check2.equal(checkString):
        return 1
    return 0

Очевидно, что нам достаточно получить secretFromUser от данной лицензии и на ее основе генерировать свои. Тут возникла проблема, поскольку было неясно что является ID для лицензии. Появилась теория, что была где то допущена ошибка и написан следующий файл, дабы пощупать ручками:

#include "stdafx.h" 
#include <iostream>
#include <string>
#include <Windows.h>



 
struct magic{
    union{ 
        char *s1; 
        char s2[16]; 
    }; 
    int size; 
    int real_length; 
}; 

magic * get_my_magic(char * buf){ 
    struct magic *ret = (magic *)malloc(24); 
    int ln = strlen(buf); 
    ret->s1 = (char *)malloc(ln);
    ret->size = ln; 
    ret->real_length = ln; 
    strncpy(ret->s1, buf, ln); 
    return ret; 
} 

int main() {
    magic *id = get_my_magic("admin@nsa.gov.us");
    magic *key = get_my_magic("7e43ecf0b4e27dacfb5e613437b17acb46e8deab2c70510dc71844b492a691ec");
    auto hMod = LoadLibraryA("Leaked_Lisence.dll");
    auto myFunc = (int (*)(magic, magic))GetProcAddress(hMod, "verify");
    auto s = myFunc(*id, *key);
    std::cout << s << std::endl;
}

Структурка magic необходима, поскольку sizeof(std::string) в студии был <> 24

Тем не менее практика показала, что теоритические выкладки были верными и мы вернулись к поиску id. Попробовав "quals2016@asis-ctf.ir" получили следующую лицензию:
6e52e0f5a99023eeac30672828ec22db53ea9dab30414a1fca4511ebd5bea4fe
и, как следствие, флаг:
ASIS{6e52e0f5a99023eeac30672828ec22db53ea9dab30414a1fca4511ebd5bea4fe}