dora
Swiper, no swiping!
2 min read
[ + ]Overview
Playing around with the binary we are prompted for a key, and if that key is wrong, we get a segfault
.
Lets take a deeper look.
[ + ]Reversing
From a high-level, and looking at the psuedo code, this challenge looks fairly innocuous. It is not until you look at the instructions themselves that you get the full picture.
It seems like some number is read, then something is XOR'd, then a call is made. In IDA, this pseudo code is symptomatic of weird calls being make.
Taking a look at the assembly, the idea behind this challenge is that the bytes at a memory address are XOR'd by the value provided, then the memory location is called using call rdx
(highlighted in red). To solve, you need to find the right value to be able to have working code at that memory location when call rdx
happens.
[ + ]Solution
My solution was kind of un-orthodox, but worked. I figured there is no reference to any other memory addresses, flag.txt
, or imports, so the values being XOR'd must actually open and read the flag.txt
file. By that logic, I simply brute forced it:
def solve():
ida_chars = bytes([
0x97, 0x46, 0x23, 0x34, 0x4D, 0x8A, 0xC4, 0x7E, 0x7C, 0x7C,
0x7C, 0x73, 0x79, 0x97, 0x47, 0x22, 0x34, 0xF5, 0xBB, 0xC6,
0x83, 0x7C, 0x7C, 0x7C, 0xC4, 0x7C, 0x7C, 0x7C, 0x7C, 0x73,
0x79, 0xC3, 0x7D, 0x7C, 0x7C, 0x7C, 0xC6, 0x83, 0x7C, 0x7C,
0x7C, 0xC4, 0x7D, 0x7C, 0x7C, 0x7C, 0x73, 0x79, 0xC3, 0x7C,
0x7C, 0x7C, 0x7C, 0xC4, 0x40, 0x7C, 0x7C, 0x7C, 0x73, 0x79,
0x94, 0xBD, 0x83, 0x83, 0x83, 0x1A, 0x10, 0x1D, 0x1B, 0x52,
0x08, 0x04, 0x08, 0x7C, 0x94, 0xBC
])
for i in range(256):
flag = bytes(x ^ i for x in ida_chars)
if b"flag" in flag:
print(i)
return i
return -1
I was able to verify that this is correct by debugging after the XOR:
As shown, there are syscalls happening to open and read flag.txt
.
Solver
import sys
from pwn import *
from pwnlib.util.packing import *
# Context
context.arch = 'amd64'
context.log_level = 'DEBUG'
# Main vars
NETID = ''
HOST, PORT = 'host', 1250
def solve():
ida_chars = bytes([
0x97, 0x46, 0x23, 0x34, 0x4D, 0x8A, 0xC4, 0x7E, 0x7C, 0x7C,
0x7C, 0x73, 0x79, 0x97, 0x47, 0x22, 0x34, 0xF5, 0xBB, 0xC6,
0x83, 0x7C, 0x7C, 0x7C, 0xC4, 0x7C, 0x7C, 0x7C, 0x7C, 0x73,
0x79, 0xC3, 0x7D, 0x7C, 0x7C, 0x7C, 0xC6, 0x83, 0x7C, 0x7C,
0x7C, 0xC4, 0x7D, 0x7C, 0x7C, 0x7C, 0x73, 0x79, 0xC3, 0x7C,
0x7C, 0x7C, 0x7C, 0xC4, 0x40, 0x7C, 0x7C, 0x7C, 0x73, 0x79,
0x94, 0xBD, 0x83, 0x83, 0x83, 0x1A, 0x10, 0x1D, 0x1B, 0x52,
0x08, 0x04, 0x08, 0x7C, 0x94, 0xBC
])
for i in range(256):
flag = bytes(x ^ i for x in ida_chars)
if b"flag" in flag:
print(i)
return i
return -1
def pwn():
conn = remote(HOST, PORT)
conn.recvuntil(b'(something like abc123): ')
conn.sendline(NETID)
conn.recvuntil(b'What\'s the key?')
sol = solve()
if sol == -1:
print("No solution found")
sys.exit(1)
conn.sendline(f"{sol}")
conn.recvuntil(b'flag{')
response = conn.recvline()
conn.close()
print("flag{" + response.decode().strip())
if __name__ == "__main__":
pwn()