PicoCTF 2019

Intorduction

Picked character name, then walked to the computer, the text ‘Somebody changed my password’ appeared, walked out the door to

General Skills

The Factory’s Secret - Points: 1

There appear to be some mysterious glyphs hidden inside this abandoned factory… I wonder what would happen if you collected them all?

  • Fragment 1 - When exploing the first room, accidently happened upon a glyph
    • Manual review of inventory shows an image, which appears to be a fragment of a QR code
    • Inspect your swords\nElements of fire\nHome of hearth\nPage and squire
  • Fragment 2 - Went into web exploitation door
    • Navigated past the computer into the door through the top
    • Moved the boulder into the lava and accessed hidden door through the bottom
    • Collected the glyph
  • Fragment 4 - Went into the binary exploitation door
    • Didnt find anything, and gave up for days, then returned and continued to go through alternating red and blue door, until music intensified and yellow door appeared
    • Entered yellow door and collect the fragment
  • Fragment 5 - Went into the forensics door
    • Moved around and explored the room, until I spotted waves in the top left hand corner of the room
    • Approached the waves and collected the fragment
  • Fragment 3 - Entered the cryptography door
    • Manually inspected each grave stone until I got to the fifth one across from the left in the right hand plot in the sixth row from the bottom

Lets Warm Up

If I told you a word started with 0x70 in hexadecimal, what would it start with in ASCII

  • Visited http://www.asciitable.com/ and looked up 0x70, same as ‘p’
  • Submitted: picoCTF{p}

Warmed Up

What is 0x3D (base 16) in decimal (base 10).

  • Visited http://www.asciitable.com/ and looked up 0x3D, same as 61
  • Submitted: picoCTF{16}

2Warm

Can you convert the number 43 (base 10) to binary (base 2)?

  • Used windows calculator in programmer mode to convert decimal 42 to binary, found 101010
  • Submitted: picoCTF{101010}

Bases

What does this bDNhcm5fdGgzX3IwcDM1 mean? I think it has something to do with bases.

  • Used Cyberchef to convert from base64, found l3arn_th3_r0p35
  • Submitted: picoCTF{l3arn_th3_r0p35}

First Grep

Can you find the flag in file? This would be really tedious to look through manually, something tells me there is a better way. You can also find the file in /problems/first-grep_0_93be1631acf1a93b98cdcc3e7b9fdc52 on the shell server.

  • Downloaded the file
  • grep picoCTF file
  • Submitted: picoCTF{grep_is_good_to_find_things_4b2451ea}

Resources

We put together a bunch of resources to help you out on our website! If you go over there, you might even find a flag! https://picoctf.com/resources (link)

  • Visitied the page at https://picoctf.com/resources
  • Found picoCTF{r3source_pag3_f1ag} (2019 competition) and picoCTF{xiexie_ni_lai_zheli} (2018 competition)
  • Submitted: picoCTF{r3source_pag3_f1ag}

strings it

Can you find the flag in file without running it? You can also find the file in /problems/strings-it_3_8386a6aa560aecfba03c0c6a550b5c51 on the shell server.

  • Downloaded the ‘strings’ file
  • Ran strings on the file and redirected the output into strings.txt
  • Ran grep for picoCTF on the strings.txt file to get the flag
  • Submitted: picoCTF{5tRIng5_1T_c7fff9e5}

what’s a net cat?

Using netcat (nc) is going to be pretty important. Can you connect to 2019shell1.picoctf.com at port 49816 to get the flag?

  • Installed netcat (choco install netcat)
  • Connect to host (nc 2019shell1.picoctf.com 49816)
  • Submitted: picoCTF{nEtCat_Mast3ry_a752a0d3}

Based

To get truly 1337, you must understand different data encodings, such as hexadecimal or binary. Can you get the flag from this program to prove you are on the way to becoming 1337? Connect with nc 2019shell1.picoctf.com 44303.

  • Connected to host using netcat (nc 2019shell1.picoctf.com 44303)
  • Found, Please give the 01100011 01101111 01101100 01101111 01110010 01100001 01100100 01101111 as a word.
  • Used cybershet to convert the provided data, first part of challenege, From Bionary, second using From Octal, and finally From Hex
  • Submitted: picoCTF{learning_about_converting_values_b515dfd2}

First Grep: Part II

Can you find the flag in /problems/first-grep–part-ii_5_956980126dc47c50540b0f8f35a8e443/files on the shell server? Remember to use grep.

  • Connect to server using the web shell provided via https://2019webshell1.picoctf.com/
  • Use pico CTF credentials to log in
  • Performed a recursive grep (grep -r picoCTF /problems/first-grep--part-ii_5_956980126dc47c50540b0f8f35a8e443/files/*)
  • Found flag in /problems/first-grep–part-ii_5_956980126dc47c50540b0f8f35a8e443/files/files6/file23
  • Submitted: picoCTF{grep_r_to_find_this_0898e9c9}

Plumbing

Sometimes you need to handle process data outside of a file. Can you find a way to keep the output from this program and search for the flag? Connect to 2019shell1.picoctf.com 13203.

  • Connected using netcat (nc 2019shell1.picoctf.com 13203)
  • The output scrolled past the screen
  • Piped the output to grep and searched for picoCTF (nc 2019shell1.picoctf.com 13203 | grep picoCTF)
  • Submitted: picoCTF{digital_plumb3r_995d3c81}

whats-the-difference

Can you spot the difference? kitters cattos. They are also available at /problems/whats-the-difference_0_00862749a2aeb45993f36cc9cf98a47a on the shell server

  • Logged in via the web shell
  • Tried to compare string between the files but found nothing useful
    • strings kitters.jpg > kittens.txt
    • strings cattos.jpg > cattos.txt
    • diff kittens.txt cattos.txt
  • Tried to get hex dumps of the files and compare but found nothing useful
    • xxd /problems/whats-the-difference_0_00862749a2aeb45993f36cc9cf98a47a/cattos.jpg > /tmp/cattos.bin
    • xxd /problems/whats-the-difference_0_00862749a2aeb45993f36cc9cf98a47a/kitters.jpg > /tmp/kitters.bin
    • diff /tmp/cattos.bin /tmp/kitters.bin > /tmp/diff.txt
  • Google for file compare utilities and came across the cmp command, read the man page, and attempted it using a couple of switch options, until something interesting was found
    • cmp -l -b /problems/whats-the-difference_0_00862749a2aeb45993f36cc9cf98a47a/kitters.jpg /problems/whats-the-difference_0_00862749a2aeb45993f36cc9cf98a47a/cattos.jpg
  • Was able to grab the required column
    • cmp -l -b /problems/whats-the-difference_0_00862749a2aeb45993f36cc9cf98a47a/kitters.jpg /problems/whats-the-difference_0_00862749a2aeb45993f36cc9cf98a47a/cattos.jpg | awk '{print $5}'
  • Google results found this https://stackoverflow.com/questions/24331687/is-it-possible-to-print-the-awk-output-in-the-same-line/24332610, and was able to get the flag string
    • cmp -l -b /problems/whats-the-difference_0_00862749a2aeb45993f36cc9cf98a47a/kitters.jpg /problems/whats-the-difference_0_00862749a2aeb45993f36cc9cf98a47a/cattos.jpg | awk 'BEGIN { ORS="" }; { print $5 }'
  • Submitted: picoCTF{th3yr3_a5_d1ff3r3nt_4s_bu773r_4nd_j311y_aslkjfdsalkfslkflkjdsfdszmz10548}

where-is-the-file

I’ve used a super secret mind trick to hide this file. Maybe something lies in /problems/where-is-the-file_4_f26b413d005c16c61f127740ab242b35.

  • Used the wen shell
  • `file /problems/where-is-the-file_4_f26b413d005c16c61f127740ab242b35
    • /problems/where-is-the-file_4_f26b413d005c16c61f127740ab242b35: directory
  • `ls /problems/where-is-the-file_4_f26b413d005c16c61f127740ab242b35
  • `ls -las /problems/where-is-the-file_4_f26b413d005c16c61f127740ab242b35
    • total 80
    • 4 drwxr-xr-x 2 root root 4096 Sep 28 22:05 .
    • 72 drwxr-x–x 684 root root 69632 Oct 10 18:02 ..
    • 4 -rw-rw-r– 1 hacksports hacksports 39 Sep 28 22:05 .cant_see_me
  • file /problems/where-is-the-file_4_f26b413d005c16c61f127740ab242b35/.cant_see_me
    • /problems/where-is-the-file_4_f26b413d005c16c61f127740ab242b35/.cant_see_me: ASCII text
  • cat /problems/where-is-the-file_4_f26b413d005c16c61f127740ab242b35/.cant_see_me
  • Submitted: picoCTF{w3ll_that_d1dnt_w0RK_cb4a5081}

flag_shop

There’s a flag shop selling stuff, can you buy a flag? Source. Connect with nc 2019shell1.picoctf.com 3967.

nc 2019shell1.picoctf.com 3967
Welcome to the flag exchange
We sell flags

1. Check Account Balance

2. Buy Flags

3. Exit

Enter a menu selection
2
Currently for sale
1. Defintely not the flag Flag
2. 1337 Flag
1
These knockoff Flags cost 900 each, enter desired quantity
2386100

The final cost is: -2147477296

Your current balance after transaction: 2147478396

Welcome to the flag exchange
We sell flags

1. Check Account Balance

2. Buy Flags

3. Exit

Enter a menu selection
1



Balance: 2147478396


Welcome to the flag exchange
We sell flags

1. Check Account Balance

2. Buy Flags

3. Exit

Enter a menu selection
2
Currently for sale
1. Defintely not the flag Flag
2. 1337 Flag
2
1337 flags cost 100000 dollars, and we only have 1 in stock
Enter 1 to buy one1
YOUR FLAG IS: picoCTF{m0n3y_bag5_cd0ead78}
Welcome to the flag exchange
We sell flags

1. Check Account Balance

2. Buy Flags

3. Exit

Enter a menu selection
3
  • Submitted: picoCTF{m0n3y_bag5_cd0ead78}

mus1c

I wrote you a song. Put it in the picoCTF{} flag format

114
114
114
111
99
107
110
114
110
48
49
49
51
114
  • Used a Python intepreter to manipulate the results until the flag was found in the right format
>>> res='''114
... 114
... 114
... 111
... 99
... 107
... 110
... 114
... 110
... 48
... 49
... 49
... 51
... 114'''
>>> x = res.split()
>>> z = ""
>>> for i in range(len(x)):
...     z += (chr(int(x[i])))
...
>>> print(z)
rrrocknrn0113r
>>> print("picoCTF{"+z+"}")
picoCTF{rrrocknrn0113r}
  • Submitted: picoCTF{rrrocknrn0113r}

1_wanna_b3_a_r0ck5tar

I wrote you another song. Put the flag in the picoCTF{} flag format

Rocknroll is right              
Silence is wrong                
A guitar is a six-string        
Tommy's been down               
Music is a billboard-burning razzmatazz!
Listen to the music             
If the music is a guitar                  
Say "Keep on rocking!"                
Listen to the rhythm
(If the rhythm without Music is nothing)
Tommy is rockin guitar
Shout Tommy!                    
Music is amazing sensation 
Jamming is awesome presence
Scream Music!                   
Scream Jamming!                 
Tommy is playing rock           
Scream Tommy!       
They are dazzled audiences                  
Shout it!
Rock is electric heaven                     
Scream it!
Tommy is jukebox god            
Say it!                                     
Break it down
Shout "Bring on the rock!"
(Else Whisper "That ain't it, Chief")                 
Break it down 
  • Used Python intepreter to get flag
>>> res='''66
... 79
... 78
... 74
... 79
... 86
... 73'''
>>> x = res.split()
>>> z = ""
>>> for i in range(len(x)):
...     z += (chr(int(x[i])))
...
>>> print("picoCTF{"+z+"}")
picoCTF{BONJOVI}
>>>
  • Submitted: picoCTF{BONJOVI}

Web Exploitation

Insp3ct0r

Kishor Balan tipped us off that the following code may need inspection: https://2019shell1.picoctf.com/problem/61676/ (link) or http://2019shell1.picoctf.com:61676

  • Opened the link in a web browser (Firefox)
  • Manually reviewed the page source code at view-source:https://2019shell1.picoctf.com/problem/61676/, found 1/3 of the flag ‘picoCTF{tru3_d3’
  • Manually reviewed the CSS sylesheet at view-source:https://2019shell1.picoctf.com/problem/61676/mycss.css, found 2/3 of the flag ’t3ct1ve_0r_ju5t’
  • Manually reviewed the Javascript file included in the page at view-source:https://2019shell1.picoctf.com/problem/61676/myjs.js, found 3/3 of the flag ‘_lucky?1638dbe7}’
  • Manually pieced together the flag
  • Subm,itted: picoCTF{tru3_d3t3ct1ve_0r_ju5t_lucky?1638dbe7}

dont-use-client-side

Can you break into this super secure portal? https://2019shell1.picoctf.com/problem/47289/ (link) or http://2019shell1.picoctf.com:47289

  • Opened the link in a web browser
  • Manually reviewed the source code and found the verify() function
  • Manually pieced together the checkpass value from the code
  • Submitted: picoCTF{no_clients_plz_ce22dc}

logon

The factory is hiding things from all of its users. Can you login as logon and find what they’ve been looking at? https://2019shell1.picoctf.com/problem/12284/ (link) or http://2019shell1.picoctf.com:12284

  • Attempted to logon using default credentials, username as admin, and password as password
  • Was able to log on, manually reviewed page source but found nothing useful
  • Used Cookie Quick Manager extension for Firefox to view cookies, found Admin value set to False, changed to True, saved cookie and refreshed page
  • Submitted: picoCTF{th3_c0nsp1r4cy_l1v3s_6f2c20e9}

where are the robots

Can you find the robots? https://2019shell1.picoctf.com/problem/32229/ (link) or http://2019shell1.picoctf.com:32229

Client-side-again

Can you break into this super secure portal? https://2019shell1.picoctf.com/problem/4163/ (link) or http://2019shell1.picoctf.com:4163

  • Opened the link a browser
  • Manually reviewed the source code and found the verify function
  • Pasted the code into https://beautifier.io/
  • Manually reviwed the de-obfuscated code and determined that only the following needs to be executed to get the flag:
if (checkpass[_0x4b5b('0x2')](0x0, split * 0x2) == _0x4b5b('0x3')) {
if (checkpass[_0x4b5b('0x2')](split * 0x2, split * 0x2 * 0x2) == _0x4b5b('0x4')) {
if (checkpass[_0x4b5b('0x2')](split * 0x2 * 0x2, split * 0x3 * 0x2) == _0x4b5b('0x6')) {
if (checkpass[_0x4b5b('0x2')](split * 0x3 * 0x2, split * 0x4 * 0x2) == _0x4b5b('0x5')) {
  • Opened web console in browser and pasted the obfuscated code into the console
  • Execute each check to get the value being compared as this forms part of the flag
21:19:56.907 _0x4b5b('0x3');
21:19:57.056 "picoCTF{"
21:20:01.910 _0x4b5b('0x4');
21:20:02.048 "not_this"
21:20:07.534 _0x4b5b('0x6');
21:20:07.677 "_again_e"
21:20:16.354 _0x4b5b('0x5');
21:20:16.494 "a9191}"
  • Submitted: picoCTF{not_this_again_ea9191}

Open-to-admins

This secure website allows users to access the flag only if they are admin and if the time is exactly 1400. https://2019shell1.picoctf.com/problem/37878/ (link) or http://2019shell1.picoctf.com:37878

  • Clue and hint suggest setting admin and time cookie
  • Used curl to submit request curl -v --cookie "admin=True;time=1400" https://2019shell1.picoctf.com/problem/37878/flag
  • Submitted: picoCTF{0p3n_t0_adm1n5_2e8d3883}

picobrowser

This website can be rendered only by picobrowser, go and catch the flag! https://2019shell1.picoctf.com/problem/32205/ (link) or http://2019shell1.picoctf.com:32205

  • Clue suggests browser identification used to render flag
  • Typically browsers are identified using the user agent header
  • Attempted to get flag using curl curl -v -A "picobrowser" https://2019shell1.picoctf.com/problem/32205/flag
  • Submitted: picoCTF{p1c0_s3cr3t_ag3nt_ee951878}

Irish-Name-Repo 1

There is a website running at https://2019shell1.picoctf.com/problem/4162/ (link) or http://2019shell1.picoctf.com:4162. Do you think you can log us in? Try to see if you can login!

  • The clue did not give much away, checked hint and identified referenced to backend databases
  • Visited site and navigated to Support page and Admin Login page, suspected SQL injection vulnerability on login form
  • Attempted basic SQL injection using the username as Admin and the password as ' OR '1'='1'--xx
  • Submitted: picoCTF{s0m3_SQL_96ab211c}

Irish-Name-Repo 2

There is a website running at https://2019shell1.picoctf.com/problem/14912/ (link). Someone has bypassed the login before, and now it’s being strengthened. Try to see if you can still login! or http://2019shell1.picoctf.com:14912

  • Attempted the same injection as Irish-Name-Repo 1, but received “SQLi detected.” message
  • Reviewed the hint which suggested that the password is being filtered
  • Attempted username as Admin' -- and multiple variation of it, but kepreceived “Login failed.” message, until i tried username as admin'--cc:w
  • Submitted: picoCTF{m0R3_SQL_plz_752d1173}

Empire1

Psst, Agent 513, now that you’re an employee of Evil Empire Co., try to get their secrets off the company website. https://2019shell1.picoctf.com/problem/49726/ (link) Can you first find the secret code they assigned to you? or http://2019shell1.picoctf.com:49726

CREATE TABLE user ( 
  id INTEGER NOT NULL, 
  username VARCHAR(64), 
  name VARCHAR(128), 
  password_hash VARCHAR(128), 
  secret VARCHAR(128), 
  admin INTEGER, 
  PRIMARY KEY (id) 
)

CREATE TABLE todo ( 
  id INTEGER NOT NULL, 
  item VARCHAR(256), 
  user_id INTEGER, 
  PRIMARY KEY (id), 
  FOREIGN KEY(user_id) REFERENCES user (id) 
)
  • Tried to get the secret value for the user I had created
  • X’ || (SELECT secret FROM user WHERE username = ’test’) || ‘X
  • Submitted: picoCTF{wh00t_it_a_sql_injectdf389592}

Irish-Name-Repo 3

There is a secure website running at https://2019shell1.picoctf.com/problem/4161/ (link) or http://2019shell1.picoctf.com:4161. Try to see if you can login as admin!

  • Navigated to the page and attempted to login via the admin page
  • entered an arbiitrary password “test” and got a page saying “Login failed.”
  • Tried some basic SQL injectin but kept getting a blank page. Thinking this was blind SQL injection, attempted some basic manual blind injection from the cheat sheets, but did not have any luck
  • Returned to the main page and tried to find a registration page but did not have any luck
  • Whilst manually reviewing the source, found the hidden debug field on the login page, used the browser editor to set the value to 1
  • Attempted login using test as the password and received the debug SQL statement
  • Attempted SQL injection with debugging, but when submitting test' OR 1=1; --X, get some encoded statement
password: test' OR 1=1; --X
SQL query: SELECT * FROM admin where password = 'grfg' BE 1=1; --K'
  • Navigated to https://www.boxentriq.com/code-breaking/text-analysis and tried to use the text analysis tool with the debug output string grfg' BE 1=1; --K as input
  • Reviewed the results manually until row 13 of the Caesar shift analysis which resembled our initial injection input testorx
  • This indicated that the input was being passed into a ROT13/Caesar shift cipher, so just re-injected the output to get the injection
  • Injected grfg' BE 1=1; --K
password: grfg' BE 1=1; --K
SQL query: SELECT * FROM admin where password = 'test' OR 1=1; --X'

Logged in!

Your flag is: picoCTF{3v3n_m0r3_SQL_d490b67d}
  • Submitted: picoCTF{3v3n_m0r3_SQL_d490b67d}

JaWT Scratchpad

Check the admin scratchpad! https://2019shell1.picoctf.com/problem/37903/ or http://2019shell1.picoctf.com:37903

Hints included, What is that cookie? Have you heard of JWT?

  • Navigated to the site and checked cookies
  • Logged in as john, as I noticed the reference to john the ripper on the page
  • Found the JWT set as the cookie, I have a little bit of experience with JWT, so tried setting the algorithm in the header to None using "alg":"none" as well as changing the user to admin using "user":"admin" and "admin":true, but kept getting internal errors. Suspected that the API/server has not included None in the algorithm whitelist.
    • eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiam9obiJ9._fAF3H23ckP4QtF1Po3epuZWxmbwpI8Q26hRPDTh32Y
    • Additional information on JWT can be found in RFC7519 and RFC7797
  • https://security.stackexchange.com/questions/134200/cracking-a-jwt-signature
  • Used eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiam9obiJ9#fdf005dc7db77243f842d1753e8ddea6e656c666f0a48f10dba8513c34e1df66 into a file call jwt.txt
  • Used JTR with the rockyou wordlist /usr/sbin/john --wordlist=/usr/share/wordlists/rockyou.txt jwt.txt
/usr/sbin/john --wordlist=/usr/share/wordlists/rockyou.txt jwt.txt 
Using default input encoding: UTF-8
Loaded 1 password hash (HMAC-SHA256 [password is key, SHA256 128/128 AVX 4x])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
ilovepico        (?)
1g 0:00:00:11 DONE (2020-03-01 01:33) 0.08779g/s 649282p/s 649282c/s 649282C/s iloverob4live345..ilovepatri
Use the "--show" option to display all of the cracked passwords reliably
Session completed
  • Used the devugger at https://jwt.io/ to update the JWT using the secret and existing hash for "user":"admin"
  • Reset the Cookie containing the JWT to the generated JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.gtqDl4jVDvNbEe_JYEZTN19Vx6X9NNZtRVbKPBkhO-s
  • Submitted: picoCTF{jawt_was_just_what_you_thought_9ed4519dee8140de7a186a5df5a08d6e}

Java Script Kiddie

The image link appears broken… https://2019shell1.picoctf.com/problem/37826 or http://2019shell1.picoctf.com:37826

This is only a JavaScript problem.

  • Used curl to hit the site, since the clue mentioned Javascript, I didn’t want want to trigger anything
  • Manually reviewed the Javascript code, particularly the assemble_png function
    • Appears to be be populating a bytes array from /bytes, then when a key is submitted, attempts to unscrable the bytes array to populates ‘results’ array. The results array is then used to create a PNG file which is set as the ‘Area’ source
    • The input is only used if its length of the input is 16
    • The result is the value of the bytes shifted up by 48 in the Unicode table
    • The assemble_png function always returns false :)
  • I gave up for a day and then came back
  • Tried to understand PNG file format
    • https://tools.ietf.org/html/rfc2083
    • 12.11 - PNG file signature magic numbers as 89 50 4E 47 0D 0A 1A 0A should be at offset 0, i.e. start of file
    • Followed by 4-part chunks comprising 4-byte length, 4-byte type, and chunk data, and a 4-byte CRC of the chunk (including length and type)
    • Section 4 - A valid PNG image must contain an IHDR chunk, one or more IDAT chunks, and an IEND chunk.
    • The IHDR chunck must appear first and contain the 4-byte width, 4-byte height, 1-byte bit depth, 1-byte colour type, 1-byte compression method, 1-byte filter method, and 1-byte interlace method. Therefore 13 bytes in length
    • Thus we know that the IHDR chunk will have a fix length, 13 bytes as 00 00 00 0D and type because IHDR (in hex) 49 48 44 52 is a critical chunk
    • So we know the first 16-bytes of the decrypted bytes we expect, i.e. a good image should start with 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52
  • If we grab just the bytes off the server at https://2019shell1.picoctf.com/problem/37826/bytes, and them manually search for the pattern, but the shifter value which is based on the key moves the byte order on us, so what do!
  • I gave up for a couple of days and then came back
  • Realised that the key must be 16-charcters in length and that each character is used to decrypt a series of bytes, but there are only ever 16 series. The shifter variable is used to determine where in the series the value is swapped from
  • Thus we should be shifting the numbers in the series to form the known 16-byte header of a PNG file, but first lets convert the hex digits to decimal so we can desk/paper check this. I tried to solve the problem using Javascript in the browser using the following code, and discoered that some elements of th header may be found multiple times in a series, i.e. could have multiple shifter or key values, but was getting closer to the solution
/* Stolen from the original Javascript */
var bytes = [];
$.get("bytes", function(resp) { bytes = Array.from(resp.split(" "), x => Number(x)); });

/* X-ploit function */
function x()
{
  var LEN = 16; /* Length of the key, as well as number of series */
  var pnghdr = ['89','50','4e','47','d','a','1a','a','0','0','0','d','49','48','44','52']; /* Known PNG header values as hexadecimal values, but cleaned up for Javascript toString(16) matching */
  var key = ''; /* Variable to hold a possible key value */
  var series = ''; /* Variable to temporarily hold a series being searched */
  var found = 0; /* Number of times a value is found in a series */

  for(var i = 0; i < LEN; i++)
  {
    for(var j = 0; j < (bytes.length / LEN); j++)
    {
      /* Found the header value in the series */
      if (bytes[(j*LEN)+i].toString(16) == pnghdr[i]) 
      {
        found++;
        console.log('found: ' + pnghdr[i] + ' at ' + j + ', found: ' + found);
        key += (found == 1 ? "   " : ',')+j.toString();
      }
      series += String('   '+(bytes[(j*LEN)+i]).toString(16)).slice(-3);
    }

    console.log(series);

    /* Reset variables for next iteration */
    series = '';
    found = 0;
  }
  console.log("key = "+key)
  return true;
}
  • Refactored the code to try and provide possible combinations of the multiple key elements to provide a list of possible complete keys
/* Stolen from the original Javascript */
var bytes = [];
$.get("bytes", function(resp) { bytes = Array.from(resp.split(" "), x => Number(x)); });

/* X-ploit function */
function x()
{
  var LEN = 16; /* Length of the key, as well as number of series */
  var pnghdr = ['89','50','4e','47','d','a','1a','a','0','0','0','d','49','48','44','52']; /* Known PNG header values as hexadecimal values, but cleaned up for Javascript toString(16) matching */
  var keyparts = [[]]; /* Variable to hold a possible key value */
  var series = ''; /* Variable to temporarily hold a series being searched */
  var found = 0; /* Number of times a value is found in a series */

  for(var i = 0; i < LEN; i++)
  {
    /* Reset variables for next iteration */
    series = '';
    found = 0;
    var keypart = [];

    for(var j = 0; j < (bytes.length / LEN); j++)
    {
      /* Found the header value in the series */
      if (bytes[(j*LEN)+i].toString(16) == pnghdr[i]) 
      {
        found++;
        // DEBUG
        //console.log('found: ' + pnghdr[i] + ' at ' + j + ', found: ' + found);
        keypart.push(j.toString());
      }
      series += String('   '+(bytes[(j*LEN)+i]).toString(16)).slice(-3);
    }

    /* Append the key part to the rest of the parts */
    keyparts.push(keypart);
  }

  /* Combine the key parts to get all possible keys */
  keys = [[]];
  for(var k = 0; k < keyparts.length; k++)
  {
    var part = keyparts[k];
    var combined = [];
    for(var l = 0; l < keys.length; l++)
    {
      for(var m = 0; m < part.length; m++)
      {
        combined.push(keys[l].concat(part[m]));
      }
    }
    keys.push(combined);
  }

  /* Print all possible keys */
  for(var n = 0; n < keys.length; n++)
  {
    console.log(keys[n]);
  }

  return true;
}

See also