picoCTF: Picker 1 Write-up

Picker 1 - PicoCTF | Jun “Sky” Lu

Picker 1 Challenge

Picker 1 Challenge

Overview:

The challenge requires you to analyze the python source code of the program and find a way to read the flag.txt file located in the same directory as the program. The instance provides the command to connect to the program via CLI and the source code file.

Initial Steps

Launch Instance

Note: The instance above is a different instance than in the write-up. In the write-up, the port 61353 was used instead.

Note: The instance above is a different instance than in the write-up. In the write-up, the port 61353 was used instead.

Upon launching the instance, the command to connect to the instance with netcat is provided. For this specific instance, the command is:

nc saturn.picoctf.net 61353

Upon connecting to the instance, the program displays the output “Try entering “getRandomNumber” without the double quotes…

image.png

Initially, I tried inputs such as getRandomNumber with and without quotes and other basic commands, but this method does not work.

After downloading and inspecting the python source code file “Picker-I.py”, there were two blocks of interest:


import sys

def getRandomNumber():
  print(4)  # Chosen by fair die roll.
            # Guaranteed to be random.
            # (See XKCD)

def exit():
  sys.exit(0)
  
def esoteric1():
  esoteric = \
  
def win():
  # This line will not work locally unless you create your own 'flag.txt' in
  #   the same directory as this script
  flag = open('flag.txt', 'r').read()
  #flag = flag[:-1]
  flag = flag.strip()
  str_flag = ''
  for c in flag:
    str_flag += str(hex(ord(c))) + ' '
  print(str_flag)
  
  
#Rest of the code here...
#

while(True):
  try:
    print('Try entering "getRandomNumber" without the double quotes...')
    user_input = input('==> ')
    eval(user_input + '()')
  except Exception as e:
    print(e)
    break

The key to solving this challenge is the program’s win() method and the input while loop. According to the python code, the win() method opens and reads the flag.txt file in the same directory, which should correctly display the flag.

def win():
  # This line will not work locally unless you create your own 'flag.txt' in
  #   the same directory as this script
  flag = open('flag.txt', 'r').read()
  #flag = flag[:-1]
  flag = flag.strip()
  str_flag = ''
  for c in flag:
    str_flag += str(hex(ord(c))) + ' '
  print(str_flag)
  
  
  
while(True):
  try:
    print('Try entering "getRandomNumber" without the double quotes...')
    user_input = input('==> ')
    eval(user_input + '()')
  except Exception as e:
    print(e)
    break

In the input while loop, the block is relatively straightforward. The user’s input is evaluated with the eval command, which reads a string and parses it as an expression. The user input is appended with parenthesis, meaning the input is taken as ‘string()’.

Source: https://www.geeksforgeeks.org/eval-in-python/

Exploitation:

Since the eval function interprets the user input as a python expression, the input, ‘win’, can be used to read the flag.txt file in the directory of the launched instance.

image.png

The contents of the flag.txt file was outputted. The file contains a cipher-text presumably of the flag which can be decoded using dcode.fr

Decrypt the Cipher and Obtain the Flag

image.png

image.png

After inserting the result into dcode.fr’s cipher identifier, the code turns out to be ASCII code. After using the ASCII code cipher decoder, the result was the flag.

Flag: picoCTF{4_d14m0nd_1n_7h3_r0ugh_6e04440d}