Solutions



WINNER SOLUTIONS

CTF Winner, John Koerner, put together a breakdown on how to solve the challenges on his site.   https://johnkoerner.com/codemash/codemash-ctf-breakdown


Players hosted solutions

  • https://github.com/lnxdork/For_CTFs
  • If you host a site where you are writing up how you solved the challenges, send me a link to be placed here.  Otherwise individual player submitted solutions are inline below.

Below are the walkthroughs for the challenges.  Use this information to help you understand and learn from.  A few of the challenges have alternate ways to solve provided by players of the CTF.

CHALLENGE #1

  • HINT:

    • Well do you like his style(.css)?  Just keep scrolling….
  • SOLVE:

    • The style.css file is indirectly referenced in the “js/init.js” script.  open css/style.css and scroll to the bottom for the flag.

 

CHALLENGE #2

  • HINT:

    • The link doesn’t take you directly to C-3PO’s wiki – it does some computation ./bots/bots.html – understand that and follow the breadcrumb trail
    • Either change your user-agent or manually navigate
    • Pay attention to the meta data
  • SOLVE:  

    • link directs you to bots/bots.html > view source on that page: view-source:https://codemash.hacking-lab.com/codemash/bots/bots.html
    • The obfuscated code informs you that if your UserAgent is set to HoboRobo stay on page, otherwise redirect to C3PO wiki.
      • copy unicode to https://r12a.github.io/apps/conversion/ and select Dec code)
      • HINT FROM PLAYER: Open Chrome Dev Tools with F12 and deobfuscate code with String.fromCharCode(enter code)
    • Current page displays 
    • coded message is Robot Interactive Language – translate with http://roila.org/language-guide/vocabulary/
    • message tells you to navigate to https://codemash.hacking-lab.com/codemash/bots/four.html which redirects you to the C3PO wiki again depending on UserAgent, otherwise opens another image with a message META
    • What is important on the four.html page is the meta tag: <meta name=”descriptioncontent=”Robots talk in ROILA language: eman egap eht esrever tsum“>  which is telling you to reverse the page name
    • view-source:https://codemash.hacking-lab.com/codemash/bots/ruof.html will also redirect you to C3PO, so view source and find the link to the final picture 
  • ALTERNATE SOLUTION FROM PLAYER

  • ALTERNATE SOLUTION FROM PLAYER

    • This one I used postman to see the html of the page which had an image.
    • When I pulled up the image I couldn’t understand the text so I googled it which eventually lead me to http://roila.org/language-guide/vocabulary/
    • Translated text
    • I got to another image and eventually found a hint in a meta tag that the answer wasn’t four but four backwards.
  • ALTERNATE SOLUTION FROM PLAYER

    • This one had quite a few layers. The main link takes you to a Wikipedia page, but I figured the flag wasn’t there so I inspected the link found this: bots/bots.html
    • I slowed down my connection with chrome dev tools and stopped the bots page before it could redirect. That produced some encoded JS.
    • I decoded the JS and determined that it was redirecting if the “useragent != HoboRobo”
    • After some googling to learn about what a user agent is, I learned that I could modify my user agent in Chrome Dev tools. Doing that led to another page with an image that had what appeared to be gibberish.
    • Googling the text revealed that it was ROILA and translated to something like: “you must make word of addition two and two – this be name of page”. After a few minutes of fumbling around, I determined that I needed to edit the URL to be “/four.html”
    • This led to another image that looked like the word “METAE”. Which caused me to look at the <meta> tags in the page source. This yielded the following text:” eman egap eht esrever tsum”. Initially I thought that it was more ROILA, but a goggle search revealed that it was not. Backwards it reads “must reverse the page name”, so now we enter “/ruof.html” which yields the flag.

 

CHALLENGE #3

  • HINT:

    • BEST in leet speak = 8357
    • The #< or #> is how many numbers correct from the left and if the next number provided is greater or less than the actual.
  • SOLVE:

    • netcat to port 8357 (“BEST” in leet letters)
    • Bot expects a 20 digit number
    • it returns the number of correctly guessed numbers (from the left), and a “<” or “>” indicating if the next number is smaller or bigger
    • 78025928232920712967
  • ALTERNATE SOLUTION FROM PLAYER:

    • Run the following python script:
    • #!/usr/bin/env python3
      import sys
      import telnetlib
      import timedef test(password):
      tn = telnetlib.Telnet(‘codemash.hacking-lab.com’, 8357)
      # tn.set_debuglevel(1)
      # time.sleep(1)
      tn.read_until(b”dude:”)
      tn.write(password.encode(‘ascii’) + b”\n”)
      tn.read_until(b”\n”)
      out = tn.read_all().decode(‘ascii’)
      tn.close()
      return outhalfpassword =””
      #halfpassword =”78″
      for x in range((1+len(halfpassword)), 21):
      for i in range(0, 10):
      testpass = (halfpassword + str(i)).ljust(20, ‘0’)
      print(testpass)
      out=test(testpass)
      try:
      if (int(out.split(“<“)[0])>=x):
      halfpassword = halfpassword + str(i)
      break
      except:
      exit(out)
  • ALTERNATE SOLUTION FROM PLAYER

    • The hint on this one revealed that it was a network related, and one of the tweets suggested using netcat. I had never used netcat, so I spent a significant amount of time googling documentation and syntax. b. I used https://www.site24x7.com/find-ip-address-of-web-site.html to get the IP.
    • At first, I didn’t understand the hint about the “BEST” port on the server, so I started scanning all the ports with netcat, which was taking a really long time. Then I thought about it some more and realized that the 1337 Riddler would use 1337 Speak. So I translated the word BEST to 8357 with https://qntm.org/l33t
    • Using that port, I reached out to the server with netcat. The Riddler responded with “Make an educated guess dude”. My first guess returned “I need 20 digits dude”.
    • So I did 20 “1s” then 20 “2s” etc. When I got to 7 the response was “>1”. So I made a sheet in notepad++ and manually went through the next 19 digits using alt+drag to edit more than one row at a time. (This took a really long time, but I am not so good with scripting. . . )

 

CHALLENGE #4

  • HINT:

    • Play with the levels of the picture
  • SOLVE:

    • Download the picture
    • Open the picture in a tool like GIMP or PAINT.NET
    • alternately upload picture to https://www168.lunapic.com/editor/?action=newbright
    • Adjust the levels > Adjust the input histogram level all the way down

 

CHALLENGE #5

  • HINT:

    • Create a QR code
  • SOLVE:

    • Add a comma between every character in each txt file,
    • Save the files as csv format and open them in excel
    • Use the corresponding excel functions, as described in the challenge, comparing it in the matrix format.
    • At the end, change all the 1 cells to black and all the 0 cells to white
    • Scan QR code that is formed with cell phone scanner
  • ALTERNATE SOLUTION FROM PLAYER:

    • Run python script  (Python Imaging Library dependency)
    • #!/usr/bin/env pythona=0b0111011001000100111111111010001110100110110111010000011000000001111001100010110101111110010001101011111001101110011000110001100011001010010001001001100101111010101100010000110001100010111010010010111011100000010100101000100100110001010001110111101110000001011101000000110000100101101111000011001011101011110100111010011110101111101110100000111100100101010100011100011010111010100100001110010011101110100110111011000101011011101001110110100111111110100001111101101011101010110111101110000111100001110100001110001011100010000000001110101101000101110000001110001001100110110001101000101000001110011011100110011001101010110110100
      b=0b0111001001110010010100010100111001111011010110001011011000011010111101100100010001100101000100010001010000001101000100010110100101101101111010011000011111110011001010101011101100011011110010011110111000110010000011101110110001111011110110100110001001100101010101010000001101001010010100100100000111101111111111101111010100100000100111000100111101111001010001000111000011010011011001101010010110001100000000100011111100000100101010010010110010111111111001100100010111001001100111001110010111000011111010110011001101110011000000101111111101110011101000010111101101000101100111101000001101101100111100111110101010011110110101110
      c=0b1001010011101000010001000010010100001011001000000000000110000100000000110100100101001010000000010100000000000010000000110100110000001100000000100001000010000000000000000000100100011111100001001000100001000010010100100001010000000011000000101011000000000010000000000000110000000000000010010000010110100010000010000010101000000100100000010001001000000010110000010100000000000010011111100010001001000000100001110100001000000000110101100000000000000001000001000011000000000000011100110010000001100000100000000000000011000101000100101101000000100000001010010100101000000010001100000010100000000100110001000010000100100000000011101
      d=0b0110101011011100011110111010110000101010101100001101111100111110101110001111111000000010010101001001101110101101110110011000000100111000110000100001000101111011101000000100010100011110111000111100100010000001010000100100111101110101111101101100101000100100101001100011101001101100111101001111111000001011010011110010010101010110110011111111010101110100100011110010101001101001111101111000111101101001011110000110001111111110010111100100000101000100000110111000101011101010100000110110110100110011110000001011010100111010100001110000000110011010111010111011001110111111000010110010110011011100011101010101011100010101100011000from PIL import Image
      import mathf=(bin((((~a)&b)|c)^d))bitarray=(f).strip(‘0b’)
      bitcount=len(bitarray)
      size=int(math.sqrt(bitcount))outbytes= b”
      for bit in range(0,bitcount):
      if bitarray[bit]==”1″:
      outbytes += b’\x00′
      else:
      outbytes += b’\xFF’

      img = Image.frombytes(‘L’, (int(size), int(size)), outbytes2)
      img=img.resize((size*8,size*8))
      img.save(“fimg-output.png”,”png”)

  • ALTERNATE FROM PLAYER:

    #!/usr/bin/env python
    import sys

    op = sys.argv[1]

    with open(sys.argv[2], ‘r’) as f:
    lines = f.read().splitlines()

    if op != “n”:
    with open(sys.argv[3], ‘r’) as f2:
    lines2 = f2.read().splitlines()

    for i in range(len(lines)):
    if op == “n”:
    o = “”
    for c in lines[i]:
    if c == “0”:
    o = o +”1″
    else:
    o = o + “0”
    print(o)
    elif op == “a”:
    o = “”
    for j in range(len(lines[i])):
    c = lines[i][j]
    c2 = lines2[i][j]
    if c == “1” and c2 == “1”:
    o = o + “1”
    else:
    o = o + “0”
    print(o)
    elif op == “o”:
    o = “”

    #        print(lines[i])
    #        print(lines2[i])

    for j in range(len(lines[i])):
    c = lines[i][j]
    c2 = lines2[i][j]

    #            print(“{}:{}”.format(c,c2))

    if c == “1” or c2 == “1”:
    o = o + “1”
    else:
    o = o + “0”
    print(o)

    elif op == “x”:
    o = “”

    for j in range(len(lines[i])):
    c = lines[i][j]
    c2 = lines2[i][j]

    if (c ==  c2):
    o = o + “1”
    else:
    o = o + “0”
    print(o)

    then just did each operation to a file.  On the end you could use sed and ANSI characters to output the QR in bash

  • ALTERNATE SOLUTION FROM PLAYER

    • a = open(“a.txt”)
      b = open(“b.txt”)
      c = open(“c.txt”)
      d = open(“d.txt”)data = []
      i = 0
      for line in a:
      j = 0
      data.append(list(line.strip()))
      for char in line:
      if char == “0”:
      data[i][j] = “1”
      elif char == “1”:
      data[i][j] = “0”
      j += 1
      i += 1
      i = 0
      for line in b:
      j = 0
      for char in line.strip():
      data[i][j] = str(int(data[i][j]) & int(char))
      j += 1
      i += 1
      i = 0
      for line in c:
      j = 0
      for char in line.strip():
      data[i][j] = str(int(data[i][j]) | int(char))
      j += 1
      i += 1
      i = 0
      for line in d:
      j = 0
      for char in line.strip():
      data[i][j] = str(int(data[i][j] != char))
      j += 1
      i += 1for line in data:
      print(“”)
      print(” “, end=”)
      for char in line:
      if char == “1”:
      print(u”\u2588″, end=”)
      print(u”\u2588″, end=”)
      else:
      print(” “, end=”)
  • ALTERNATE SOLUTION FROM PLAYER

    • There may be some error with my script, as I had to manually change a couple cells, in the corner squares, but I was able to get the code with this C# script that I ran from LinqPad.  For the Excel part, I used EPPlus.  The full paths to the files have been removed.There may be some error with my script, as I had to manually change a couple cells, in the corner squares, but I was able to get the code with this C# script that I ran from LinqPad.  For the Excel part, I used EPPlus.  The full paths to the files have been removed.
    • string[] sA = System.IO.File.ReadAllLines(@”a.txt”);
    • string[] sB = System.IO.File.ReadAllLines(@”b.txt”);
    • string[] sC = System.IO.File.ReadAllLines(@”c.txt”);
    • string[] sD = System.IO.File.ReadAllLines(@”d.txt”);
    • UInt64[] iA = new UInt64[sA.Length];
    • UInt64[] iB = new UInt64[sA.Length];
    • UInt64[] iC = new UInt64[sA.Length];
    • UInt64[] iD = new UInt64[sA.Length];
    • string[] cResult = new string[sA.Length];
    • for (int i = 0; i < iA.Length; i++)
    • {
    •     iA[i] = Convert.ToUInt64(sA[i]2);
    •     iB[i] = Convert.ToUInt64(sB[i]2);
    •     iC[i] = Convert.ToUInt64(sC[i]2);
    •     iD[i] = Convert.ToUInt64(sD[i]2);
    •     iA[i] = iA[i] ^ 0xFFFFFF;
    •     iA[i] = iA[i] & iB[i];
    •     iA[i] = iA[i] | iC[i];
    •     iA[i] = iA[i] ^ iD[i];
    •     cResult[i] += Convert.ToString(BitConverter.GetBytes(iA[i])[3]2).PadLeft(1‘0’);
    •     cResult[i] += Convert.ToString(BitConverter.GetBytes(iA[i])[2]2).PadLeft(8‘0’);
    •     cResult[i] += Convert.ToString(BitConverter.GetBytes(iA[i])[1]2).PadLeft(8‘0’);
    •     cResult[i] += Convert.ToString(BitConverter.GetBytes(iA[i])[0]2).PadLeft(8‘0’);
    • }
    • ExcelPackage package = new ExcelPackage();
    • var sheet = package.Workbook.Worksheets.Add(“1”);
    • for (int row = 0; row < cResult.Length; row++)
    • {
    •     for (int col = 0; col < cResult[row].Length; col++)
    •     {
    •             sheet.Cells[row + 1, col + 1].Style.Fill.PatternType = ExcelFillStyle.Solid;
    •         if (cResult[row][col] == ‘1’)
    •         {
    •             sheet.Cells[row + 1, col + 1].Style.Fill.BackgroundColor.SetColor(Color.Black);
    •         }
    •         else{
    •             sheet.Cells[row + 1, col + 1].Style.Fill.BackgroundColor.SetColor(Color.White);
    •         }
    •     }
    • }
    • var packageBytes = package.GetAsByteArray();
    • File.WriteAllBytes(@”qr.xlsx”, packageBytes);

CHALLENGE #6

SOLUTION:

ALTERNATE SOLUTION FROM PLAYER:

  • Run python script (python 2)
  • “363336643331333832643438363537373432326436383530333137323264346337393738333932643635373035343465”.decode(“hex”).decode(“hex”)

ALTERNATE SOLUTION FROM PLAYER:

  • Import the code into cells 4 char wide from A1 to X1 and use:
  • =CHAR(HEX2DEC(CONCATENATE(MID(A1,2,1),CHAR(HEX2DEC(RIGHT(A1,2))))))
  • (drag the function across the rest of the cells to complete)

ALTERNATE SOLUTION FROM PLAYER:

val actual = convertHexes(convertHexes(
  “363336643331333832643438363537373432326436383530333137323264346337393738333932643635373035343465”))
if (actual.matches(“cm18-.{4}-.{4}-.{4}-.{4}”)) {
  println(s”Success! $actual”)
} else {
  println(“Sorry no match”)
}
 
def convertHexes(hexes: String): String = {
  val hexDigits = hexes.toList
 
  def charToHexDigit(c: Char) = {
    “0123456789abcdef”.indexOf(c.toLower)
  }
 
  (hexDigits zip hexDigits.drop(1)).zipWithIndex
    .filter(_._2 % 2 == 0)
    .map(_._1)
    .map {
      case (a, b) => (charToHexDigit(a) * 16 + charToHexDigit(b)).toChar
    }
    .mkString
}

CHALLENGE #7

 

SOLUTION #8

  • SOLUTION

    • Decompile the java class
    • append `System.out.println(codeword);` to the end
    • Compile and run the java application
  • ALTERNATE SOLUTION FROM PLAYER:

    • from the class java file I was able to extract the java code which I then turned into C# and ran it and watched the variable to find the flag
    • class Program
      {
      public static void Main(String[] args)
      {
      string key = “lockpickingisfun”;
      string cipher = “?8hiyKT5fw*W^J~art3t.47i”;if (args.Length != 1)
      {
      Console.WriteLine(“Provide codeword to open the lock!”);
      return;
      }
      string input = args[0];
      StringBuilder codeword = new StringBuilder();
      for (int i = 0; i < cipher.Length; i++)
      {
      codeword.Append((char)(key[(i % key.Length)] – cipher[(i)] + 54));
      }
      if (codeword.ToString()==input)
      {
      Console.WriteLine(“Correct codeword! The Lock is open!”);
      }
      else
      {
      Console.WriteLine(“Wrong codeword!”);
      }
      }
      }

 

CHALLENGE #9

  • SOLUTION:

  • ALTERNATE SOLUTION FROM PLAYER:

    • The PDF had multiple files in it and I used http://www.extractpdf.com/ which showed me the flag
  • ALTERNATE SOLUTION FROM PLAYER:

    • Upon seeing this challenge I had to look up how to hide/reveal things hidden in a PDF.
    • I found several articles on layering, and ended up using https://www.pdf-online.com/osa/extract.aspx?o=img to split the layers.
    • One of the layers revealed the flag

 

CHALLENGE #10

  • SOLUTION:

    • Use strings command to extract strings from this c program
    • Use grep to filter out the flag (-v for inverted match)“`sh
      strings chest | grep cm18 | grep oots -v | grep hell -v | grep rrot -v | grep dana -v | grep ones -v | grep y key -v | grep flag -v | grep coin -v | grep wels -v | grep frum -v | grep ment -v
      “`
  • ALTERNATE SOLUTION FROM PLAYER:

    • Loaded them in excel, split by each group of characters, and then by using the filters was able to find the one that was actually the flag
  • ALTERNATE SOLUTION FROM PLAYER:

    • No file type was indicated, so I used http://checkfiletype.com/ which revealed that it was an ELF file.
    • After a bunch more searching, I couldn’t figure out how to open an ELF file, so I opened the file in notepad++ and searched for “cm18”. Apparently this was expected, as there were a whole lot of cm18-xxxx-xxxx-xxxx-xxxx codes, but they all had similar and piratey phrases in them like: cm18-bOjH-bUgo-lden-coin (golden coin), cm18-lYtQ-bUoC-vXpa-rrot (parrot), and cm18-gKkQ-bUoC-seas-hell (seashell).
    • I figured that the real flag was somewhere in the list, but notepad ++ made it almost impossible to search the list. So I dumped line# 14 into excel, and began poking around.
    • I transposed, sorted, and filtered the list and one of the codes stood out

 

CHALLENGE #11

  • SOLUTION:

    • Decompress the zip, and restore the file from git history.
    • This must be applied 1000 times (easier with a script).
    • There are four traps at some of the 100 steps, which must be handled:
      • skipping one number
      • old revision
      • branch
      • password-protection of zip file.
  • ALTERNATE SOLUTION FROM PLAYER

    • When this one unzipped there was a uncommitted git change which lead to another zip — this went on for a bit and then there was an image of a trunk. Had to go back up a level and switch branches. This happened a few times. Eventualy we got a password that we had to use to finish it off and find the flag. There was a similar CTF that was helpful in a write-up I found online.
  • ALTERNATE SOLUTION FROM PLAYER

    • Need to run a few time with values changed … and to manually fix the “problems.  (2 scripts provided)
    • #!/usr/bin/env python3
      import osfor x in range(1000, 0, -1):
      filenumber = (str(x)).rjust(4, ‘0’)
      print(filenumber)
      if (os.path.isfile(filenumber + “.zip”)):
      out = os.popen(“unzip ” + filenumber + “.zip”).read()
      out = os.popen(“git init ” + filenumber + “-r”).read()
      out = os.popen(“cp -r ” + filenumber + “/.git/objects ” + filenumber + “-r/.git”).read()
      out = os.popen(“cd ” + filenumber + “-r && git fsck”).read()
      print(out)
      id=out.split(“dangling commit “)[1]
      out = os.popen(“cd ” + filenumber + “-r && git branch main ” + id).read()
      out = os.popen(“cd ” + filenumber + “-r && git checkout main”).read()
      out = os.popen(“mv ” + filenumber + “-r/*.zip .”).read()
    • #!/usr/bin/env python3
      import osfor x in range(1000, 0, -1):
      filenumber = (str(x)).rjust(4, ‘0’)
      print(filenumber)
      if (os.path.isfile(filenumber + “.zip”)):
      out = os.popen(“cd ” + filenumber + ” && git log “).read()
      print(out)
  • ALTERNATE SOLUTION FROM PLAYER

    • This one was a pain in the butt because I am not familiar with scripting or Git. I unzipped the file, and found a git repository. I poked around the files a bit, but didn’t see anything overly suspicious in any of them.
    • Then I looked at the original zip file in notepad++ and saw “0999.zip”. This made me think there was some kind of deletion that needed to be undone.
    • So I researched more how git works, and found that deleted files can sometimes be recovered. So I checked out 0999.zip, unzipped it, and found another git repository.
    • I did the same thing with the next 4 layers, and then realized that I needed a way to script the change if there were going to be 1000 layers like the file name suggested or it was going to take me forever.
    • I decided to use the Kali Virtual Box and write a bash script to handle the unzipping and undeleting.
    • The first script I wrote, left all the folders inside each other, and it eventually failed because the file path got too long, so I rewrote it this way:
      #!/bin/bash
      for i in {0999..0001}
      do
      git checkout $i.zip
      unzip $i.zip -d ~/Desktop/Main/
      cd ~/Desktop/Main/$i/
      echo $i
      done
      exit 0

       

    • This worked until around 0800.zip when the Kali virtual box totally crashed.
    • So I started over and got a friend to help with a powershell script. This is what we came up with:
      $ErrorActionPreference = "Stop"
      for ($i=1000;$i -gt 0;$i--)
      {
         $number = "{0:D4}" -f $i
         $parentPath = "$env:UserProfile\Desktop\CTF"
         $path = $(Resolve-Path "$parentPath\$number.zip")
      
         Expand-Archive -Path $path -DestinationPath $(Get-Item $path).Directory.FullName
      
         $extractPath = $(Resolve-Path "$parentPath\$number")
         git -C $extractPath reset --hard
         $newZip = "$("{0:D4}" -f $($i - 1)).zip"
         while(-not $(Test-Path $extractPath\$newZip -PathType Leaf))
         {
           $i--
           $newZip = "$("{0:D4}" -f $($i - 1)).zip"
         }
      Write-Host "$extractPath\$newZip" -ForegroundColor Yellow
      Copy-Item "$extractPath\$newZip" -Destination "$parentPath\$newZip"
      }
    • This worked until 612 when the script failed because the path \612 didn’t exist. There was an image in its place with junk in a trunk.
    • I went back to 613 and did a git log. That showed a few commits.
      $ git log
      
      commit 155f7743c14bf72add80eeb39dceecf887265f70
      Author: Gorilla <gorilla@codemash.org>
      Date: Thu Dec 7 09:49:54 2017 -0500
      
      Change committed
      
      commit bab35d50ca51b6dcbef34e673e6da22837052bc8
      Author: Gorilla <gorilla@codemash.org>
      Date: Thu Dec 7 09:49:54 2017 -0500
      
      Change committed
      
      commit 8b9ddc677c2924c8baaf6eceff0ecacd0240e53c
      Author: Gorilla <gorilla@codemash.org>
      Date: Thu Dec 7 09:49:54 2017 -0500
    • Commit committed

      I checked them out

      $ git checkout bab35d50ca51b6dcbef34e673e6da22837052bc8
      Previous HEAD position was 8b9ddc6... Commit committed
      HEAD is now at bab35d5... Change committed

       

    • That made an image appear about being a GIT Master
    • $ git checkout 8b9ddc677c2924c8baaf6eceff0ecacd0240e53cGave me the file I needed to keep going. So I moved the zip file to the right directory, changed the variable in the script, fired back up the script and kept going.
    • At 277 the script failed again. And I was left with a message about branches
    • I went back to 278 and tried a git log, but there was nothing to see. So I opened the git GUI and looked at the branch history, which revealed a second branch “blaster”
    • Another checkout command handled this:
      aschertz@01479-ASCHERTZ MINGW64 ~/Desktop/CTF/0278 (master) 
      $ git log 
      commit 6b090bdf95474fc3084174048eb8b14094ead9c8 
      Author: Gorilla <gorilla@codemash.org> 
      Date:   Thu Dec 7 09:44:59 2017 -0500 
      
          Commit committed 
      
      commit d78f05d5a8597f6c2bd68c65fb306b1ff0592c70 
      Author: Gorilla <gorilla@codemash.org> 
      Date:   Thu Dec 7 09:44:59 2017 -0500 
      
          Commit committed 
      
      aschertz@01479-ASCHERTZ MINGW64 ~/Desktop/CTF/0278 (master) 
      $ git checkout d78f05d5a8597f6c2bd68c65fb306b1ff0592c70 
      Note: checking out 'd78f05d5a8597f6c2bd68c65fb306b1ff0592c70'. 
      HEAD is now at d78f05d... Commit committed
    • I now had the right zip, so I fired up the script again. It failed at 45 and left a clue:  “Pass is Fluffy99”
    • And checkout the 43.zip file with “git checkout 0043.zip”
    • Then I moved the file to the right directory and fired back up the script.
    • This went all the way to 0001.zip which contained an image of the flag
  • ALTERNATE SOLUTION FROM PLAYER

    • Written in bash
    • #!/bin/bashfor i in $(seq -f “%04g” 43 1)
      do
      echo “going to directory…”
      cd repo
      pwdecho “checking out deleted zip”
      git checkout — $i.zipecho “moving zip to parent dir…”
      mv $i.zip ..
      cd ..
      pwdecho “clearing out repo dir…”
      rm -rf repo/.git

      echo “unzipping file…”
      unzip $i.zip

      echo “moving git to repo…”
      mv $i/.git repo

      echo “removing zip file…”
      rm $i.zip

      echo “removing empty dir…”
      rm -rf $i
      done

  • ALTERNATE SOLUTION FROM PLAYER

    • Other than some manual things to get around the irregularities in the zip file or repository, I ran this. This was my first PowerShell script, so I wasn’t sure how to pad the filename to 4 characters. I had to manually add 0s, as I got further.

      function bacon {
      Param ([int] $b)
      if (1 -eq $b) {return}
      Expand-Archive E:\CodeMashCTF11\0$($b)\0$($b-1).zip -DestinationPath E:\CodeMashCTF11\
      cd ../0$($b-1)
      git checkout -f
      return bacon -b ($b-1)
      }

 

CHALLENGE #12

  • This was the onsite challenge… Code was located at the bottom of the electronic board, seen in the reflection of the glass, just above the elephant in the picture.
  • FLAG:  cm18-kala-hari-code-mash  (code is not in the picture)

 

CHALLENGE #13

  • SOLUTION

    • Download the challenge image
    • Use unzip or binwalk to extract the images behind the challenge image
    • Use steghide to extract the data hidden in the images
    • Use the password extracted from meadow.jpg to extract the flag from forest.jpg
  • ALTERNATE SOLUTION FROM PLAYER

    • There were multiple files. (Water, Forrest, Meadow)
    • Eventually figured out it was a rar and changed the extension to open it.
    • After looking at the three images, there was a clue I could see in notepad++ and used a steghide tool to look at the files which eventually revealed a password: The-Mad-Hatter which was used to find the flag in the forrest.jpg file.
  • ALTERNATE SOLUTION FROM PLAYER

    • I fixated on the wrong thing in this challenge, and spent a bunch of time trying to “follow” the white rabbit on twitter. Eventually, I gave up on that, and returned to the challenge page.
    • Upon examining the rabbit image in notepad++ I could see that there were other filenames being referenced (forest.jpg, meadow.jpg, and water.jpg).
    • After some searching on google to determine how files could be hidden in a jpeg, I found that sometimes they can be used like a rar archive.
    • So I edited the file to be a rar and extracted all.
    • The three images popped out.
    • I put them in notepad++ and found these messages:
      • Forest: “This image has a protected secret”
      • Meadow: “This meadow is all dried out, check the water first”
      • Water: “Steghide was here. With an empty password”
    • rest followed previous solutions

 

CHALLENGE #14

  • SOLUTION:

    • Follow the link to the first shred
    • Clue in challenge is rest of shreds are topsecret
    • Change the url to `topsecret_challenge_shred2.html` and `topsecret_challenge_shred3.html`
    • Combine the three parts with a dash

 

CHALLENGE #15

  • SOLUTION:

    • Deobfuscate the javascript code which is at the very bottom of the HTML file.
    • Understand the password check.
      • username: cavs
      • password: 3816547290
    • Enter the credentials, and a page with the flag is shown.
  • ALTERNATE SOLUTION FROM PLAYER:

    • This challenge redirects to a login page. I inspected the button, and found the JS function that it called:  <input type=”button” onclick=”javascript:checkEntries();” value=”Login”>
    • I searched for checkEntries(), and found two functions with that name, and that made me suspicious. So I went back to the page and looked for more scripts. That revealed this mess:eval(atob(“ZXZhbChmdW5jdGlvbihwLGEsYyxrLGUsZCl7ZT1mdW5jdGlvbihjKXtyZXR1cm4gYy50b1N0cmluZygzNil9O2lmKCEnJy5yZXBsYWNlKC9eLyxTdHJpbmcpKXt3aGlsZShjLS0pe2RbYy50b1N0cmluZyhhKV09a1tjXXx8Yy50b1N0cmluZyhhKX1rPVtmdW5jdGlvbihlKXtyZXR1cm4gZFtlXX1dO2U9ZnVuY3Rpb24oKXtyZXR1cm4nXFx3Kyd9O2M9MX07d2hpbGUoYy0tKXtpZihrW2NdKXtwPXAucmVwbGFjZShuZXcgUmVnRXhwKCdcXGInK2UoYykrJ1xcYicsJ2cnKSxrW2NdKX19cmV0dXJuIHB9KCdyIHEoKXsyIHU9Ny44KFwnd1wnKS5iOzIgcD03LjgoXCd2XCcpLmI7MiA0PVswLDAsMCwwLDAsMCwwLDAsMCwwXTsyIDU9YzszKHU9PT1cJ2dcJyl7MyhwPjAmJnAuaD09OSl7NT1qO2YoaT0xO2k8PTk7aSsrKXsyIDY9cC5rKGktMSk7MiBhPXAuZSgwLGkpOzMoNFs2XSE9MHx8YSVpIT0wKXs1PWN9Myg0WzZdPT0wKXs0WzZdPTF9fX19Myg1KXs3Lm0ubj1cJ29cJyt1K1wneFwnK3ArXCcuc1wnfXR7ZChcJ2xcJyl9fScsMzQsMzQsJ3x8dmFyfGlmfHVzZWR8b2t8ZGlnaXR8ZG9jdW1lbnR8Z2V0RWxlbWVudEJ5SWR8MTB8cGFydHx2YWx1ZXxmYWxzZXxhbGVydHxzdWJzdHJpbmd8Zm9yfGNhdnN8bGVuZ3RofHx0cnVlfGNoYXJBdHxub3BlfGxvY2F0aW9ufGhyZWZ8cGFsbV98fGNoZWNrRW50cmllc3xmdW5jdGlvbnxodG1sfGVsc2V8fHBwYXNzfHB1c2VyfF8nLnNwbGl0KCd8JyksMCx7fSkpDQo=”));
    • Chrome Dev tools cant pretty print this block. So I looked up the atob() function, and found that it was used for base 64 decoding.
    • So I pulled out the string from the function, and decoded it using: https://www.base64decode.org/ That produced the following:eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!”.replace(/^/,String)){while(c–){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return’\\w+’};c=1};while(c–){if(k[c]){p=p.replace(new RegExp(‘\\b’+e(c)+’\\b’,’g’),k[c])}}return p}(‘r q(){2 u=7.8(\’w\’).b;2 p=7.8(\’v\’).b;2 4=[0,0,0,0,0,0,0,0,0,0];2 5=c;3(u===\’g\’){3(p>0&&p.h==9){5=j;f(i=1;i<=9;i++){2 6=p.k(i-1);2 a=p.e(0,i);3(4[6]!=0||a%i!=0){5=c}3(4[6]==0){4[6]=1}}}}3(5){7.m.n=\’o\’+u+\’x\’+p+\’.s\’}t{d(\’l\’)}}’,34,34,’||var|if|used|ok|digit|document|getElementById|10|part|value|false|alert|substring|for|cavs|length||true|charAt|nope|location|href|palm_||checkEntries|function|html|else||ppass|puser|_’.split(‘|’),0,{}))
    • I dropped that into http://jsbeautifier.org/ and got the cleaned up JS:function checkEntries() {var u = document.getElementById(‘puser’).value;var p = document.getElementById(‘ppass’).value;var used = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

      var ok = false;

      if (u === ‘cavs’) {

      if (p > 0 && p.length == 10) {

      ok = true;

      for (i = 1; i <= 10; i++) {

      var digit = p.charAt(i – 1);

      var part = p.substring(0, i);

      if (used[digit] != 0 || part % i != 0) {

      ok = false

      }

      if (used[digit] == 0) {

      used[digit] = 1

      }

      }

      }

      }

      if (ok) {

      document.location.href = ‘palm_’ + u + ‘_’ + p + ‘.html’

      } else {

      alert(‘nope’)

      }

      }

       

    • It’s easy to see that the username is ”cavs”, but the password is a bit more tricky.
  • ALTERNATE SOLUTION FROM PLAYER

    • Script written in ruby to solve
    • @a = true
      @idx = 1def mod_passes(v)
      ret_val = true
      s = v.join.to_s
      (1..10).each do |i|
      ret_val = false if s.slice(0,i).to_i % i != 0
      end
      ret_val
      endwhile @a do
      v = [0,1,2,3,4,5,6,7,8,9].shuffle
      puts “#{@idx} #{v}”
      @a = false if mod_passes(v)
      @idx += 1
      endputs @a
  • ALTERNATE SOLUTION FROM PLAYER

    • python script
    • from itertools import permutations
    • for c in list(map(“”.join, permutations(‘0123456789’))):
    •       ok = True;
    •       for i in range(1,10):
    •             digit = c[i-1]
    •             part = int(c[0:i])
    •             if part % i != 0:
    •                 ok = False
    •                break
    •             if ok == True:
    •                 print(c)
Advertisements