Binary Instrumentation 4 picoCTF 2026 Solution

Published: March 20, 2026

Description

The executable was designed to send the flag to someone. Are you that someone? Download the binary bin-ins4.zip (password: picoctf).

Download and extract bin-ins4.zip using the password 'picoctf'.

Run the binary and observe its network behaviour.

bash
unzip -P picoctf bin-ins4.zip
bash
chmod +x bin-ins4
  1. Step 1Observe the binary's network behaviour
    Confirm the binary actually attempts a connection (netstat / Wireshark), then sweep WinSock exports broadly with frida-trace. Don't assume send() is the API: WSASend, sendto, and SSL_write are common alternates. See Frida for binary instrumentation.
    bash
    unzip -P picoctf bin-ins4.zip
    bash
    # Confirm a connection is actually attempted before blaming the hook:
    bash
    netstat -an | grep -i syn_sent || ss -tn
    bash
    # Sweep all WinSock send-family exports plus connect:
    bash
    frida-trace ./bin-ins4 -i 'ws2_32!s*' -i 'connect' -i 'WSASend' -i 'SSL_write'
    Learn more

    The Windows Sockets 2 (WS2_32.dll) library provides the standard socket API on Windows. The send() function transmits data from a buffer to a connected socket. Its prototype is int send(SOCKET s, const char *buf, int len, int flags) - so the second argument is a pointer to the data and the third is the length in bytes.

    frida-trace is a command-line utility that generates skeleton Frida hooks for every function matching the specified pattern (-i) and logs calls automatically. It is the fastest way to discover which network functions a binary uses without reading disassembly - useful when you don't yet know whether a binary uses send, WSASend, sendto, or a higher-level HTTP library.

    In malware analysis, intercepting outbound network calls is critical for capturing C2 (command and control) traffic before it leaves the host. The same Frida technique used here is employed by malware researchers to extract encryption keys, decode payloads, and map protocol structures - all without needing to reverse the full binary.

  2. Step 2Hook WS2_32.dll send() with Frida to capture the flag
    Write a Frida script that hooks the send() export from WS2_32.dll. When the binary calls send() with the flag data, intercept the buffer argument and print its contents to the console.
    js
    cat > intercept.js << 'EOF'
    // Hook WS2_32.dll send() to intercept the flag before transmission
    const send = Module.getExportByName("WS2_32.dll", "send");
    
    Interceptor.attach(send, {
        onEnter(args) {
            // args[1] = buf (pointer in target's address space), args[2] = len
            const len = args[2].toInt32();
            // Bounds-check the length: Frida will crash if you ask it to read
            // gigabytes from a stale pointer.
            if (len > 0 && len < 10000) {
                const data = args[1].readByteArray(len);
                const str = new TextDecoder().decode(new Uint8Array(data));
                console.log("Intercepted send() data:", str);
            }
        }
    });
    EOF
    bash
    frida -l intercept.js ./bin-ins4
    Learn more

    The Frida NativePointer.readByteArray(n) method reads exactly n bytes from the pointed-to address and returns them as an ArrayBuffer. Combined with TextDecoder, you can convert raw bytes to a human-readable string. This is more reliable than readUtf8String() when the data might not be null-terminated or might contain non-UTF8 bytes.

    args[1] is a pointer in the target process's address space, not in the Frida agent's. NativePointer.readByteArray(n) dereferences it on read, so the value comes back as a regular ArrayBuffer the JS side can read. Bounds-checking len matters: if a stray call passes a corrupt size value, an unbounded read can crash the target.

    The key to this approach is that Frida runs your hook in-process - your JavaScript code has the same memory access as the binary itself. The flag buffer at args[1] is a real pointer into the process's virtual address space, and reading it gives you the plaintext data before it is encrypted by any TLS layer applied at the OS socket level.

    This is why SSL/TLS interception at the application layer is more reliable than MITM proxying: a Frida hook on SSL_write or the platform's secure channel functions reads data before encryption, bypassing certificate pinning entirely. Major mobile security research tools (like Objection) use this approach to defeat SSL pinning on iOS and Android apps.

  3. Step 3Read the flag from the Frida output
    The Frida console will print the flag when the binary calls send() with the flag buffer.
    Learn more

    Once Frida's hook fires, the flag appears in the console without the binary ever successfully connecting to the remote server. This demonstrates a core advantage of in-process hooking over network-level interception: you see the data regardless of whether the network connection succeeds, even if the remote server is offline or unreachable.

    An alternative to Frida for this class of challenge is running the binary under Wireshark or tcpdump with a local listener (nc -lp PORT) configured to receive the connection - if the binary connects to a hardcoded IP, you can redirect it with /etc/hosts or firewall rules, and then capture the flag from the TCP stream. However, Frida is simpler because it does not require network reachability at all.

    The broader skill here is data flow tracing: following how sensitive data (a flag, a password, an encryption key) moves through a program from its origin in memory to its eventual destination. This is a foundational technique in both CTF reversing and real-world malware analysis.

Flag

picoCTF{b1n_1nstrum3nt4t10n_4_...}

The binary uses WS2_32.dll's send() to transmit the flag over the network. A Frida script hooking this export captures the data in-transit before it leaves the process.

Want more picoCTF 2026 writeups?

Useful tools for Reverse Engineering

Related reading

What to try next