Upon accessing the site, we find a textbox with a submit button next to it. When we press submit, a placeholder image icon appears. We suspect that inputting a correct password into the box will make the image valid. Let's inspect the javascript, given that this is a JS-only problem by the hint:
Looking on source code, we'll see assemble_png function.
We note the AJAX query for bytes. Accessing https://2019shell1.picoctf.com/problem/37826/bytes gives us a large array of bytes represented as integers. We also read the code to see that bytes is treated as a 2D array with 16 columns; each column is shifted by the corresponding value in key. (For instance, if the third digit in key is 7, then the third column is shifted down by 7). We can write a python script to help visualize this:
deftohex(a):return"{:02x}".format(a)f=open("bytes.txt","r")bytelist=map(int,f.read().split(" "))f.close()key="0000000000000000"result= [0 forxinbytelist]SIZE=16for i inrange(SIZE):shift=ord(key[i]) -48for j inrange(len(result) /SIZE):result[(j*SIZE+i)] = bytelist[(((j+shift)*SIZE) % len(bytelist)) + i]for i inrange(len(result) /SIZE):print' '.join(map(tohex,result[i*SIZE:(i+1)*SIZE]))
If instead the key were to be 0070000000000000, the third column would begin with 3c, 42, 4e, 01, etc.
From here, the key observation to make is that this data must represent a PNG image; we also know that a PNG must begin with the following header:
89504e470d0a1a0a
Based on this alone, we can find that the first half of the key is 49952030, which rotates the columns to get the header to be correct. Furthermore, we know that this header must be immediately followed by an IHDR chunk, which always has length 0d. Thus, our first row must look like:
89504e470d0a1a0a0000000d49484452
We can thus quickly find that the correct key must be of the form 49952030???75112. The three ?s are there because the corresponding byte (00) has multiple possible values (4,5,6 for the first, 7,8,9 for the second (we can't have the two-digit 10), and 2,3,4,5 for the third). We could brute force these possibilites, but we can reduce our search space by look at the second row. By the spec, this corresponds to the content of the IHDR chunk, which must look like:
Let's see what the three ?s must be:
The first ? must make the bit depth valid (1, 2, 4, 8, 16); the only way we can do this is having * the first ? = 5.
The second ? must make the color type valid (0, 3 based on the bit depth); we must have the second ? = 7,8,9.
The third ? must make the compression method valid (0 is the only one allowed); we must have the third ? = 2,3,4.
With only nine possibilites left, we can simply brute force the possible keys: