惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
月光博客
月光博客
腾讯CDC
Last Week in AI
Last Week in AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园_首页
量子位
博客园 - 聂微东
Jina AI
Jina AI
小众软件
小众软件
The Cloudflare Blog
有赞技术团队
有赞技术团队
V
V2EX
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
WordPress大学
WordPress大学
阮一峰的网络日志
阮一峰的网络日志
B
Blog
MongoDB | Blog
MongoDB | Blog
L
LangChain Blog
宝玉的分享
宝玉的分享
C
Check Point Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
IT之家
IT之家
N
Netflix TechBlog - Medium
I
InfoQ
J
Java Code Geeks
S
SegmentFault 最新的问题
V
Visual Studio Blog
Microsoft Security Blog
Microsoft Security Blog
博客园 - 叶小钗
D
DataBreaches.Net
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
B
Blog RSS Feed
S
Schneier on Security
Webroot Blog
Webroot Blog
P
Proofpoint News Feed
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threatpost
Project Zero
Project Zero
Scott Helme
Scott Helme
C
CERT Recently Published Vulnerability Notes
P
Privacy International News Feed
T
The Exploit Database - CXSecurity.com
D
Darknet – Hacking Tools, Hacker News & Cyber Security

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
CTF Lab Writeup: "Bypass Me" — PicoCTF Binary Exploitation Challenge
Vedant Kulkarni · 2026-05-31 · via DEV Community

1. Executive Summary

Field Details
Challenge Name Bypass Me
Category Binary Exploitation / Reverse Engineering
Difficulty Beginner–Intermediate
Target bypassme.bin on foggy-cliff.picoctf.net:53044
Primary Technique Static reverse engineering + XOR cipher decoding
Key Vulnerability Runtime password decoded via trivial XOR cipher, fully recoverable through static analysis
Tools Used ssh, file, nm, objdump, Python (mental model)
Flag Location Printed after successful password authentication

The Core Story

A binary that appears to be a secure, hardened authentication portal is completely defeatable through static analysis alone. The password is never truly hidden — it is simply obfuscated using a single-byte XOR operation. By reading the assembly, we recovered the password without ever running a debugger, without brute force, and without guessing. This challenge teaches one of the most fundamental lessons in security: obfuscation is not encryption.


2. Reconnaissance & Enumeration

2.1 Establishing Access

The challenge provides SSH credentials directly:

ssh ctf-player@foggy-cliff.picoctf.net -p 53044
# Password: 1ad5be0d

Enter fullscreen mode Exit fullscreen mode

Why SSH?

The challenge specifies it explicitly. SSH (Secure Shell) provides an interactive remote shell session, allowing us to explore, execute, and analyze the target binary in its native environment.

Breaking Down the Command

Flag Meaning
ctf-player The username we're logging in as
foggy-cliff.picoctf.net The remote hostname
-p 53044 Connect on port 53044 instead of the default SSH port 22

💡 Beginner Tip: Always accept the host fingerprint the first time you connect to a CTF server. In a real production environment, you would verify the fingerprint through a trusted, out-of-band method. In a CTF environment, it is generally safe to type yes.


2.2 Initial File System Enumeration

Once inside, the first thing we do is look around:

ls -la

Enter fullscreen mode Exit fullscreen mode

Why ls -la and not just ls?

  • -l → Long format: shows permissions, owner, size, and modification date
  • -a → Shows hidden files (those starting with .)

Output Analysis:

-rwsr-xr-x 1 root root 21672 Mar  6 20:10 bypassme.bin

Enter fullscreen mode Exit fullscreen mode

The most critical piece of information here is the permission string: -rwsr-xr-x.

That s where you'd normally expect an x for the owner execute bit is the SUID (Set User ID) bit. This deserves its own explanation:

🔑 What is SUID?
Normally, when you run a program, it runs with your permissions. When the SUID bit is set and the file is owned by root, the program runs with root's permissions, regardless of who launches it. This is how sudo and passwd work. In a CTF context, this tells us the binary can read files we cannot — like a flag file owned by root.

What we did NOT do:

  • We did not immediately try to exploit the SUID bit for privilege escalation (e.g., via PATH injection or LD_PRELOAD). Why? Because the challenge description told us the goal is to bypass authentication, not necessarily escalate privileges. The SUID bit is simply the mechanism by which the binary reads the flag file on our behalf.

2.3 Binary Profiling

file bypassme.bin

Enter fullscreen mode Exit fullscreen mode

Why file? The file command reads the magic bytes at the beginning of a file and identifies its true type regardless of extension. This is essential before analysis.

Output:

bypassme.bin: setuid ELF 64-bit LSB shared object, x86-64, dynamically linked, with debug_info, not stripped

Enter fullscreen mode Exit fullscreen mode

Parsing Every Field

Field Meaning & Significance
setuid ELF Confirms that the SUID bit is set. When executed, the binary runs with the privileges of its owner (in this case, root).
64-bit Indicates that the program uses a 64-bit architecture and register set (rax, rdi, rsi, etc.).
LSB Stands for Little-Endian Byte Order, the standard byte ordering used on most modern x86 systems.
x86-64 The binary targets the 64-bit Intel/AMD architecture. Most common reverse-engineering and debugging tools support this architecture natively.
dynamically linked The binary relies on shared libraries (such as libc) at runtime. Functions like strcmp() and printf() are typically resolved from external libraries.
with debug_info A valuable finding. Debug symbols are present, making reverse engineering and source-level debugging significantly easier.
not stripped Another valuable finding. Function names and other symbol information have been retained in the binary, improving readability during analysis.

💡 Key Insight: A "stripped" binary has had its symbol table removed, making reverse engineering significantly harder. A "not stripped" binary with "debug_info" is essentially giving us a roadmap. In a real-world malware scenario or hardened application, symbols would be stripped. This binary was compiled without stripping, which is a developer oversight.


2.4 Runtime Behavior Observation

Before touching any analysis tool, we always run the target to understand its user-facing behavior:

./bypassme.bin

Enter fullscreen mode Exit fullscreen mode

Why run it first? This gives us the "black box" view — what a normal user would see. We observed:

  • An ASCII art banner ("SECURE PORTAL")
  • A loading/initialization animation
  • A password prompt with a 3-attempt counter: [3 tries left] Enter password:

What this tells us:

  1. There is a finite attempt limit — brute force via the normal interface is impractical
  2. The password prompt means there's a comparison somewhere in the code
  3. The 3-attempt limit is enforced in software — meaning we can bypass it entirely by analyzing the binary rather than interacting with it

What we did NOT do:

  • We did not try common passwords (admin, password, 1234). That would be guessing, not hacking.
  • We did not use strings bypassme.bin as our primary approach. While strings can sometimes reveal hardcoded passwords, a developer using even basic obfuscation (like XOR) would defeat it. We wanted a methodology that works even when strings fails.

3. Initial Foothold — Static Reverse Engineering

3.1 Symbol Table Analysis

nm bypassme.bin

Enter fullscreen mode Exit fullscreen mode

What is nm? The nm command lists symbols from an object file or binary. Symbols are named entries in the symbol table — they include function names, global variables, and external library references.

Why nm before objdump? nm gives us the complete map of the binary's functions in seconds. It's the fastest way to understand the binary's structure before committing to deeper disassembly. Think of it as reading the table of contents before reading a book.

Key findings from nm output:

_Z15decode_passwordPc     decode_password(char*)
_Z13auth_sequencev        auth_sequence()
_Z8sanitizePKcPc          sanitize(char const*, char*)
_Z8type_outPKcj           type_out(char const*, unsigned int)

Enter fullscreen mode Exit fullscreen mode

💡 Name Mangling: The _Z15decode_passwordPc format is C++ name mangling. The compiler encodes type information into function names. _Z indicates a mangled name, 15 is the length of the function name, decode_password is the name, and Pc means "pointer to char". You can demangle these with c++filt _Z15decode_passwordPc.

The most important symbol:

_Z15decode_passwordPc   decode_password(char*)

Enter fullscreen mode Exit fullscreen mode

This immediately tells us: the password is not stored in plaintext. It is decoded at runtime by a function. This is our primary target.

External library calls that matter:

U strcmp@@GLIBC_2.2.5

Enter fullscreen mode Exit fullscreen mode

The U means "undefined" — it's imported from an external library. The presence of strcmp tells us the decoded password is compared to user input using a standard string comparison. This is our breakpoint target in a dynamic analysis scenario.


3.2 Disassembling decode_password

objdump -d --no-show-raw-insn bypassme.bin | grep -A 40 '<_Z15decode_passwordPc>'

Enter fullscreen mode Exit fullscreen mode

Breaking Down the Command

Component Meaning
objdump Disassembler for binary files
-d Disassemble executable sections
--no-show-raw-insn Hides raw hex bytes — cleaner output for reading
grep -A 40 Show 40 lines after the matching line
'<_Z15decode_passwordPc>' Match the specific function label

Why objdump and not ghidra or IDA Pro? Those tools are excellent but require a GUI or installation. objdump is available on virtually every Linux system by default, making it the universal first choice for quick static analysis in a remote shell environment.


3.3 Decoding the Password — The Core Vulnerability

From the disassembly of decode_password, we extracted this critical logic:

movabs $0xc9cff9d8cfdadff9,%rax    ; Load 8 encoded bytes into rax
mov    %rax,-0x13(%rbp)             ; Store on stack
movw   $0xd8df,-0xb(%rbp)          ; Load 2 more encoded bytes
movb   $0xcf,-0x9(%rbp)            ; Load 1 more encoded byte

Enter fullscreen mode Exit fullscreen mode

This gives us 11 encoded bytes stored on the stack:

f9 df da cf d8 f9 cf c9 df d8 cf

Enter fullscreen mode Exit fullscreen mode

⚠️ Important — Endianness: The value 0xc9cff9d8cfdadff9 is stored in little-endian format. This means the bytes are stored in reverse order in memory. So in memory, the sequence starts with f9, then df, then da, etc.

Then the decoding loop:

movzbl -0x13(%rbp,%rax,1),%eax   ; Load encoded byte[i]
xor    $0xffffffaa,%eax            ; XOR with 0xAA
mov    %dl,(%rax)                  ; Store decoded byte to output buffer

Enter fullscreen mode Exit fullscreen mode

The algorithm in plain English:

For each byte in the encoded array, XOR it with 0xAA. The result is the decoded password character.

Performing the XOR manually:

Index Encoded (hex) XOR 0xAA Decoded (ASCII)
0 0xF9 0xF9 ^ 0xAA 0x53 = S
1 0xDF 0xDF ^ 0xAA 0x75 = u
2 0xDA 0xDA ^ 0xAA 0x70 = p
3 0xCF 0xCF ^ 0xAA 0x65 = e
4 0xD8 0xD8 ^ 0xAA 0x72 = r
5 0xF9 0xF9 ^ 0xAA 0x53 = S
6 0xCF 0xCF ^ 0xAA 0x65 = e
7 0xC9 0xC9 ^ 0xAA 0x63 = c
8 0xDF 0xDF ^ 0xAA 0x75 = u
9 0xD8 0xD8 ^ 0xAA 0x72 = r
10 0xCF 0xCF ^ 0xAA 0x65 = e

Decoded password: SuperSecure

💡 Why XOR? XOR is the most common obfuscation technique in malware and CTF challenges because it is:

  • Reversible: XOR is its own inverse. A XOR key = B and B XOR key = A
  • Simple to implement: One assembly instruction
  • Easily broken: If you know the key (or can find it in the binary), it provides zero cryptographic security

3.4 Confirming the Authentication Flow in main

objdump -d --no-show-raw-insn bypassme.bin | grep -A 120 '<main>'

Enter fullscreen mode Exit fullscreen mode

This confirmed the exact execution path:

main:
  1. decode_password() → decoded password stored at rbp-0x110
  2. intro_sequence()  → shows the banner/animation
  3. fgets()           → reads user input into rbp-0x210
  4. sanitize()        → cleans user input
  5. strcmp(user_input, decoded_password) at 0x1759
  6. If equal → auth_sequence() → fopen("flag") → print flag
  7. If not equal → "Wrong password" → loop back (max 3 tries)

Enter fullscreen mode Exit fullscreen mode

The road not taken — Dynamic Debugging with LLDB:

The challenge hint specifically mentioned LLDB (a debugger). Here's how we would have used it if static analysis had failed:

# We would have set a breakpoint at the strcmp call address
lldb bypassme.bin
(lldb) b *0x1759          # Break at strcmp
(lldb) run
(lldb) x/s $rsi           # Read the decoded password from the rsi register

Enter fullscreen mode Exit fullscreen mode

In x86-64 Linux calling convention:

  • rdi = first argument to strcmp (user input)
  • rsi = second argument to strcmp (decoded password)

We chose not to use LLDB because static analysis gave us a complete answer with less complexity. Dynamic debugging introduces additional challenges (ASLR, needing to interact with the program, etc.). Always exhaust static analysis before resorting to dynamic analysis.


3.5 Obtaining the Flag

With the password SuperSecure recovered, we ran the binary and entered it:

./bypassme.bin
# At the prompt: SuperSecure

Enter fullscreen mode Exit fullscreen mode

The binary authenticated successfully, opened the flag file via fopen, and printed the flag.


4. "Privilege Escalation" — The SUID Mechanism

In this challenge, there was no traditional privilege escalation step because the SUID binary is the privilege escalation mechanism. Here's how it works:

┌─────────────────────────────────────────────────────┐
│  ctf-player (low privilege user)                    │
│  → runs bypassme.bin                               │
│  → OS sees SUID bit + owner = root                 │
│  → process runs as root                            │
│  → fopen("/path/to/flag") succeeds                 │
│  → flag contents printed to our terminal           │
└─────────────────────────────────────────────────────┘

Enter fullscreen mode Exit fullscreen mode

The flag file is readable only by root. Without the SUID binary, we could never access it. The binary acts as a controlled gateway — but since we bypassed the authentication check, we walked right through it.


5. Lessons Learned & Mitigation

5.1 Key Takeaways for Attackers (CTF Players)

Lesson Detail
Read symbols first nm and objdump reveal the entire structure of a binary in seconds
Not stripped = gift Debug symbols make reverse engineering dramatically faster
XOR is not encryption Single-byte XOR obfuscation is defeated trivially once the key is in the binary
Static before dynamic Exhaust static analysis before firing up a debugger
SUID = read the flag SUID root binaries are the key that unlocks root-owned files
Follow the strcmp In authentication binaries, find the comparison function and read its arguments

5.2 Mitigation Strategies for Defenders (Blue Team)

Vulnerability 1: Trivial XOR Obfuscation

What the developer did: Stored a password encoded with a single-byte XOR key (0xAA) — both the encoded bytes and the key are in the binary.

What should be done instead:

  • Never store passwords in a binary at all, even obfuscated
  • Use challenge-response authentication where the password never leaves the server
  • If a local comparison is unavoidable, use a proper cryptographic hash (bcrypt, Argon2) — an attacker who recovers a hash cannot reverse it
  • Use remote authentication — have the binary send the input to a server for verification; the "correct answer" never exists locally

Vulnerability 2: Binary Not Stripped / Debug Info Present

What the developer did: Compiled and deployed the binary with full debug symbols and without stripping.

What should be done instead:

  • Always strip production binaries: strip --strip-all bypassme.bin
  • Remove debug info at compile time (avoid -g flag in gcc/g++)
  • Use obfuscation tools like LLVM-Obfuscator for additional protection (note: this raises the bar, it doesn't solve the fundamental problem)

Detection (Blue Team Monitoring):

Alert: Process bypassme.bin executed by user ctf-player
  → Running with effective UID 0 (root)
  → Opened file: /root/flag.txt
  → This access pattern is anomalous for this user

Enter fullscreen mode Exit fullscreen mode

A proper SIEM or EDR (like Wazuh, Falco, or CrowdStrike) would flag a low-privilege user triggering a SUID binary that subsequently reads sensitive root-owned files.


Appendix: Full Attack Chain Summary

1. SSH into target
        ↓
2. ls -la → Discover SUID binary bypassme.bin
        ↓
3. file bypassme.bin → 64-bit ELF, not stripped, debug_info present
        ↓
4. nm bypassme.bin → Discover decode_password(), strcmp usage
        ↓
5. objdump disassembly of decode_password()
        ↓
6. Extract encoded bytes: f9 df da cf d8 f9 cf c9 df d8 cf
        ↓
7. XOR each byte with 0xAA → "SuperSecure"
        ↓
8. Run binary → Enter "SuperSecure" → FLAG OBTAINED

Enter fullscreen mode Exit fullscreen mode

Total tools used: ssh, ls, file, nm, objdump
No exploits. No brute force. No debugger needed.
Pure static analysis.


🎓 Final Thought for Beginners: This challenge perfectly illustrates why security-through-obscurity fails. The developer thought they were hiding the password by encoding it. But encoding is not encrypting. The moment we could read the binary's assembly, the "hidden" password was completely visible. Real security means an attacker can have full access to your code and still cannot compromise your system. That's the standard to aim for.