えびちゃんの日記

えびちゃん(競プロ)の日記です。

Writeup for destructuring, Daily AlpacaHack 2026/2/11

Daily AlpacaHack 2026/2/11 の write-up です。

alpacahack.com

最初は下記のようなコードで解きました。

solve.py

import re

from pwn import *


def nc(nc_comm):
    nc_argv0, host, port = nc_comm.split()
    return remote(host, int(port))


p = nc("nc 34.170.146.252 25646")


def prettify(j):
    j = j.replace("[,", "[0,")
    j = j.replace(", ,", ", 0,")
    j = j.replace(", ,", ", 0,")
    j = j.replace(", ]", ", 0]")
    j = j.replace("_", "")
    return re.sub(r"([a-z])", r'"\1"', j).strip()


for _ in range(5):
    p.recvuntil(b"Stage: ")
    _ = p.recvline()
    line = p.recvline().decode().strip()
    j = re.fullmatch(r"const (.+) = json;", line).group(1)
    j = prettify(j)
    p.sendlineafter(b"json> ", j.encode())

.replace(", ,", ", 0,") を単に 1 回だけ使うと [1, , , , 2] のような入力を [1, 0, , 0, 2] にしてしまい、うまくいきません(置換の範囲が overlap してしまうため)。 2 回行えばうまくいくのがちょっと面白いなと思いました。正規表現でがちゃがちゃやるのも考えたのですが、あんまり頭を使いたくなかったので。 入力において空白がぐちゃぐちゃになったりしておらず、優しいなと思いました。

一度解いてしばらくしてから、次の解法に思い至りました。そもそも JavaScript では {a: [, , { b: _0, c: [{ d: _1 }] }] } のようなパターンを書けるという前提が教えられているわけで、餅は餅屋、JavaScriptJavaScript 屋です。

// Welcome to Node.js v24.13.0.
// Type ".help" for more information.
> {a: [, , { b: 0, c: [{ d: 1 }] }] }
{ a: [ <2 empty items>, { b: 0, c: [Array] } ] }
> JSON.stringify({a: [, , { b: 0, c: [{ d: 1 }] }] })
'{"a":[null,null,{"b":0,"c":[{"d":1}]}]}'

ということで、node に食わせればそのまま整形までやってくれそうです。

solve.py

import re
from subprocess import PIPE, Popen

from pwn import *


def nc(nc_comm):
    nc_argv0, host, port = nc_comm.split()
    return remote(host, int(port))


p = nc("nc 34.170.146.252 25646")


def prettify(j):
    p = Popen(["node"], stdin=PIPE, stdout=PIPE)
    j = j.replace("_", "").strip()
    stdout, _ = p.communicate(f"console.log(JSON.stringify({j}));".encode())
    return stdout.decode()


for _ in range(5):
    p.recvuntil(b"Stage: ")
    _ = p.recvline()
    line = p.recvline().decode().strip()
    j = re.fullmatch(r"const (.+) = json;", line).group(1)
    j = prettify(j)
    p.sendlineafter(b"json> ", j.encode())

p.recvuntil(b"Here's your flag: ")
print(p.recvline().decode())

以上です。Alpaca{the_notation_is_pretty_intuitive_IMO} 👏