0% found this document useful (0 votes)
5 views67 pages

Codebreaker2 Techtalk v6.1

The Fall 2014 Codebreaker Challenge 2.0 involves reverse-engineering a program believed to be used by a terrorist organization for covert communication. Participants must complete four tiers of challenges, starting with executing hidden functionality and culminating in decrypting a message from a high-value target. Solutions are due by the end of 2014, and participants are encouraged to use various reverse engineering tools and techniques to succeed.

Uploaded by

Joe Ordinary
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views67 pages

Codebreaker2 Techtalk v6.1

The Fall 2014 Codebreaker Challenge 2.0 involves reverse-engineering a program believed to be used by a terrorist organization for covert communication. Participants must complete four tiers of challenges, starting with executing hidden functionality and culminating in decrypting a message from a high-value target. Solutions are due by the end of 2014, and participants are encouraged to use various reverse engineering tools and techniques to succeed.

Uploaded by

Joe Ordinary
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 67

Fall 2014

CODEBREAKER CHALLENGE 2.0

1
Challenge Scenario
“An international terrorist organization has recently
revised the operational security (OPSEC) procedures
used to communicate with their members in the field.
We have recovered a program that we believe is
being used to covertly send encrypted messages. On
the surface, the program appears to simply check the
weather forecast in a few cities, but we believe there
is more to the program than meets the eye. Your
mission is to figure out how to execute the covert
functionality, reverse-engineer the encryption
algorithm, create a decryption program, and lastly
figure out a way to decipher a message that was
captured from a high-value target.”
2
The Challenge

 There are 4 different levels or "tiers" to this


challenge problem
 Tier 1: Determine how to execute the hidden
functionality
 Tier 2: Bypass an authentication check
 Tier 3: Create a decryption program
 Tier 4: Decrypt message from a high-value target
 Each tier gets progressively harder and builds
off lower tiers
3
The Challenge (cont.)

 The program will provide you with directions


for where to send an encrypted email after
you complete Tier 3
 Please use your *.edu address so we know you are
a student
 You will then be sent the encrypted message for
Tier 4
 Solutions are due by the end of 2014

4
Getting Started

 Review the ‘Getting Started’ tips in the


Codebreaker Challenge document
 Download the IDA Demo from Hex-Rays
 https://www.hex-
rays.com/products/ida/support/download_demo.h
tml
 Try running the program with different
options and observe its behavior
 Disassemble and start analyzing the binary
5
Reverse Engineering Tips

 Examine strings in the binary using IDA


 Look for clues that relate to the functionality you are trying
to find / reverse
 Utilize IDA xrefs to find code that references the string(s) of
interest
 Utilize symbols (e.g., function names) to help determine
what a section of code does
 Try setting debugger breakpoints to help RE code
 Single-step after hitting a breakpoint and see how the
values in registers/memory change
 Look for the result of interesting computations. You can
sometimes get the data you need from memory
 Leverage online resources, e.g.,Intel manuals, RE
lectures, etc. for help on reverse-engineering
6
Reverse Engineering Tips

 Optimizing compilers sometimes generate


strange looking code for simple operations

 In this challenge, you will encounter one such


optimization during Tiers 2 – 4

 To save you some time/frustration, we will


walk through an example and explain the
math behind the optimization
7
What does this code do?
mov edx, 0xAC769185 // edx = 0xAC769185
mov eax, ecx // ecx = input value
imul edx // edx:eax = eax * edx
lea eax, [edx + ecx*0x1]// eax = edx + ecx
mov edx, eax // edx = eax
sar edx, 0x6 // arith right shift; edx = edx >> 0x6
mov eax, ecx // eax = ecx
sar eax, 0x1f // eax = eax >> 0x1f (31)
mov ebx, edx // ebx = edx
sub ebx, eax // ebx = ebx - eax
mov eax, ebx // eax = ebx
imul eax, eax, 0x5f // edx:eax = eax * 0x5f (95)
mov edx, ecx // edx = ecx
sub edx, eax // edx = edx – eax
// edx is the final result

8
Signed Division and Remainder

 The code computes: edx = ecx % 95


 Why multiply by 0xAC769185 and where did that
number come from?
 Division is a time consuming operation
 When the divisor is a constant, the compiler can
optimize the computation
 The basic trick is to multiply by a “magic value”
(~ 232/d) and extract the leftmost 32 bits of the
product
 The following site computes these numbers for
you: http://www.hackersdelight.org/magic.htm
9
Signed Division and Remainder

 For wordsize W ≥ 3 and divisor d, 2 ≤ d <


2𝑊−1 , we wish to find the least integer m and
p such that:

𝑚𝑛 𝑛
= for 0 ≤ n < 2𝑊−1 (1a)
2𝑝 𝑑
𝑚𝑛 𝑛
+1= for −2𝑊−1 ≤ n ≤ −1 (1b)
2𝑝 𝑑

with 0 ≤ m < 2𝑊 and p ≥ 𝑊


10
Signed Division and Remainder

 The “magic number” M used in the multiply


instruction is given by:
𝑚, 𝑖𝑓 0 ≤ 𝑚 < 2𝑊−1
𝑀=
𝑚 − 2𝑊 , 𝑖𝑓 2𝑊−1 ≤ 𝑚 < 2𝑊
 Because (1b) must hold for 𝑛 = −𝑑,
−𝑚𝑑
+ 1 = −1, which implies
2𝑝
𝑚𝑑
>1 (2)
2𝑝

11
Signed Division and Remainder

 Let 𝑛𝑐 be the largest value of n such that


rem(𝑛𝑐 , d) = d-1. It can be calculated from:
2𝑊−1
𝑛𝑐 = ∗d−1
𝑑
= 2𝑊−1 − 𝑟𝑒𝑚 2𝑊−1 , 𝑑 − 1 (3)
 Because (1a) must hold for 𝑛 = 𝑛𝑐 :
𝑚𝑛𝑐 𝑛𝑐 𝑛𝑐 −(𝑑−1)
= = or
2𝑝 𝑑 𝑑
𝑚𝑛𝑐 𝑛𝑐 +1
< (4)
2𝑝 𝑑
12
Signed Division and Remainder

 Combining (4) with (2) gives:


2𝑝 2𝑝 𝑛𝑐 +1
<𝑚< (5)
𝑑 𝑑 𝑛𝑐
 Because 𝑚 is to be the least integer satisfying
2𝑝
(5), it is the next integer greater than :
𝑑
2𝑝 +𝑑−𝑟𝑒𝑚(2𝑝 ,𝑑) 2𝑝
𝑚= = +1 (6)
𝑑 𝑑
2𝑝 > 𝑛𝑐 (𝑑 − 𝑟𝑒𝑚 2𝑝 , 𝑑 ) (7)

13
Signed Division and Remainder

 Algorithm to find 𝑀 and shift amount 𝑠 from 𝑑


 Compute 𝑛𝑐 using (3)
 Solve for 𝑝 by trying successively larger values,
starting at 𝑊, until satisfying the inequality in (7)
 When the smallest 𝑝 ≥ 𝑊 satisfying (7) is found,
𝑚 is calculated from (6)
 The shift amount is computed as: 𝑠 = 𝑝 − 𝑊
 𝑀 is simply a reinterpretation of 𝑚 as a signed
integer

14
64-bit Data Types
Consider the following program:

int main(){
char one = 0x11; // sizeof(char) == 1
char two = 0x22;
int three = 0x33333333; // sizeof(int) == 4
int four = 0x44444444;
long long five = 0x5555555555555555; // sizeof(long long) == 8
long long six = 0x6666666666666666;
printf("8b: %hu 32b: %u 64b: %llu\n", one + two, three + four, five + six);
return 0;
}

15
64-bit Data Types – x86_64
Part 1: Move values onto the stack

mov BYTE PTR [rbp-0x2],0x11


mov BYTE PTR [rbp-0x1],0x22
mov DWORD PTR [rbp-0xc],0x33333333
mov DWORD PTR [rbp-0x8],0x44444444
mov DWORD PTR [rbp-0x20],0x55555555
mov DWORD PTR [rbp-0x1c],0x55555555
mov DWORD PTR [rbp-0x18],0x66666666
mov DWORD PTR [rbp-0x14],0x66666666

16
64-bit Data Types – x86_64
Part 2: Load into registers and compute

mov rax,QWORD PTR [rbp-0x18] // 0x6666666666666666 in rax


mov rdx,QWORD PTR [rbp-0x20] // 0x7777777777777777 in rdx
lea rcx,[rdx+rax*1] // rcx = rax + rdx*1
mov eax,DWORD PTR [rbp-0x8] // 0x44444444 in eax
mov edx,DWORD PTR [rbp-0xc] // 0x33333333 in edx
add edx,eax // edx = edx + eax
movsx esi,BYTE PTR [rbp-0x2] // 0x11 in esi
movsx eax,BYTE PTR [rbp-0x1] // 0x22 in eax
add esi,eax // esi = esi + eax

17
64-bit Data Types – x86
No 64-bit registers 

long long five = 0x5555555555555555; // sizeof(long long) == 8


long long six = 0x6666666666666666;

Let’s make it work with 32-bit ones!

18
64-bit Data Types – x86
Part 1: Move values onto the stack (same as x86_64)

mov BYTE PTR [ebp-1],0x11


mov BYTE PTR [ebp-2],0x22
mov DWORD PTR [ebp-8],0x33333333
mov DWORD PTR [ebp-12],0x44444444
mov DWORD PTR [ebp-24],0x55555555
mov DWORD PTR [ebp-20],0x55555555
mov DWORD PTR [ebp-32],0x66666666
mov DWORD PTR [ebp-28],0x66666666

19
64-bit Data Types – x86
Part 2: Load into registers and compute

mov eax,DWORD PTR [ebp-32] // 0x66666666 in eax


mov edx,DWORD PTR [ebp-28] // 0x66666666 in edx
add eax,DWORD PTR [ebp-24] // eax = eax + 0x55555555
adc edx,DWORD PTR [ebp-20] // edx = edx + 0x55555555 + CF

mov eax,DWORD PTR [ebp-12] // 0x444444 in eax
add eax,DWORD PTR [ebp-8] // eax = eax + 0x33333333

movsx edx,BYTE PTR [ebp-1] // 0x11 in edx
movsx eax,BYTE PTR [ebp-2] // 0x22 in eax
lea eax,[edx+eax] // eax = edx + eax*

20
Questions

21
Technical Walkthrough

 Original Codebreaker Challenge


 Released during Fall 2013
 Reverse-engineering / crypt challenge
 Program prompted for a password
 AES key is derived from SHA256 hash of password
 AES-encrypted blob w/ instructions for how to submit the
solution stored in the executable
 To verify the correct password was entered, the derived key is
used to compute an HMAC of the encrypted blob
 If HMAC is correct, the blob is decrypted, revealing
instructions.
 Weakness of the design is in the key-derivation function
 Only first 2-bytes of SHA256 hash matter
 Easy to brute force

22
Running the program

23
Running the program (2)

24
Disassemble

 Disassemble the Codebreaker binary


 If asked whether you want to use Proximity View
 Click no
 Use graph view

25
Disassemble (2)

26
Disassemble (3)

27
Observe Strings
 Observe the strings that show up in IDA
 Click Views->Open Subviews->Strings
 You should see the strings that are displayed when
you run the program
Welcome to the NSA Codebreaker Challenge!

Loading……

To win the challenge, you must be the first to decrypt the code
protected by the password. You are free to use any means at your
disposal to reverse-engineer and/or modify this binary in order to discover
the encryption key. Instructions for submitting you solution will be ‘revealed’
when you are successful…good luck!

Enter Password:
28
Observe Strings (2)

29
Observe Strings (3)

30
ACCESS DENIED

 Double click on the “ACCESS DENIED\n”


string
 This takes you to the data section of the binary
where the string is stored
 To the right of the string are cross references
to this address (show up as DATA XREF in
IDA)
 Press ctrl-x to pull up a cross-references
window; you will see two different references
31
ACCESS DENIED (2)

32
ACCESS DENIED (3)

33
Double-click Reference

 You should now be looking at disassembled


x86 code
 We just leveraged the fact that in order to print
the ACCESS DENIED message to the screen, the
code had to reference the address in the data
section of the program where the string was
stored.
 Using xrefs in IDA is a quick and easy way to
find interesting code sections

34
Double-click Reference (2)

35
Explore Code Block

 Explore the code block preceding the access


denied message (note: you can double-click call statements to visit the function body)
 You will see routines to:
 print the initial welcome screen,
 prompt the user for the password and
 compute the password length
 The branch for “ACCESS DENIED” is taken
when the strlen of the password is 0.

36
Explore Code Block (2)

37
Explore Code Block (3)

38
Explore Code Block (4)

39
Explore Code Block (5)

40
Explore Code Block (6)

41
Explore Code Block (7)

42
Explore Code Block (8)

43
Explore Code Block (9)

44
Explore Code Block (10)

45
Secure Hash Algorithm

 Hash values can be used to verify the


integrity of the data without providing any
means to derive the original data. The
algorithm is irreversible (SHA-2 is implemented in some widely used security
applications and protocols: TLS, SSL, PGP, SSH, S/MIME, Bitcoin and IPsec)

 The first call computes the SHA256 hash of


the password
 You can figure out that it is a SHA256 by Googling
for some of the large constants that you will find
in the code (0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c,
0x1f83d9ab, 0x5be0cd19)

46
Secure Hash Algorithm (2)

47
Secure Hash Algorithm (3)

48
Secure Hash Algorithm (4)

49
Secure Hash Algorithm (5)

50
AES Key Derivation Routine

 AES is a symmetric-key algorithm; same key


is used to encrypt and decrypt the data.
 The AES key is being derived from the hash of
the password
 Lets take a closer look at what is being done
to the password hash

51
AES Key Derivation Routine (2)

52
AES Key Derivation Routine (3)

53
AES Key Derivation Routine (4)

54
AES Key Derivation

 The 16-byte key is derived as follows:


 H0, H1, …, H31 represents the 32-bytes of the
SHA256 hash
 K0, K1, …, K15 are the 16-bytes of key
 R0, R1, …, R15 are the 16-bytes of fixed
random data that is in the program
(0x23,0x8e,0x60,0xe1,0xd2,0x96,0x38,0xc7,0xa5,0xc0,0x22,0x74,0x4f,0x31,0x5b,0xcd)

55
AES Key Derivation
• K0 = H1 xor R0
• K1 = H0 xor R1
• K2 = K1 xor R2
• K3 = K0 xor R3
• K4 = K3 xor R4
• K5 = K2 xor R5
• :
• K15 = K12 xor R15
• Looking at the above equations, do you notice any problems?
– How many bytes of the password hash are ultimately used in the
derivation of the key?
– Given this, how many possible AES keys could be derived from this
function?
– Is that something that you can efficiently compute and brute-force?

56
Keyed-Hash Message
Authentication Code
• Following the code you will see that the AES
key is passed to a function that computes the
Keyed-Hash Message Authentication Code
(HMAC) of the cipher text stored in the
program.
• If the computed HMAC-SHA256 matches the
expected HMAC
(0xbc,0xb0,0x78,0x41,0xaa,0xd0,0x06,0x68,0xdd,0xa4,0x74,0x06,0xd7,0x1a,0x2b,0xd2,0x9b,0x0e,0xdb,0x0d,0xf9,0xce,0xf4,
0xa7,0xf9,0x51,0x6c,0x99,0xfc,0xb6,0x95,0xf8)

 Then, the AES key is used to decrypt the cipher text


 Else, “ACCESS DENIED” message is displayed

57
Keyed-Hash Message
Authentication Code (2)

58
Keyed-Hash Message
Authentication Code (3)

59
Keyed-Hash Message
Authentication Code (4)

60
AES Decryption

61
Brute Force Attack

 Leverage the fact that you know the


expected HMAC and you know how to derive
putative key
 (0xbc,0xb0,0x78,0x41,0xaa,0xd0,0x06,0x68,0xdd,0xa4,0x74,0x06,0xd7,0x1a,0x2b,0xd2,0x9b,0x0e,0xdb,0x0d
,0xf9,0xce,0xf4,0xa7,0xf9,0x51,0x6c,0x99,0xfc,0xb6,0x95,0xf8)

 Write a simple program to brute force the key


and decrypt the ciphertext
 The CyaSSL library is easy to use and contains all
the functions that you need (it was used to write
the challenge problem)

62
Brute Force Code
printf("Searching for a solution...\n");
for (i=0; i < (1<<16); i++)
{
memcpy(hashGuess, (uint8_t*)&i, 2);
// Derive the AES key to decrypt secret code
retCode = deriveAESKey(hashGuess, (uint8_t*)AESKey);
// Compute HMAC of ciphertext
computeHMAC(ciphertext, sizeof(ciphertext), AESKey, AES_KEY_SIZE, HMACdigest);
// Compare computed HMAC with expected value
if (memcmp(HMACdigest, HMAC_cipher, SHA256_DIGEST_SIZE) == 0)
{
fprintf(stderr, "FOUND SOLUTION!\n");
fprintf(stderr, "SHA256 Hash of Password -> Byte 1: 0x%x\tByte 2: 0x%x\n", hashGuess[0], hashGuess[1]);
fprintf(stderr, "AES Key: ");
printHexString(AESKey, AES_KEY_SIZE);
printf("\n");
// Decrypt the challenge ciphertext
decrypt(AESKey, plain, sizeof(plain));
printf("%s\n", plain);
}
}

63
Ciphertext
 uint8_t ciphertext[] = {0x34,0x3b,0x71,0x62,0xba,0x9f,0x55,0xb8,0xd9,0x88,0x71,0x98,0x24,0x41,0x3e,0x4d,
0xa4,0xbd,0x1a,0xe1,0x2c,0xae,0x2c,0xff,0x1d,0x4e,0x1a,0x9e,0x94,0x8a,0x4d,0x07,
0x71,0x5d,0xc6,0x1f,0xef,0x91,0x09,0x67,0xda,0xfa,0x37,0x96,0x11,0xe1,0x67,0xd6,
0x3e,0xa1,0x5e,0x58,0x0b,0x81,0xdd,0xb2,0xaf,0x5d,0xde,0xde,0x9d,0x82,0xb3,0x72,
0x36,0x86,0xa6,0x72,0xea,0x3e,0x5a,0xa0,0x21,0x4e,0x94,0xbf,0x51,0x12,0xbe,0xfc,
0xb6,0x07,0x3d,0x51,0x36,0xcf,0x76,0x93,0xab,0xc6,0x6c,0x7b,0x5f,0xc8,0x16,0xa2,
0x11,0xc0,0xe6,0x87,0x9e,0xab,0x40,0x56,0xa4,0xb7,0xa5,0x20,0x44,0xbf,0xb0,0xb7,
0x5b,0x43,0x4a,0x02,0x19,0x09,0x1d,0xb2,0x30,0xbb,0x15,0xce,0x1c,0x97,0xd8,0x77,
0xbc,0x42,0x87,0x14,0x93,0x85,0xd2,0x0a,0x7d,0xc4,0x44,0x0e,0x82,0x35,0x3b,0xc4,
0x40,0x78,0x7a,0x59,0xa1,0x59,0x18,0x09,0x22,0x17,0x68,0xc0,0xfc,0x7a,0x5f,0x67,
0x5b,0x2a,0xb3,0xfc,0x53,0xbc,0xe0,0x92,0xff,0x0d,0x84,0x74,0x31,0x1f,0xf5,0x16,
0x4f,0x17,0x50,0x8d,0x95,0x51,0x06,0xf7,0xbc,0xda,0x15,0x05,0x76,0xb5,0x10,0x78,
0xa4,0xa1,0xf1,0x45,0xf1,0x6e,0x78,0x2c,0x3a,0x01,0x4e,0x82,0x68,0x4f,0xe8,0x12,
0x69,0xdd,0x00,0x77,0x17,0xec,0x95,0x76,0xbc,0x8c,0x43,0xc5,0x99,0x53,0xba,0x86,
0x4c,0x6b,0x46,0x4a,0x35,0x82,0xe1,0x10,0xee,0x2a,0x73,0x4d,0x80,0x55,0xdc,0xbc};

64
Brute Force Solution

65
Plaintext

 Congratulations! You have successfully


decrypted the challenge cipher.
 Please send an email (use your *.edu address)
with a writeup of your solution and the string
bd461a21f932a4130a6f670d to the following
address: _________________________

66
Questions

67

You might also like