bridge of death

What is the air-speed velocity of an unladen swallow?

2 min read


Table of Contents

[ + ] Overview
[ + ] Reversing and Solution

[ + ]Overview

Taking a high-level look at the binary after running it we see we are prompted with a series of 5 questions ;).

Image

Lets dig deeper.

[ + ]Reversing and Solution

The idea for this challenge is that there are 3 questions to answer.

Image

To solve the first one, the following must return true:

Image

The solution to question1:

def q1():
    return b'My name is Sir Lancelot of Camelot.\n'

The call to the second question must return false, and the sub routine is split as follows:

Image Image

The idea here is to find two numbers such that the return value of the func2 call is equal to the second value.

As shown above, v5 is equal to 10 when initialized, and hitting the second if statement would return v5. So by passing 10 as the first value, we can ensure that 10 is returned from func2. Next we must make sure that both values are the same so the second value is also 10.

The solution to question2:

def q2():
    return b'10\n10\n'

For the third question, you have to pass two values at each iteration and make sure that forestOfEwing[(256 * val_1) + val_2] is equal to the index of the loop.

Image

To solve this, I exported the array and pickled it so that I didn't have to keep it hard coded in the file. Then looped from 1 to 9 and found where the loop index's value was stored in the list, then divided the index by 256 and taking the min, and subtracting that from the index of forestOfEwing list.

Image

The solution to question3:

def q3():
    res = b''
    # list of bytes from the binary
    with open('q3.pkl', 'rb') as f:
        q3_list = pickle.load(f)
    for i in range(1, 10):
        index = q3_list.index(bytes.fromhex(str(i).zfill(2)).decode('utf-8'))
        print(index)
        num1 = index // 256
        num2 = index % 256
        res += str(num1).encode('utf-8') + b'\n' + str(num2).encode('utf-8') + b'\n'
    return res
Image
 Solver
import pickle
from pwn import *
from pwnlib.util.packing import *
# Context
context.arch = 'amd64'
context.log_level = 'DEBUG'
# Main vars
NETID = ''
HOST, PORT = 'host', 8005

def q1():
    return b'My name is Sir Lancelot of Camelot.\n'
    
def q2():
    return b'10\n10\n'
    
def q3():
    res = b''
    # list of bytes from the binary
    with open('q3.pkl', 'rb') as f:
        q3_list = pickle.load(f)
    for i in range(1, 10):
        index = q3_list.index(bytes.fromhex(str(i).zfill(2)).decode('utf-8'))
        print(index)
        num1 = index // 256
        num2 = index % 256
        res += str(num1).encode('utf-8') + b'\n' + str(num2).encode('utf-8') + b'\n'
    return res

def pwn():
    conn = remote(HOST, PORT)
    conn.recvuntil(b'(something like abc123): ')
    conn.sendline(NETID)
    conn.recvuntil(b'What is your name?')
    conn.send(q1())
    conn.recvuntil(b'What is your quest?')
    conn.send(q2())
    conn.recvuntil(b'What is the air-speed velocity of an unladen swallow?')
    conn.send(q3())
    conn.recvuntil(b'flag{')
    response = conn.recvline()
    conn.close()
    print("flag{" + response.decode().strip())
    
if __name__ == "__main__":
    pwn()