Skip to content

Utils

encode(data)

Encode data to bytes if it is not already.

Parameters:

Name Type Description Default
data

The data to encode (str, int, or bytes).

required

Returns:

Name Type Description
bytes

The encoded data.

Source code in src/pwninit/helpers/utils.py
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
def encode(data):
    """
    Encode data to bytes if it is not already.

    Args:
        data: The data to encode (str, int, or bytes).

    Returns:
        bytes: The encoded data.
    """
    if isinstance(data, int):
        data = str(data).encode()
    elif isinstance(data, str):
        data = data.encode()
    return data

getb(d, a, b)

Extract a substring between two delimiters.

Parameters:

Name Type Description Default
d bytes or str

The data to search in.

required
a bytes or str

The start delimiter.

required
b bytes or str

The end delimiter.

required

Returns:

Type Description

bytes or str: The substring between a and b.

Source code in src/pwninit/helpers/utils.py
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
def getb(d, a, b):
    """
    Extract a substring between two delimiters.

    Args:
        d (bytes or str): The data to search in.
        a (bytes or str): The start delimiter.
        b (bytes or str): The end delimiter.

    Returns:
        bytes or str: The substring between `a` and `b`.
    """
    a_ = d.find(a)
    if a_ == -1 or len(a) == 0:
        a_ = 0
    b_ = d.find(b, a_ + len(a))
    if b_ == -1 or len(b) == 0:
        b_ = len(d)
    return d[a_ + len(a) : b_]

getr(d, p)

Extract the first match of a regex pattern from the data.

Parameters:

Name Type Description Default
d bytes or str

The data to search in.

required
p str

The regex pattern.

required

Returns:

Type Description

bytes or str: The first match of the pattern.

Source code in src/pwninit/helpers/utils.py
234
235
236
237
238
239
240
241
242
243
244
245
def getr(d, p):
    """
    Extract the first match of a regex pattern from the data.

    Args:
        d (bytes or str): The data to search in.
        p (str): The regex pattern.

    Returns:
        bytes or str: The first match of the pattern.
    """
    return re.findall(p, d)[0]

hexdump(data, s=context.word_size // 8)

Print a hexdump of the specified data.

Parameters:

Name Type Description Default
data bytes

The data to dump.

required
s int

The size of each chunk in bytes.

word_size // 8
Source code in src/pwninit/helpers/utils.py
281
282
283
284
285
286
287
288
289
290
291
def hexdump(data, s=context.word_size // 8):
    """
    Print a hexdump of the specified data.

    Args:
        data (bytes): The data to dump.
        s (int): The size of each chunk in bytes.
    """
    idx_max = math.ceil(math.log(len(data), 16))
    for i in range(0, len(data), s):
        log.info(f"%0{idx_max}x: %#0{2 * s + 2}x" % (i, u64(data[i : i + s])))

jitspray(code, size=8, jmp=b'\xeb\x03')

Perform a jitspray with movabs on x64 by default.

Parameters:

Name Type Description Default
code str

Assembler code

required
size int

Maximum code part size (default 8 for movabs)

8
jmp bytes

Stub for jumping between code parts

b'\xeb\x03'
Source code in src/pwninit/helpers/utils.py
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
def jitspray(code, size=8, jmp=b"\xeb\x03"):
    """
    Perform a jitspray with movabs on x64 by default.

    Arguments:
        code(str):  Assembler code
        size(int):  Maximum code part size (default 8 for movabs)
        jmp(bytes): Stub for jumping between code parts
    """
    code = [asm(c) for c in code.splitlines()]
    size -= len(jmp)
    parts = [b""]
    for c in code:
        if len(c) > size:
            log.error(
                f"jitspray(): code part {c.hex()} too long for maximum size {size}"
            )
        p = parts[-1]
        if len(p) + len(c) > size:
            parts[-1] = p.ljust(size, b"\x90") + jmp
            parts.append(c)
        else:
            parts[-1] += c
    return [u64(p) for p in parts]

printx(**kwargs)

Print hex values for the specified keyword arguments.

Parameters:

Name Type Description Default
**kwargs

Key-value pairs to print.

{}

Example:

>>> printx(test=0x0)
[+] test: 0x0
Source code in src/pwninit/helpers/utils.py
265
266
267
268
269
270
271
272
273
274
275
276
277
278
def printx(**kwargs):
    """
    Print hex values for the specified keyword arguments.

    Args:
        **kwargs: Key-value pairs to print.

    Example:

        >>> printx(test=0x0)
        [+] test: 0x0
    """
    for k, v in kwargs.items():
        log.success("%s: %#x" % (k, v))

Compute the cookie value used to mangle/demangle a pointer.

Parameters:

Name Type Description Default
mangled int

The mangled pointer.

required
demangled int

The demangled pointer.

required

Returns:

Name Type Description
int

The cookie value.

Source code in src/pwninit/helpers/utils.py
336
337
338
339
340
341
342
343
344
345
346
347
def ptr_cookie(mangled, demangled):
    """
    Compute the cookie value used to mangle/demangle a pointer.

    Args:
        mangled (int): The mangled pointer.
        demangled (int): The demangled pointer.

    Returns:
        int: The cookie value.
    """
    return ptr_demangle(mangled, demangled)

ptr_demangle(addr, cookie=0)

Demangle a pointer with a cookie value.

Parameters:

Name Type Description Default
addr int

The address to demangle.

required
cookie int

The cookie value.

0

Returns:

Name Type Description
int

The demangled pointer.

Source code in src/pwninit/helpers/utils.py
322
323
324
325
326
327
328
329
330
331
332
333
def ptr_demangle(addr, cookie=0):
    """
    Demangle a pointer with a cookie value.

    Args:
        addr (int): The address to demangle.
        cookie (int): The cookie value.

    Returns:
        int: The demangled pointer.
    """
    return ror(addr, 17) ^ cookie

ptr_mangle(addr, cookie=0)

Mangle a pointer with a cookie value.

Parameters:

Name Type Description Default
addr int

The address to mangle.

required
cookie int

The cookie value.

0

Returns:

Name Type Description
int

The mangled pointer.

Source code in src/pwninit/helpers/utils.py
308
309
310
311
312
313
314
315
316
317
318
319
def ptr_mangle(addr, cookie=0):
    """
    Mangle a pointer with a cookie value.

    Args:
        addr (int): The address to mangle.
        cookie (int): The cookie value.

    Returns:
        int: The mangled pointer.
    """
    return rol(addr ^ cookie, 17)

Compute the safelink value for a pointer.

Parameters:

Name Type Description Default
addr int

The base address.

required
ptr int

The pointer value.

required

Returns:

Name Type Description
int

The safelinked value.

Source code in src/pwninit/helpers/utils.py
294
295
296
297
298
299
300
301
302
303
304
305
def safelink(addr, ptr):
    """
    Compute the safelink value for a pointer.

    Args:
        addr (int): The base address.
        ptr (int): The pointer value.

    Returns:
        int: The safelinked value.
    """
    return (addr >> 12) ^ ptr

Recover a safelinked next pointer assuming both next & addr are in the same page.

Parameters:

Name Type Description Default
ptr int

The next value

required
Source code in src/pwninit/helpers/utils.py
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
def safelink_bf64(ptr)->int:
    """
    Recover a safelinked next pointer assuming both next & addr are in the same page.

    Arguments:
        ptr(int): The next value
    """
    fd = 0
    for i in range(36, -1, -12):
        tmp = fd
        fd <<= 12
        fd |= (tmp ^ (ptr >> i)) & 0xFFF
    if fd & 0xF != 0:
        log.warn("safelink_bf64(): page differs")
    return fd

solve_hashcash(data)

Solve hashcash pow

Source code in src/pwninit/helpers/utils.py
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def solve_hashcash(data):
    """
    Solve hashcash pow
    """
    binary = _get_binary("hashcash")
    if binary is None:
        return None

    cmd = re.findall(rb"hashcash (-m.*?b\d+) ([0-9A-Za-z+/]+)", data)
    if len(cmd) == 0:
        log.error(f"Proof of work failed (hashcash): {data}")

    cmd = cmd[0]
    p = run([binary, cmd[0], cmd[1]], stdout=PIPE, stderr=DEVNULL)
    if p.returncode != 0:
        log.error(f"Proof of work failed (hashcash): {data}")

    return p.stdout

solve_hxp(data)

Solve hxp pow

Source code in src/pwninit/helpers/utils.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
def solve_hxp(data):
    """
    Solve hxp pow
    """
    binary = _get_binary("hxp")
    if binary is None:
        return None

    prefix = re.findall(rb"sha256\(unhex\(\"([0-9A-fa-f]+)\"", data)
    difficulty = re.findall(rb"ends with (\d+) zero", data)
    if len(prefix) == 0 or len(difficulty) == 0:
        log.error(f"Proof of work failed (hxp): {data}")

    prefix = prefix[0]
    difficulty = difficulty[0]
    p = run([binary, difficulty, prefix], stdout=PIPE, stderr=DEVNULL)
    if p.returncode != 0:
        log.error(f"Proof of work failed (hxp): {data}")

    return p.stdout

solve_kctf(data)

Solve kctf pow

Source code in src/pwninit/helpers/utils.py
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
def solve_kctf(data):
    """
    Solve kctf pow
    """
    binary = _get_binary("kctf")  # kctf & redpwn are actually the same
    if binary is None:
        return None

    arg = re.findall(rb"\) solve (.+)\n", data)
    print(arg)
    if len(arg) == 0:
        log.error(f"Proof of work failed (kctf): {data}")

    arg = arg[0]
    p = run([binary, arg], stdout=PIPE, stderr=DEVNULL)
    print(p)
    if p.returncode != 0:
        log.error(f"Proof of work failed (kctf): {data}")

    return p.stdout

solve_pow(data)

Take a buffer and detect the pow used and finally solve it using the solver set in config.

Parameters:

Name Type Description Default
data bytes

the buffer containing the pow to solve

required
Source code in src/pwninit/helpers/utils.py
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
def solve_pow(data: bytes):
    """
    Take a buffer and detect the pow used and finally solve it using the solver set in config.

    Args:
        data: the buffer containing the pow to solve
    """
    functions = {
        b"Please provide an ASCII printable": solve_sossette,
        b"give S such that sha256": solve_hxp,
        b"https://pwn.red/pow": solve_redpwn,
        b"please solve a pow first": solve_kctf,
        b"hashcash": solve_hashcash,
    }

    for s, f in functions.items():
        if s in data:
            return f(data).strip()

    log.warn(f"Unknown proof of work: {data}")

solve_redpwn(data)

Solve redpwn pow

Source code in src/pwninit/helpers/utils.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
def solve_redpwn(data):
    """
    Solve redpwn pow
    """
    binary = _get_binary("redpwn")
    if binary is None:
        return None

    arg = re.findall(rb"\| sh -s (.+)\n", data)
    if len(arg) == 0:
        log.error(f"Proof of work failed (redpwn): {data}")

    arg = arg[0]
    p = run([binary, "solve", arg], stdout=PIPE, stderr=DEVNULL)
    if p.returncode != 0:
        log.error(f"Proof of work failed (redpwn): {data}")

    return p.stdout

solve_sossette(data)

Solve sossette pow

Source code in src/pwninit/helpers/utils.py
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
def solve_sossette(data):
    """
    Solve sossette pow
    """
    binary = _get_binary("sossette")
    if binary is None:
        return None

    prefix = re.findall(rb"SHA256\(([0-9A-Za-z]+) ", data)
    difficulty = re.findall(rb"starts with (\d+) bits", data)
    if len(prefix) == 0 or len(difficulty) == 0:
        log.error(f"Proof of work failed (sossette): {data}")

    prefix = prefix[0]
    difficulty = difficulty[0]
    p = run([binary, prefix, difficulty], stdout=PIPE, stderr=DEVNULL)
    if p.returncode != 0:
        log.error(f"Proof of work failed (sossette): {data}")

    return p.stdout