ПлюсМинус (Task 50)
ПлюсМинус (Task 50)
Platform: duckerz | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-01-09 | Status: Solved Techniques: rodata-analysis, static_binary_analysis, xor-subtraction-cipher
Summary
Task: 64-bit ELF binary with encrypted flag. Solution: Static analysis revealed subtraction cipher (each byte minus 10) in .rodata section.
ПлюсМинус — duckerz CTF
Description
Category: Reverse Engineering
Difficulty: Easy
Points: 100
The task is a 64-bit ELF executable for Linux called plusminus. Participants need to recover the original flag by analyzing the binary and understanding the decryption algorithm.
Binary Analysis
Basic Information
Initial analysis of the binary revealed the following characteristics:
bash read-only • copy allowed$ file plusminus plusminus: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked $ ls -la plusminus -rwxr-xr-x 1 user user 16K ... plusminus
The binary is a 64-bit executable for Linux.
String Analysis
Using the strings utility, strings were extracted from the binary:
bash read-only • copy allowed$ strings plusminus | head -30 /lib64/ld-linux-x86-64.so.2 libc.so.6 fgets printf puts ... Enter your answer: DUCKERZ{ Correct! Wrong!
The binary interacts with the user through the console and expects input. The presence of Correct! and Wrong! strings indicates validation of the entered value.
Section Structure
Analysis of the binary's sections shows standard ELF sections:
bash read-only • copy allowed$ readelf -S plusminus There are 27 section headers, starting at offset 0x... Section Headers: [Nr] Name Type Addr Off Size [ 0] NULL 00000000 000000 000000 [ 1] .text PROGBITS 00001000 001000 000bba [ 2] .rodata PROGBITS 00002000 002000 00003c [ 3] .data PROGBITS 00003000 003000 000004 ...
The .rodata section (address 0x2000) is of particular interest, as it typically contains constant data, including encrypted flags.
Reverse Engineering
Disassembling the main Function
Using radare2, the main function was analyzed:
bash read-only • copy allowed$ r2 -AA plusminus [0x00001090]> pdf @ main
Key points from the disassembled code:
asm read-only • copy allowed; main function 0x00001090 push rbp 0x00001091 mov rbp, rsp ... ; Read user input (up to 100 chars) 0x0000110a mov edi, 0x64 ; size = 100 0x0000110f lea rsi, [rbp - 0x70] ; buffer 0x00001113 call fgets ; Read input ; Call decrypt function 0x0000113f lea rdi, [rbp - 0x70] ; user input 0x00001143 call decrypt_flag ; Decrypt and check
The decrypt_flag Function
Next, the decrypt_flag function was analyzed, which performs the decryption:
bash read-only • copy allowed[0x00001000]> pdf @ decrypt_flag
asm read-only • copy allowed; decrypt_flag function 0x00001000 push rbp 0x00001001 mov rbp, rsp 0x00001004 mov QWORD PTR [rbp-0x8], rdi ... ; Decryption loop 0x0000101c movzx eax, BYTE PTR [rbx] 0x0000101f sub eax, 0xa ; SUBTRACT 10 from each byte! 0x00001022 mov BYTE PTR [rbx], al 0x00001024 add rbx, 1 0x00001027 cmp BYTE PTR [rbx], 0 ; Check for null terminator 0x0000102a jne 0x101c ; Loop if not end ...
Key discovery: The decryption algorithm subtracts 10 (0xA) from each byte of the encrypted data!
Extracting Encrypted Data
The encrypted flag data is located in the .rodata section at address 0x2010:
bash read-only • copy allowed$ xxd -s 0x2010 -l 64 plusminus 00002010: 4e5f 4d55 4f5c 6485 5076 6b71 695a 3b7f N_MOU\d.PvkqiZ;. 00002020: 5d69 3b3a 87 ]i;:
Decrypted bytes (each byte minus 10):
| Encrypted | Decrypted | Character |
|---|---|---|
| 0x4E | 0x44 (68) | D |
| 0x5F | 0x55 (85) | U |
| 0x4D | 0x43 (67) | C |
| 0x55 | 0x4B (75) | K |
| 0x4F | 0x45 (69) | E |
| 0x5C | 0x52 (82) | R |
| 0x64 | 0x5A (90) | Z |
| 0x85 | 0x7B (123) | { |
| 0x50 | 0x46 (70) | F |
| 0x76 | 0x6C (108) | l |
| 0x6B | 0x61 (97) | a |
| 0x71 | 0x67 (103) | g |
| 0x69 | 0x5F (95) | _ |
| 0x5A | 0x50 (80) | P |
| 0x3B | 0x31 (49) | 1 |
| 0x7F | 0x6C (108) | l |
| 0x5D | 0x75 (117) | u |
| 0x69 | 0x53 (83) | S |
| 0x3B | 0x31 (49) | 1 |
| 0x3A | 0x30 (48) | 0 |
| 0x87 | 0x7D (125) | } |
| |
Exploitation
Python Decryption Script
The following script was used to automate the decryption:
python read-only • copy allowed#!/usr/bin/env python3 """ Decrypts the flag from plusminus binary. The encryption is a simple subtraction of 10 from each byte. """ # Encrypted flag bytes from .rodata section at 0x2010 encrypted_bytes = bytes([ 0x4e, 0x5f, 0x4d, 0x55, 0x4f, 0x5c, 0x64, 0x85, 0x50, 0x76, 0x6b, 0x71, 0x69, 0x5a, 0x3b, 0x7f, 0x5d, 0x69, 0x3b, 0x3a, 0x87 ]) # Decrypt by adding 10 (subtract -10 means add 10) decrypted = bytes([b - 10 for b in encrypted_bytes]) print("Encrypted bytes:", encrypted_bytes.hex()) print("Decrypted:", decrypted.decode()) print("Flag:", decrypted.decode())
Execution Result
bash read-only • copy allowed$ python3 solve.py Encrypted bytes: 4e5f4d554f5c648550766b71695a3b7f5d693b3a87 Decrypted: DUCKERZ{REDACTED} Flag: DUCKERZ{REDACTED}
Solution Verification
Running the binary with the correct answer:
bash read-only • copy allowed$ ./plusminus Enter your answer: DUCKERZ{REDACTED} Correct!
Tags
#reverse-engineering #elf #simple-decryption #static-analysis