Java Script Kiddie

Problem

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

Solution

  1. Webpage source code:

     <html>
         <head>
             <script src="jquery-3.3.1.min.js"></script>
             <script>
                 var bytes = [];
                 $.get("bytes", function(resp) {
                     bytes = Array.from(resp.split(" "), x => Number(x));
                 });
    
                 function assemble_png(u_in){
                     var LEN = 16;
                     var key = "0000000000000000";
                     var shifter;
                     if(u_in.length == LEN){
                         key = u_in;
                     }
                     var result = [];
                     for(var i = 0; i < LEN; i++){
                         shifter = key.charCodeAt(i) - 48;
                         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;
                 }
             </script>
         </head>
         <body>
    
             <center>
                 <form action="#" onsubmit="assemble_png(document.getElementById('user_in').value)">
                     <input type="text" id="user_in">
                     <input type="submit" value="Submit">
                 </form>
                 <img id="Area" src=""/>
             </center>
    
         </body>
     </html>
  2. Run $.get("bytes", function(resp) {bytes = Array.from(resp.split(" "), x => Number(x));}); from the source code in developer console to get list of bytes:

     137 147 206 121 126 59 121 231 0 4 121 188 174 107 242 107 0 124 231 234 119 50 0 0 1 147 229 170 73 153 65 191 164 121 48 249 53 254 26 10 84 199 169 75 0 28 1 53 48 82 78 249 171 61 1 114 224 133 203 169 155 66 255 130 145 80 1 183 76 131 68 65 89 229 134 32 113 72 148 82 12 0 0 184 2 218 186 76 169 250 151 249 194 192 96 108 170 0 134 157 119 75 131 120 112 231 157 255 131 65 68 235 231 12 6 192 0 222 228 69 249 69 255 1 157 110 95 204 59 230 195 71 13 0 183 112 6 0 78 68 32 78 138 41 76 175 239 114 0 10 107 243 179 0 0 13 25 144 54 75 141 137 226 2 135 0 74 146 212 120 0 0 49 119 154 121 231 191 113 63 61 73 207 252 109 29 156 237 237 205 44 181 255 234 45 201 81 7 111 130 76 72 160 71 252 189 222 4 45 102 16 164 153 122 6 236 97 221 248 223 189 159 191 15 186 67 214 172 254 6 103 1 239 222 111 241 128 173 157 249 176 240 95 173 172 207 128 248 254 100 121 231 32 123 102 156 187 25 219 126 99 10 127 136 254 208 144 42 223 245 199 191 126 63 242 65 146 62 217 103 195 245 123 51 216 107 122 239 128 4 205 81 87 164 77 166 255 1 56 191 144 200 56 6 36 54 208 38 51 163 146 136 97 152 102 86 67 136 54 254 211 246 158 221 31 179 191 243 21 0 230 168 247 251 222 113 110 91 32 183 22 244 45 1 220 168 97 180 247 205 207 14 199 186 146 106 250 144 115 222 151 173 111 131 220 144 233 122 255 219 176 73 150 157 22 143 74 217 68 101 232 176 170 113 254 92 169 250 106 153 148 251 31 124 122 156 191 239 186 121 94 197 5 252 248 34 55 29 252 124 181 226 55 127 124 206 48 75 126 234 94 137 135 121 191 89 24 135 209 221 81 56 181 115 52 122 68 77 240 90 247 182 197 190 111 203 15 236 79 123 223 170 144 93 244 56 247 7 190 219 76 219 245 39 129 110 133 226 176 46 193 253 78 206 160 247 86 91 37 36 24 234 87 241 98 57 36 107 14 56 242 135 213 233 55 229 121 228 96 149 95 6 92 30 230 184 44 149 107 102 16 42 182 95 228 158 18 21 32 205 77 53 94 221 173 252 21 127 15 82 95 163 242 120 224 214 163 0 230 91 72 244 111 255 32 95 225 170 135 57 178 172 87 45 193 84 78 90 202 51 178 127 63 249 165 189 47 239 27 208 191 248 67 223 59 130 249 207 207 49 252 164 114 231 181 214 188 181 227 26 125 27 198 147 64 200 215 229 143 249 29 171 227 252 115 152 80 6 143 53 160 77 210 113 143 214 204 219 20 236 102 252 153 126 12 3 249 152 188 213 49 94 226 157 55 144 180 159 251 199 200 141 203 31 146 9 206 111 7 85 183 119 73 111 109 171 243 240 189 215 29 215 242 235 162 178 174 106 73 165 173 84 219 232 242 250 59 147 235 27 119 211 11 99 98 142 102 37 139 64 58 30 49 178 226 245 73 253 239 252 179 115 177 18
  3. The website takes the above list of bytes and shifts them based on the key the user enters. For each character in the key, the script shifts every 16th byte starting with byte i, where i is the index of the character in the key. In this way, the first 16 bytes of the image correspond to the 16 digits in the user-specified key.

  4. A PNG file consists of a PNG signature followed by a series of chunks. The first eight bytes of a PNG file always contain the following (decimal) values: 137 80 78 71 13 10 26 10. Each chunk header has a well-known structure: 4 bytes of length and 4 bytes of chunk type. The first chunk is called IHDR and has the length of 0xD, so we know that the next 8 bytes are 00 00 00 0D 49 48 44 52.

  5. Run script.py. For each character of the key, this script will try all digits until one is found that places the expected value in the current location.

    Output:

     Key: 0438892208991464
     Key Length: 16
  6. Use zbar (sudo apt install zbar-tools): zbarimg index.png and get the flag:

     QR-Code:picoCTF{905765bf9ae368ad98261c10914d894e}
     scanned 1 barcode symbols from 1 images in 0.03 seconds

Flag

picoCTF{905765bf9ae368ad98261c10914d894e}

Last updated