================================================================================ FICTIONAL DISASSEMBLY — CTF Red Team Lesson 06 Tool: objdump -d -M intel challenge_keychecker Section: .text (key-checking function) Architecture: x86-64 NOTE: This is a text representation for educational purposes only. ================================================================================ challenge_keychecker: file format elf64-x86-64 Disassembly of section .text: 0000000000401000
: 401000: 55 push rbp 401001: 48 89 e5 mov rbp,rsp 401004: 48 83 ec 50 sub rsp,0x50 401008: 48 8d 3d f1 0f 00 00 lea rdi,[rip+0xff1] # 402000 <_IO_stdin_used+0x0> 40100f: e8 ec fe ff ff call 400f00 401014: 48 8d 3d f5 0f 00 00 lea rdi,[rip+0xff5] # 402010 <_IO_stdin_used+0x10> 40101b: 31 c0 xor eax,eax 40101d: e8 de fe ff ff call 400f00 401022: 48 8d 45 b0 lea rax,[rbp-0x50] 401026: 48 89 c6 mov rsi,rax 401029: 48 8d 3d f0 0f 00 00 lea rdi,[rip+0xff0] # 402020 <_IO_stdin_used+0x20> 401030: 31 c0 xor eax,eax 401032: e8 c9 fe ff ff call 400f00 401037: 48 8d 7d b0 lea rdi,[rbp-0x50] 40103b: e8 10 00 00 00 call 401050 401040: 85 c0 test eax,eax 401042: 74 0e je 401052 401044: 48 8d 3d e5 0f 00 00 lea rdi,[rip+0xfe5] # 402030 <"Access granted!"> 40104b: eb 0c jmp 401059 40104d: 48 8d 3d ec 0f 00 00 lea rdi,[rip+0xfec] # 402040 <"Access denied!"> 401054: e8 a7 fe ff ff call 400f00 401059: 31 c0 xor eax,eax 40105b: c9 leave 40105c: c3 ret ; ========================================================================== ; check_key — validates user input against hardcoded password ; Arguments: rdi = pointer to user input string ; Returns: eax = 1 if valid, 0 if invalid ; ========================================================================== 0000000000401050 : 401050: 55 push rbp 401051: 48 89 e5 mov rbp,rsp 401054: 48 89 7d f8 mov QWORD PTR [rbp-0x8],rdi ; save input pointer 401058: 48 83 ec 20 sub rsp,0x20 ; --- Step 1: Check input length --- 40105c: 48 8b 7d f8 mov rdi,QWORD PTR [rbp-0x8] 401060: e8 9b fe ff ff call 400f00 401065: 48 83 f8 10 cmp rax,0x10 ; length must be 16 401069: 75 60 jne 4010cb ; fail if wrong length ; --- Step 2: Check first 4 characters directly --- 40106b: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8] 40106f: 0f b6 00 movzx eax,BYTE PTR [rax] ; input[0] 401072: 3c 73 cmp al,0x73 ; 's' = 0x73 401074: 75 55 jne 4010cb 401076: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8] 40107a: 0f b6 40 01 movzx eax,BYTE PTR [rax+0x1] ; input[1] 40107e: 3c 33 cmp al,0x33 ; '3' = 0x33 401080: 75 49 jne 4010cb 401082: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8] 401086: 0f b6 40 02 movzx eax,BYTE PTR [rax+0x2] ; input[2] 40108a: 3c 63 cmp al,0x63 ; 'c' = 0x63 40108c: 75 3d jne 4010cb 40108e: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8] 401092: 0f b6 40 03 movzx eax,BYTE PTR [rax+0x3] ; input[3] 401096: 3c 72 cmp al,0x72 ; 'r' = 0x72 401098: 75 31 jne 4010cb ; --- Step 3: XOR-check remaining characters against key array --- ; The expected values (XOR'd with 0x42) are stored at 0x402050 ; Expected XOR'd bytes: 0x27 0x76 0x2a 0x74 0x27 0x24 0x20 0x22 ; 0x75 0x2c 0x2b 0x24 ; After XOR with 0x42: 'e' '4' 'h' '6' 'e' 'f' 'b' '`' -- wait ; Let's make this spell something: ; We want "s3cr" + "3t_k3y_v4lu3" = "s3cr3t_k3y_v4lu" (16 chars with null... ; actually "s3cr" already set, need 12 more to get 16 total) ; Remaining 12 chars: "3t_k3y_v4lu3" ; XOR with 0x42: ; '3'^0x42=0x71, 't'^0x42=0x36, '_'^0x42=0x1d, 'k'^0x42=0x29 ; '3'^0x42=0x71, 'y'^0x42=0x3b, '_'^0x42=0x1d, 'v'^0x42=0x34 ; '4'^0x42=0x76, 'l'^0x42=0x2e, 'u'^0x42=0x37, '3'^0x42=0x71 40109a: 48 c7 45 e8 00 00 00 mov QWORD PTR [rbp-0x18],0x0 ; i = 0 4010a1: 00 4010a2: eb 1e jmp 4010c2 ; jump to loop check ; --- XOR comparison loop --- 4010a4: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8] ; loop body start 4010a8: 48 03 45 e8 add rax,QWORD PTR [rbp-0x18] 4010ac: 48 83 c0 04 add rax,0x4 ; &input[i+4] 4010b0: 0f b6 10 movzx edx,BYTE PTR [rax] ; dl = input[i+4] 4010b3: 80 f2 42 xor dl,0x42 ; dl ^= 0x42 4010b6: 48 8d 05 93 0f 00 00 lea rax,[rip+0xf93] ; 402050 4010bd: 48 03 45 e8 add rax,QWORD PTR [rbp-0x18] 4010c1: 0f b6 00 movzx eax,BYTE PTR [rax] ; al = expected[i] 4010c4: 38 c2 cmp dl,al ; compare XOR'd input vs expected 4010c6: 75 03 jne 4010cb ; fail if mismatch ; --- Loop increment and bounds check --- 4010c8: 48 ff 45 e8 inc QWORD PTR [rbp-0x18] ; i++ 4010cc: 48 83 7d e8 0c cmp QWORD PTR [rbp-0x18],0xc ; i < 12? 4010d1: 7c d1 jl 4010a4 ; continue loop ; --- All checks passed --- 4010d3: b8 01 00 00 00 mov eax,0x1 ; return 1 (success) 4010d8: eb 05 jmp 4010df ; --- Failure path --- 4010da: b8 00 00 00 00 mov eax,0x0 ; return 0 (failure) 4010df: c9 leave 4010e0: c3 ret ; ========================================================================== ; Data referenced by check_key (in .rodata at 0x402050) ; These are the XOR-expected bytes for characters input[4] through input[15] ; To recover plaintext: expected[i] XOR 0x42 = correct_char ; ========================================================================== Contents of section .rodata at 0x402050: 402050: 71 36 1d 29 71 3b 1d 34 76 2e 37 71 q6.)q;.4v.7q ; Decoding the XOR table: ; 0x71 ^ 0x42 = 0x33 = '3' ; 0x36 ^ 0x42 = 0x74 = 't' ; 0x1d ^ 0x42 = 0x5f = '_' ; 0x29 ^ 0x42 = 0x6b = 'k' ; 0x71 ^ 0x42 = 0x33 = '3' ; 0x3b ^ 0x42 = 0x79 = 'y' ; 0x1d ^ 0x42 = 0x5f = '_' ; 0x34 ^ 0x42 = 0x76 = 'v' ; 0x76 ^ 0x42 = 0x34 = '4' ; 0x2e ^ 0x42 = 0x6c = 'l' ; 0x37 ^ 0x42 = 0x75 = 'u' ; 0x71 ^ 0x42 = 0x33 = '3' ; Full password: "s3cr" + "3t_k3y_v4lu3" = "s3cr3t_k3y_v4lu3" ; ========================================================================== ; decode_flag — called after successful key check ; Decodes the flag by XOR'ing stored bytes with key 0x42 ; ========================================================================== 0000000000401100 : 401100: 55 push rbp 401101: 48 89 e5 mov rbp,rsp 401104: 48 83 ec 30 sub rsp,0x30 401108: 48 8d 05 f1 0f 00 00 lea rax,[rip+0xff1] ; 402100 40110f: 48 89 45 d0 mov QWORD PTR [rbp-0x30],rax ; encoded_flag ptr 401113: 48 c7 45 e8 00 00 00 mov QWORD PTR [rbp-0x18],0x0 ; i = 0 40111a: 00 40111b: eb 18 jmp 401135 ; --- Decode loop: flag[i] = encoded[i] ^ 0x42 --- 40111d: 48 8b 45 d0 mov rax,QWORD PTR [rbp-0x30] 401121: 48 03 45 e8 add rax,QWORD PTR [rbp-0x18] 401125: 0f b6 10 movzx edx,BYTE PTR [rax] ; dl = encoded[i] 401128: 80 f2 42 xor dl,0x42 ; dl ^= 0x42 40112b: 48 8d 45 d8 lea rax,[rbp-0x28] 40112f: 48 03 45 e8 add rax,QWORD PTR [rbp-0x18] 401133: 88 10 mov BYTE PTR [rax],dl ; decoded[i] = dl 401135: 48 ff 45 e8 inc QWORD PTR [rbp-0x18] ; i++ 401139: 48 83 7d e8 18 cmp QWORD PTR [rbp-0x18],0x18 ; i < 24? 40113e: 7c dd jl 40111d ; --- Print decoded flag --- 401140: 48 8d 7d d8 lea rdi,[rbp-0x28] 401144: e8 b7 fd ff ff call 400f00 401149: c9 leave 40114a: c3 ret ; ========================================================================== ; Encoded flag data at 0x402100 (24 bytes, XOR'd with 0x42) ; ; 04 2e 23 05 39 70 31 22 25 33 31 36 23 37 24 70 25 22 31 23 27 23 76 39 ; ; Decode: each byte XOR 0x42: ; 0x04^0x42='F', 0x2e^0x42='l', 0x23^0x42='A', 0x05^0x42='G', ; 0x39^0x42='{', 0x70^0x42='2', 0x31^0x42='s', 0x22^0x42='`'... ; ; Let's encode FLAG{r3v3rs3_3ng1n33r1ng} (25 chars) with XOR 0x42: ; F=0x46^0x42=0x04 L=0x4c^0x42=0x0e A=0x41^0x42=0x03 G=0x47^0x42=0x05 ; {=0x7b^0x42=0x39 r=0x72^0x42=0x30 3=0x33^0x42=0x71 v=0x76^0x42=0x34 ; 3=0x33^0x42=0x71 r=0x72^0x42=0x30 s=0x73^0x42=0x31 3=0x33^0x42=0x71 ; _=0x5f^0x42=0x1d 3=0x33^0x42=0x71 n=0x6e^0x42=0x2c g=0x67^0x42=0x25 ; 1=0x31^0x42=0x73 n=0x6e^0x42=0x2c 3=0x33^0x42=0x71 3=0x33^0x42=0x71 ; r=0x72^0x42=0x30 1=0x31^0x42=0x73 n=0x6e^0x42=0x2c g=0x67^0x42=0x25 ; }=0x7d^0x42=0x3f ; ========================================================================== Contents of section .rodata at 0x402100: 402100: 04 0e 03 05 39 30 71 34 71 30 31 71 ....90q4q01q 40210c: 1d 71 2c 25 73 2c 71 71 30 73 2c 25 .q,%s,qq0s,% 402118: 3f ? ; Decoded flag: FLAG{r3v3rs3_3ng1n33r1ng} ================================================================================ ANALYSIS SUMMARY Password: s3cr3t_k3y_v4lu3 - First 4 chars checked via direct byte comparison (0x73, 0x33, 0x63, 0x72) - Remaining 12 chars checked via XOR with 0x42 against stored table Flag: FLAG{r3v3rs3_3ng1n33r1ng} - Encoded in .rodata at 0x402100 using XOR with key 0x42 - Decoded by decode_flag function after successful authentication Key observations for students: 1. The length check (cmp rax, 0x10) reveals password is 16 characters 2. Direct character comparisons leak the first 4 bytes of the password 3. The XOR key (0x42) is visible in the xor dl,0x42 instruction 4. The expected XOR'd values at 0x402050 can be decoded statically 5. The encoded flag at 0x402100 uses the same XOR key 6. No need to run the binary — pure static analysis is sufficient ================================================================================