Java Script Kiddie 2 - 450 points
Description
The image link appears broken… twice as badly… https://2019shell1.picoctf.com/problem/32262 or http://2019shell1.picoctf.com:32262
Flag
picoCTF{f1ee7ff44419a675d1a0f0a1a91dff4c}
Solution
This challenge is similar to Java Script Kiddie 1, except the code changed a bit:
var bytes = [];
$.get("bytes", function(resp) {
bytes = Array.from(resp.split(" "), x => Number(x));
});
function assemble_png(u_in){
var LEN = 16;
var key = "00000000000000000000000000000000";
var shifter;
if(u_in.length == key.length){
key = u_in;
}
var result = [];
for(var i = 0; i < LEN; i++){
shifter = Number(key.slice((i*2),(i*2)+1));
for(var j = 0; j < (bytes.length / LEN); j ++){
result[(j * LEN) + i] = bytes[(((j + shifter) * LEN) % bytes.length) + i]
}
}
while(result[result.length-1] == 0){
result = result.slice(0,result.length-1);
}
document.getElementById("Area").src = "data:image/png;base64," + btoa(String.fromCharCode.apply(null, new Uint8Array(result)));
return false;
}
It seems to do some operations based off the given key input, and then converts it to a PNG image in base64 format. We know that PNG images have the magic number 89 50 4e 47 0d 0a 1a 0a
as its file signature. Most PNG images' first 16 bytes are 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52
, so let’s assume this is the case for the image.
We can write a Python script to try all possible keys that will give base64-strings that have the first 16 bytes as 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52
. We first write a script to see what possible keys can exist:
import base64,random,string
bytes = [18,25,55,252,248,230,248,246,124,43,141,211,73,205,162,187,16,223,0,142,73,3,78,227,145,65,142,127,0,50,31,182,123,59,78,196,13,253,26,63,58,66,96,116,154,53,19,231,166,201,1,193,0,69,1,68,38,0,0,172,56,0,254,120,42,106,0,96,147,10,68,10,93,0,0,13,97,72,191,255,227,31,70,128,198,0,90,114,34,120,156,130,64,192,222,0,227,141,156,39,244,73,26,65,174,7,232,13,120,77,201,82,0,0,13,222,80,134,105,58,0,131,131,0,69,55,0,108,137,80,21,0,126,1,9,236,1,212,163,237,155,59,68,228,0,0,188,71,243,1,76,17,84,141,55,163,230,40,95,51,164,0,248,114,124,124,85,7,48,204,128,102,251,227,138,51,48,12,219,2,171,136,248,107,101,154,202,248,62,110,152,100,205,205,190,159,38,84,254,213,236,50,34,222,66,253,245,55,12,53,2,163,21,199,104,157,227,198,239,204,34,85,150,175,137,242,111,233,145,34,136,104,223,127,55,69,86,135,141,86,254,95,192,91,11,228,213,61,12,64,1,52,239,255,182,102,170,223,200,116,60,252,46,223,249,255,95,195,81,233,158,128,1,92,126,39,35,228,124,244,61,61,157,31,221,34,100,234,21,40,63,29,86,80,68,42,198,44,147,98,200,143,189,187,171,44,133,253,104,52,53,74,160,102,128,252,223,127,114,19,174,255,170,18,39,252,194,85,27,63,177,62,16,205,161,59,122,165,41,252,161,122,161,253,51,155,127,67,46,166,34,61,64,241,130,109,132,107,81,13,123,206,201,80,124,119,241,33,241,45,8,92,198,145,7,187,37,196,84,86,211,179,123,170,253,198,245,111,150,15,172,202,198,87,209,79,49,50,78,106,212,1,173,177,183,127,199,175,239,99,252,230,44,42,182,237,104,10,90,142,57,105,17,142,246,101,223,189,235,207,255,21,6,192,238,87,26,29,215,91,36,221,71,84,191,243,241,129,252,21,10,173,161,212,40,186,154,20,180,94,19,126,10,8,250,234,253,34,133,42,77,168,212,130,194,231,41,126,50,176,38,160,168,61,98,76,253,56,206,79,108,235,204,67,175,254,253,59,187,175,148,95,211,191,195,43,139,61,195,181,171,201,136,71,244,9,255,118,252,252,213,203,91,242,46,242,23,86,38,127,246,235,44,126,146,48,21,53,21,156,172,174,79,191,143,252,49,17,162,61,228,56,241,61,198,223,57,128,90,63,21,223,31,87,219,109,85,227,109,134,56,69,33,223,215,138,154,129,58,40,217,203,19,170,161,220,93,143,169,54,163,197,89,124,163,21,1,152,159,204,102,114,107,239,217,54,210,191,164,67,179,11,234,183,124,244,72,32,124,4,247,139,204,115,35,242,237,24,35,148,24,40,48,158,219,60,111,56,156,119,2,2,61,41,180,228,93,217,171,255,56,93,117,166,159,115,102,190,181,79,54,245,83,191,175,148,30,120,47,11,95,214,102,254,99,189,99,122,107,166,5,202,87,222,62,229,223,211,242,221,215,63,153,156,203,182,6,84,172,63,178,252,149,34,233,120,231,49,175,179,147,39,15,106,101,227,0,74,214,253]
num = 0
arr = [0x89,0x50,0x4e,0x47,0xd,0x0a,0x1a,0x0a,0,0,0,0xd,0x49,0x48,0x44,0x52]
for j in arr:
s = []
for i in range(len(bytes)):
if bytes[i] == j:
s.append(i)
for i in s:
if (i-num)%16 == 0:
print(hex(j)," ",chr((i-num)//16))
print("DONE!")
num += 1
This gives us:
('0x89', ' ', '\x08')
('0x89', ' ', '\x0e')
DONE!
('0x50', ' ', '\x08')
DONE!
('0x4e', ' ', '\x02')
DONE!
('0x47', ' ', '\t')
DONE!
('0xd', ' ', '\x02')
DONE!
('0xa', ' ', '\x04')
DONE!
('0x1a', ' ', '\x02')
('0x1a', ' ', '\x06')
DONE!
('0xa', ' ', '\x04')
DONE!
('0x0', ' ', '\x07')
DONE!
('0x0', ' ', '\x03')
('0x0', ' ', '\x04')
DONE!
('0x0', ' ', '\x03')
('0x0', ' ', '\x04')
DONE!
('0xd', ' ', '\x04')
('0xd', ' ', '\x06')
DONE!
('0x49', ' ', '\x00')
DONE!
('0x48', ' ', '\x04')
DONE!
('0x44', ' ', '\x08')
DONE!
('0x52', ' ', '\x06')
DONE!
So it seems the following key possibilities can occur (for each of the 16 bytes):
- 1st byte: \x08 or \x0e
- 2nd byte: \x08
- 3rd byte: \x02
- 4th byte: \t
- 5th byte: \x02
- 6th byte: \x04
- 7th byte: \x02 or \x06
- 8th byte: \x04
- 9th byte: \x07
- 10th byte: \x03 or \x04
- 11th byte: \x03 or \x04
- 12th byte: \x04 or \x06
- 13th byte: \x00
- 14th byte: \x04
- 15th byte: \x08
- 16th byte: \x06
We can write a Python script to generate all possible images, based off all of the possible keys and see if we find anything interesting. My solve script is below:
#!/usr/bin/env python2
import base64,random,string
bytes = [18,25,55,252,248,230,248,246,124,43,141,211,73,205,162,187,16,223,0,142,73,3,78,227,145,65,142,127,0,50,31,182,123,59,78,196,13,253,26,63,58,66,96,116,154,53,19,231,166,201,1,193,0,69,1,68,38,0,0,172,56,0,254,120,42,106,0,96,147,10,68,10,93,0,0,13,97,72,191,255,227,31,70,128,198,0,90,114,34,120,156,130,64,192,222,0,227,141,156,39,244,73,26,65,174,7,232,13,120,77,201,82,0,0,13,222,80,134,105,58,0,131,131,0,69,55,0,108,137,80,21,0,126,1,9,236,1,212,163,237,155,59,68,228,0,0,188,71,243,1,76,17,84,141,55,163,230,40,95,51,164,0,248,114,124,124,85,7,48,204,128,102,251,227,138,51,48,12,219,2,171,136,248,107,101,154,202,248,62,110,152,100,205,205,190,159,38,84,254,213,236,50,34,222,66,253,245,55,12,53,2,163,21,199,104,157,227,198,239,204,34,85,150,175,137,242,111,233,145,34,136,104,223,127,55,69,86,135,141,86,254,95,192,91,11,228,213,61,12,64,1,52,239,255,182,102,170,223,200,116,60,252,46,223,249,255,95,195,81,233,158,128,1,92,126,39,35,228,124,244,61,61,157,31,221,34,100,234,21,40,63,29,86,80,68,42,198,44,147,98,200,143,189,187,171,44,133,253,104,52,53,74,160,102,128,252,223,127,114,19,174,255,170,18,39,252,194,85,27,63,177,62,16,205,161,59,122,165,41,252,161,122,161,253,51,155,127,67,46,166,34,61,64,241,130,109,132,107,81,13,123,206,201,80,124,119,241,33,241,45,8,92,198,145,7,187,37,196,84,86,211,179,123,170,253,198,245,111,150,15,172,202,198,87,209,79,49,50,78,106,212,1,173,177,183,127,199,175,239,99,252,230,44,42,182,237,104,10,90,142,57,105,17,142,246,101,223,189,235,207,255,21,6,192,238,87,26,29,215,91,36,221,71,84,191,243,241,129,252,21,10,173,161,212,40,186,154,20,180,94,19,126,10,8,250,234,253,34,133,42,77,168,212,130,194,231,41,126,50,176,38,160,168,61,98,76,253,56,206,79,108,235,204,67,175,254,253,59,187,175,148,95,211,191,195,43,139,61,195,181,171,201,136,71,244,9,255,118,252,252,213,203,91,242,46,242,23,86,38,127,246,235,44,126,146,48,21,53,21,156,172,174,79,191,143,252,49,17,162,61,228,56,241,61,198,223,57,128,90,63,21,223,31,87,219,109,85,227,109,134,56,69,33,223,215,138,154,129,58,40,217,203,19,170,161,220,93,143,169,54,163,197,89,124,163,21,1,152,159,204,102,114,107,239,217,54,210,191,164,67,179,11,234,183,124,244,72,32,124,4,247,139,204,115,35,242,237,24,35,148,24,40,48,158,219,60,111,56,156,119,2,2,61,41,180,228,93,217,171,255,56,93,117,166,159,115,102,190,181,79,54,245,83,191,175,148,30,120,47,11,95,214,102,254,99,189,99,122,107,166,5,202,87,222,62,229,223,211,242,221,215,63,153,156,203,182,6,84,172,63,178,252,149,34,233,120,231,49,175,179,147,39,15,106,101,227,0,74,214,253]
def randomStr():
return ''.join(random.choice(string.ascii_lowercase) for i in range(10))
def assemble_png(u_in):
LEN = 16
key = "0000000000000000"
shifter = 0
if(len(u_in) == 16):
key = u_in
result = [0]*800
for i in range(16):
shifter = ord(key[i])
for j in range(47): # 720/16 - 45 blocks
result[(j*16)+i] = bytes[(((j+shifter)*16)%720)+i]
while result[len(result)-1] == 0:
result = result[0:len(result)-1]
flag = []
for i in result:
flag.append(i)
return flag
arr1 = ['\x08','\x0e']
arr7 = ['\x02','\x06']
arr10 = ['\x03','\x04']
arr11 = ['\x03','\x04']
arr12 = ['\x04','\x06']
for i in range(2):
for j in range(2):
for k in range(2):
for l in range(2):
for m in range(2):
key = arr1[i] + "\x08\x02\t\x02\x04" + arr7[j] + "\x04\x07" + arr10[k] + arr11[l] + arr12[m] + "\x00\x04\x08\x06"
s = assemble_png(key)
file = open('a'+randomStr()+'.png','wb')
file.write(str(bytearray(s)))
file.close()
We find one of the images is a QR code. Decoding the QR code, we get the flag:
➜ zbarimg anddgunvywj.png
QR-Code:picoCTF{f1ee7ff44419a675d1a0f0a1a91dff4c}
scanned 1 barcode symbols from 1 images in 0.05 seconds
Thus, the flag is picoCTF{f1ee7ff44419a675d1a0f0a1a91dff4c}
.