You can read the full writeup [here](https://lim1ts.github.io/ctf/2017/10/19/hackluTriangles.html), which is more wordy.
More succintly, observe that there are some .js files in the source.
In secret.js,
```function test_pw(e, _) {    var t = stoh(atob(getBase64Image("eye")))      , r = 4096      , m = 8192      , R = 12288      , a = new uc.Unicorn(uc.ARCH_ARM,uc.MODE_ARM);    a.reg_write_i32(uc.ARM_REG_R9, m),    a.reg_write_i32(uc.ARM_REG_R10, R),    a.reg_write_i32(uc.ARM_REG_R8, _.length),    a.mem_map(r, 4096, uc.PROT_ALL);    for (var o = 0; o < o1.length; o++)        a.mem_write(r + o, [t[o1[o]]]);    a.mem_map(m, 4096, uc.PROT_ALL),    a.mem_write(m, stoh(_)),    a.mem_map(R, 4096, uc.PROT_ALL),    a.mem_write(R, stoh(e));    var u = r      , c = r + o1.length;    return a.emu_start(u, c, 0, 0),    a.reg_read_i32(uc.ARM_REG_R5)}function enc_pw(e) {    var _ = stoh(atob(getBase64Image("frei")))      , t = 4096      , r = 8192      , m = 12288      , R = new uc.Unicorn(uc.ARCH_ARM,uc.MODE_ARM);    R.reg_write_i32(uc.ARM_REG_R8, r),    R.reg_write_i32(uc.ARM_REG_R9, m),    R.reg_write_i32(uc.ARM_REG_R10, e.length),    R.mem_map(t, 4096, uc.PROT_ALL);    for (var a = 0; a < o2.length; a++)        R.mem_write(t + a, [_[o2[a]]]);    R.mem_map(r, 4096, uc.PROT_ALL),    R.mem_write(r, stoh(e)),    R.mem_map(m, 4096, uc.PROT_ALL);    var o = t      , u = t + o2.length;    return R.emu_start(o, u, 0, 0),    htos(R.mem_read(m, e.length))}function get_pw() {    for (var e = stoh(atob(getBase64Image("templar"))), _ = "", t = 0; t < o3.length; t++)        _ += String.fromCharCode(e[o3[t]]);    return _}```
UnicornJS is being used here, so we know that we need to extract the ARM code being used.To do this,```function getARM1(){  var x = stoh(atob(getBase64Image("frei")));  var output = new Array();  for(var i = 0; i < o2.length ; i++){    output[i] = x[o2[i]];  }  return output;} 
//Looking at o2, we observe that our output will be in integers. //Lets try converting them to hex values.
function toHexString(byteArray) {  return Array.from(byteArray, function(byte) {    return ('0' + (byte & 0xFF).toString(16)).slice(-2);  }).join('')}```By doing `toHexString(getARM1())`, we get this "0800a0e10910a0e10a20a0e10030a0e30050a0e30040d0e5010055e30100001a036003e2064084e0064084e2015004e20040c1e5010080e2011081e2013083e2020053e1f2ffffba0000a0e30010a0e30020a0e30030a0e30040a0e30050a0e30060a0e30070a0e30090a0e300a0a0e3"
We then paste this hex-string into an [online converter](http://armconverter.com/hextoarm/) to receive:
``` ; FROM test_pw:
    MOV R0, SB       ; R0 = SB, Static base register. This is a synonym for R9. #R0 = R9 = m. (the secret password is here)    MOV R1, SL       ; R1 = SL, Stack Limit register. This is a synonym for R10. #R1 = R10 = R (the input password is here)    MOV R3, R8       ; R8 = input password length    MOV R4, #0    MOV R5, #0    MOV IP, #0    LDRB  R2, [R0]       ; Load secret password    LDRB  R6, [R1]       ; Load input password     ADD R6, R6, #5       ; Will do +5    AND IP, R4, #1       ; ip == R4 and 1    CMP IP, #0               BEQ #0x34             ; Will jump when IP is 0, or rather when R4 is even     SUB R6, R6, #3        ; Will do -3 this when R4 is odd.    CMP R2, R6            ; 0x34 here, if R4 is even, just compare.    BNE #0x54             ; R2 needs == R6    ADD R0, R0, #1    ADD R1, R1, #1    ADD R4, R4, #1        ; Increment all. R4 is a counter    CMP R4, R3            ; Check if counter < input length    BLT #0x18    MOV R5, #1      ; We need this!    MOV R0, #0      ; 0x54 here    MOV R1, #0    MOV R2, #0    MOV R3, #0    MOV R4, #0    MOV R6, #0    MOV R7, #0    MOV R8, #0    MOV SB, #0    MOV SL, #0    MOV IP, #0
    ; Repeating this with enc_pw give us ;    ; FROM enc_pw:
    MOV R0, R8          ; R8 -> R0, R0 = 8192    MOV R1, SB          ; R1 = SB, Static base register. This is a synonym for R9. #R1 = R9 = m. (we should read final result from here)    MOV R2, SL          ; R2 = SL, Stack Limit register. This is a synonym for R10. #R2 = R10 = e.length (input length)    MOV R3, #0    MOV R5, #0    LDRB  R4, [R0]      ; Load register byte. #0x14 here    CMP R5, #1          ; IS R5 = 1?     BNE #0x28               AND R6, R3, #3          ADD R4, R4, R6    ADD R4, R4, #6      ; 0x28 is here. If R5 is 0, come here    AND R5, R4, #1      ; R5 == 1 if R4 is odd.    STRB  R4, [R1]      ; store register byte    ADD R0, R0, #1          ADD R1, R1, #1    ADD R3, R3, #1    CMP R3, R2    BLT #0x14           ; Go back if R3 < input length. R3 is a counter    MOV R0, #0    MOV R1, #0    MOV R2, #0    MOV R3, #0    MOV R4, #0    MOV R5, #0    MOV R6, #0    MOV R7, #0    MOV SB, #0    MOV SL, #0```
In order to find the required password, we do the following:```function findReqR6(){  var pw = stoh("XYzaSAAX_PBssisodjsal_sSUVWZYYYb"); //We found this string above, from get_pw();  var required = new Array();  for(var i = 0 ; i < pw.length; i ++ ){      var a = pw[i];      a = a - 5;            // We do this to find out what the original input needs to be.      if(i & 1 == 1){        a = a + 3;          // Because the test adds 5, and might sub 2 in some cases      }                     // according to the assembly above.      required[i] = a;  }  return required;}```
`htos(findReqR6())` Will give us ``` SWu_N?