BSides Delhi CTF 2019 - REV - reloop - Writeup

Hi,


The challenge file is here https://drive.google.com/file/d/1JRm-E1HRVU8EmAlhz1ajADmUEyk6hpF4/view

Following is my solver using Angr:


import angr
import commands

bin_name = "level"

print commands.getstatusoutput('tar xvf %s.tar; chmod +x %s'%(bin_name,bin_name))

iter = 0
key_addr = 0x10000
while True:
    print("Iteration %d"%iter)
    b = angr.Project(bin_name)
    state = b.factory.blank_state(addr=0x400865)
    state.regs.rdi = key_addr

    key_len = 0x15
    for i in range(key_len):
        v = state.solver.BVS('x{}'.format(i), 8)
        state.memory.store(state.regs.rdi + i,v)

    sm = b.factory.simulation_manager(state)

    try:
        correct_addr = 0x400000 | open(bin_name).read().index("\xEB\x05\xB8\x01\x00\x00\x00")
    except:
        print "FLAG: %s"%(commands.getstatusoutput('./level')[1])
        quit()

    sm.explore(find=correct_addr+2)

    key_state = sm.found[0]
    
    key_data = key_state.memory.load(key_addr, key_len - 1)

    for i in range(key_len):
        const_0 = key_data.get_byte(i) >= ord('a')
        const_1 = key_data.get_byte(i) <= ord('z')
        const_2 = key_data.get_byte(i) >= ord('A')
        const_3 = key_data.get_byte(i) <= ord('Z')
        const_4 = key_state.solver.And(const_0, const_1)
        const_5 = key_state.solver.And(const_2, const_3)
        key_state.add_constraints(key_state.solver.Or(const_4, const_5))      

    key = key_state.solver.eval(key_data, cast_to=bytes).strip(b'\0\n')
    print key
    print commands.getstatusoutput('chmod +x level; echo %s | ./level; tar xvf drop'%(key))
    iter+=1



Thanks :))

Nuit du Hack CTF Quals 2018 - AssemblyMe Rev300 Writeup

Hi,

I didn't publish a CTF writeup since a while and now I'm back with a write-up which demonstrates how I solved the task in few minutes :p

We were given a web page which asks for an authentification password.
http://assemblyme.challs.malice.fr

The goal is to reverse engineer the code and figure out  the correct password.

The steps I followed to solve the challenge were:

[+] Read Webpage source code
[+] Invoke the authentication function from Chrome console

Module["asm"]["_checkAuth"]("maro")
returns 1761
Module["asm"]["_checkAuth"]
ƒ 35() { [native code] }

[+] Download the Wasm file http://assemblyme.challs.malice.fr/index.wasm
[+] Decompile the wasm file to a C file using wasmdec https://github.com/wwwg/wasmdec

There are other alternatives but the wasmdec gave me the best result.

$wasmdec -i index.wasm -o index.c -m

[+] Looking at memory dump file index.c.mem.bin, I saw "Obfuscation" and "Encryption" related strings... I thought it will be a pain in the ass but...I tried another way
[+] Search for return value 1761 in index.c file only 2 occurences in  fn_25() function
[+] Seems that the function returns 1761 if the verification fails otherwise it returns 1690

...
if (    fn_47(local_0, 1616, 4);== 0) {
if (    fn_47(local_0 + 4, 1638, 4);== 0) {
if (    fn_47(local_0 + 8, 1610, 5);== 0) {
if (    fn_47(local_0 + 13, 1598, 4);== 0) {
if (    fn_47(local_0 + 17, 1681, 3);== 0) {
if (    fn_47(local_0 + 20, 1654, 9);== 0) {
global$1 = local_1;
return 1690;
} // <No else block>
} // <No else block>
} // <No else block>
} // <No else block>
} // <No else block>
} // <No else block>
...

fn_47 seems to be a strncmp like function:
[-] The first argument local_0 points to the input.
[-] The second argument is the index in memory
[-] The third atgument is number of bytes to compare.

[+] I learned from index.js file that to access memory I can use Module["buffer"]
[+] Get 4 bytes from memory at index 1616

new TextDecoder("utf-8").decode(Module["buffer"].slice(1616,1620))
"d51X"

[+] Dump the entire password

dec = new TextDecoder("utf-8")
dec.decode(Module["buffer"].slice(1616,1620)) + dec.decode(Module["buffer"].slice(1638,1638+4))+dec.decode(Module["buffer"].slice(1610,1610+5))+dec.decode(Module["buffer"].slice(1598,1598+4)) + dec.decode(Module["buffer"].slice(1681,1681+3))+ dec.decode(Module["buffer"].slice(1654,1654+9))
"d51XPox)1S0xk5S11W_eKXK,,,xie"

[+] Provide it to the web page gives
[+] Authentication is successful. The flag is NDH{password}

Maybe isn't the intended solution regarding the encryption and the obfuscation but anyway I managed to authenticate myself :p

Flag: NDH{d51XPox)1S0xk5S11W_eKXK,,,xie}

Cheers !

European Cyber Week CTF 2017 - Red Diamond Writeup

Hi,

European Cyber Week CTF is a contest exclusively reserved for "European" students. 
I'am not eligible to play but I joined the CTF later in order to keep practicing and learn new stuff .

Red Diamond in the Binary category was the hardest task regarding the number of players who solved it (7 solves). 

The given file was a Windows binary for AMD64 !

I imported the binary file into IDAPro, then, with a top-down look at the string list I saw many paths to mruby header files such as /home/FlL/mruby1.3.0/mruby/include/mruby/value.h

I "googled" mruby. It is a lightweight implementation of the Ruby language. From this point I figured out that my mission will be hard because I never wrote a single line of ruby code. But remember that my goal is to learn new stuff ! So ! Let's do it !

Mruby can be linked and embedded within an application, which is the case.  In addition, Ruby programs can be compiled into byte code using the mruby compiler.

Typically the challenge file is an application embedding a mruby bytecode and an interpreter.

I spent some time reading about MRB file format and RiteVM.

MRB file starts with RITE00... as magic number. I searched that pattern inside the binary and, yes !,  I found it.

The bytecode program starts from offset 0x80A20 in the file (0x100482020 offset in memory)

I dumped the bytecode to a red_diamond.mrb file.

Mruby package provides an interpreter program "mruby". I downloaded mruby sources and I compiled it.


root@maro-vm:~/ecw# git clone https://github.com/mruby/mruby.git
root@maro-vm:~/ecw# cd mruby/
root@maro-vm:~/ecw/mruby# ./minirake


I tried to run the binary file.


root@maro-vm:~/ecw/mruby# ./bin/mruby -b red_diamond.mrb
CRACKME!
NoMethodError: undefined method 'usleep' for main


Well ! I got a message printed to screen, however the program crashed due to call to undefined function usleep.

I added the sleep module from here https://github.com/matsumotory/mruby-sleep ! But instead of specifying the github path, I cloned the module source and specified its path in the disk to build_config.rb. I did this in order to be able to easily alter the code if needed.


root@maro-vm:~/ecw/mruby# git clone https://github.com/matsumotory/mruby-sleep.git
root@maro-vm:~/ecw/mruby# nano build_config.rb
MRuby::Build.new do |conf|
   conf.gem 'mruby-sleep'
...

I did the same thing for the other requested modules. Those are, mruby-eval, mruby-iconv, mruby-md5 and mruby-pack.


MRuby::Build.new do |conf|
...
  conf.gem :core => 'mruby-eval'
  conf.gem 'mruby-sleep'
  conf.gem :git => 'https://github.com/mattn/mruby-iconv.git'
  conf.gem :git => 'https://github.com/mattn/mruby-md5.git'
  conf.gem 'mruby-pack'
...


Then I compiled again mruby.

root@maro-vm:~/ecw/mruby# ./minirake clean
root@maro-vm:~/ecw/mruby# ./minirake


I tried again to run the program.

root@maro-vm:~/ecw/mruby#./bin/mruby -b red_diamond.mrb
CRACKME!
Let me check if you deserve a flag ...
NO :(


Good ! works fine !

Using -v option it is possible to see VM codes of the program.

root@maro-vm:~/ecw/mruby#./bin/mruby -b -v red_diamond.mrb

mruby 1.3.0 (2017-7-4)
irep 0x555555873e30 nregs=7 nlocals=3 pools=11 syms=12 reps=2
      000 OP_LOADSELF   R3
      001 OP_STRING     R4      L(0)    ; "CRACKME!"
      002 OP_SEND       R3      :puts   1
      003 OP_LOADSELF   R3
      004 OP_LOADSELF   R4
      005 OP_LOADL      R5      L(1)    ; 400000
      006 OP_SEND       R4      :rand   1
      007 OP_SEND       R3      :usleep 1
      008 OP_LOADSELF   R3
      009 OP_STRING     R4      L(2)    ; "Let me check if you deserve a flag ..."
      010 OP_SEND       R3      :puts   1
      011 OP_LOADSELF   R3
      012 OP_LOADSELF   R4
      013 OP_LOADL      R5      L(3)    ; 600000
      014 OP_SEND       R4      :rand   1
      015 OP_LOADL      R5      L(4)    ; 2000000
      016 OP_ADD        R4      :+      1
      017 OP_SEND       R3      :usleep 1
      018 OP_ONERR      050
      019 OP_TCLASS     R3
      020 OP_LAMBDA     R4      I(+1)   method
      021 OP_METHOD     R3      :found?
      022 OP_OCLASS     R3
      023 OP_LOADNIL    R4
      024 OP_CLASS      R3      :String
      025 OP_EXEC       R3      I(+2)
      026 OP_LOADSELF   R3
      027 OP_SEND       R3      :found? 0
      028 OP_JMPNOT     R3      046
      029 OP_LOADSELF   R3
      030 OP_STRING     R4      L(5)    ; "YES :)"
      031 OP_SEND       R3      :puts   1
      032 OP_GETCONST   R3      :MD5
      033 OP_STRING     R4      L(6)    ; "\342\235\250\342\225\257\302\260\342\226\241\302\260\342\235\251\342\225\257\357\270\265\342\224\273\342\224\201\342\224\273"
      034 OP_GETGLOBAL  R5      :$salt
      035 OP_ADD        R4      :+      1
      036 OP_SEND       R3      :md5_hex        1
      037 OP_MOVE       R1      R3              ; R1:flag
      038 OP_LOADSELF   R3
      039 OP_STRING     R4      L(7)    ; "\tflag is: '"
      040 OP_MOVE       R5      R1              ; R1:flag
      041 OP_STRCAT     R4      R5
      042 OP_STRING     R5      L(8)    ; "'"
      043 OP_STRCAT     R4      R5
      044 OP_SEND       R3      :puts   1
      045 OP_JMP        049
      046 OP_LOADSELF   R3
      047 OP_STRING     R4      L(9)    ; "NO :("
      048 OP_SEND       R3      :puts   1
      049 OP_JMP        069
      050 OP_RESCUE     R3
      051 OP_GETCONST   R4      :Exception
      052 OP_RESCUE     R3      R4      cont
      053 OP_JMPIF      R4      055
      054 OP_JMP        068
      055 OP_MOVE       R2      R3              ; R2:e
      056 OP_LOADSELF   R3
      057 OP_STRING     R4      L(10)   ; "fail!"
      058 OP_SEND       R3      :puts   1
      059 OP_LOADSELF   R3
      060 OP_MOVE       R4      R2              ; R2:e
      061 OP_SEND       R4      :message        0
      062 OP_SEND       R3      :puts   1
      063 OP_LOADSELF   R3
      064 OP_MOVE       R4      R2              ; R2:e
      065 OP_SEND       R4      :backtrace      0
      066 OP_SEND       R3      :puts   1
      067 OP_JMP        070
      068 OP_RAISE      R3
      069 OP_POPERR     1
      070 OP_STOP

irep 0x5555558743e0 nregs=25 nlocals=5 pools=10 syms=19 reps=1
      000 OP_ENTER      0:0:0:0:0:0:0
      001 OP_STRING     R5      L(0)    ; "utf-0"
      002 OP_STRING     R6      L(1)    ; "utf-9"
      003 OP_RANGE      R5      R5      0
      004 OP_SEND       R5      :to_a   0
      005 OP_STRING     R6      L(2)    ; "utf-10"
      006 OP_STRING     R7      L(3)    ; "utf-30"
      007 OP_RANGE      R6      R6      0
      008 OP_SEND       R6      :to_a   0
      009 OP_ADD        R5      :+      1
      010 OP_MOVE       R2      R5              ; R2:"\302\265"
      011 OP_LOADSELF   R5
      012 OP_GETCONST   R6      :Iconv
      013 OP_MOVE       R7      R2              ; R2:"\302\265"
      014 OP_LOADI      R8      8
      015 OP_SEND       R7      :[]     1
      016 OP_MOVE       R8      R2              ; R2:"\302\265"
      017 OP_LOADI      R9      16
      018 OP_SEND       R8      :[]     1
      019 OP_LOADI      R9      254
      020 OP_LOADI      R10     255
      021 OP_LOADI      R11     0
      022 OP_LOADI      R12     65
      023 OP_LOADI      R13     0
      024 OP_LOADI      R14     82
      025 OP_LOADI      R15     0
      026 OP_LOADI      R16     71
      027 OP_LOADI      R17     0
      028 OP_LOADI      R18     86
      029 OP_LOADI      R19     0
      030 OP_LOADI      R20     91
      031 OP_LOADI      R21     0
      032 OP_LOADI      R22     50
      033 OP_LOADI      R23     0
      034 OP_LOADI      R24     93
      035 OP_ARRAY      R9      R9      16
      036 OP_STRING     R10     L(4)    ; "C*"
      037 OP_SEND       R9      :pack   1
      038 OP_SEND       R6      :conv   3
      039 OP_SEND       R5      :eval   1
      040 OP_MOVE       R3      R5              ; R3:"\302\244"
      041 OP_JMPNOT     R5      043
      042 OP_JMP        045
      043 OP_LOADNIL    R5
      044 OP_RETURN     R5      normal
      045 OP_LOADT      R4                      ; R4:"\302\247"
      046 OP_MOVE       R5      R3              ; R3:"\302\244"
      047 OP_STRING     R6      L(4)    ; "C*"
      048 OP_SEND       R5      :unpack 1
      049 OP_MOVE       R2      R5              ; R2:"\302\265"
      050 OP_MOVE       R5      R3              ; R3:"\302\244"
      051 OP_LOADI      R6      0
      052 OP_LOADI      R7      7
      053 OP_RANGE      R6      R6      0
      054 OP_SEND       R5      :[]     1
      055 OP_MOVE       R3      R5              ; R3:"\302\244"
      056 OP_MOVE       R5      R4              ; R4:"\302\247"
      057 OP_JMPNOT     R5      062
      058 OP_MOVE       R5      R3              ; R3:"\302\244"
      059 OP_SEND       R5      :first  0
      060 OP_STRING     R6      L(5)    ; "W"
      061 OP_EQ         R5      :==     1
      062 OP_MOVE       R4      R5              ; R4:"\302\247"
      063 OP_JMPNOT     R5      068
      064 OP_MOVE       R5      R3              ; R3:"\302\244"
      065 OP_SEND       R5      :last   0
      066 OP_STRING     R6      L(6)    ; "a"
      067 OP_EQ         R5      :==     1
      068 OP_MOVE       R4      R5              ; R4:"\302\247"
      069 OP_JMPNOT     R5      077
      070 OP_MOVE       R5      R3              ; R3:"\302\244"
      071 OP_LOADI      R6      1
      072 OP_ADDI       R6      :+      1
      073 OP_SEND       R5      :[]     1
      074 OP_MOVE       R6      R3              ; R3:"\302\244"
      075 OP_SEND       R6      :first  0
      076 OP_EQ         R5      :==     1
      077 OP_MOVE       R4      R5              ; R4:"\302\247"
      078 OP_JMPNOT     R5      085
      079 OP_MOVE       R5      R3              ; R3:"\302\244"
      080 OP_LOADI      R6      1
      081 OP_SEND       R5      :[]     1
      082 OP_LOADI      R6      0
      083 OP_SEND       R6      :to_s   0
      084 OP_EQ         R5      :==     1
      085 OP_MOVE       R4      R5              ; R4:"\302\247"
      086 OP_JMPNOT     R5      095
      087 OP_MOVE       R5      R3              ; R3:"\302\244"
      088 OP_LOADI      R6      3
      089 OP_SEND       R5      :[]     1
      090 OP_SEND       R5      :to_i   0
      091 OP_SUBI       R5      :-      1
      092 OP_LOADI      R6      2
      093 OP_ADDI       R6      :+      2
      094 OP_EQ         R5      :==     1
      095 OP_MOVE       R4      R5              ; R4:"\302\247"
      096 OP_JMPNOT     R5      103
      097 OP_MOVE       R5      R3              ; R3:"\302\244"
      098 OP_STRING     R6      L(7)    ; "4"
      099 OP_SEND       R6      :to_i   0
      100 OP_SEND       R5      :[]     1
      101 OP_STRING     R6      L(8)    ; "9"
      102 OP_EQ         R5      :==     1
      103 OP_MOVE       R4      R5              ; R4:"\302\247"
      104 OP_JMPNOT     R5      113
      105 OP_MOVE       R5      R3              ; R3:"\302\244"
      106 OP_LOADI      R6      5
      107 OP_LOADI      R7      -1
      108 OP_RANGE      R6      R6      0
      109 OP_SEND       R5      :[]     1
      110 OP_SEND       R5      :first  0
      111 OP_STRING     R6      L(9)    ; "("
      112 OP_EQ         R5      :==     1
      113 OP_MOVE       R4      R5              ; R4:"\302\247"
      114 OP_JMPNOT     R5      122
      115 OP_MOVE       R5      R3              ; R3:"\302\244"
      116 OP_LOADSYM    R6      :[]
      117 OP_LOADI      R7      -2
      118 OP_SEND       R5      :send   2
      119 OP_SEND       R5      :to_f   0
      120 OP_LOADI      R6      8
      121 OP_EQ         R5      :==     1
      122 OP_MOVE       R4      R5              ; R4:"\302\247"
      123 OP_LOADI      R5      8
      124 OP_LAMBDA     R6      I(+1)   block
      125 OP_SENDB      R5      :times  0
      126 OP_MOVE       R5      R4              ; R4:"\302\247"
      127 OP_JMPNOT     R5      132
      128 OP_MOVE       R5      R2              ; R2:"\302\265"
      129 OP_SEND       R5      :size   0
      130 OP_LOADI      R6      16
      131 OP_EQ         R5      :==     1
      132 OP_MOVE       R4      R5              ; R4:"\302\247"
      133 OP_SETGLOBAL  :$salt  R3              ; R3:"\302\244"
      134 OP_RETURN     R4      normal          ; R4:"\302\247"

irep 0x555555874a40 nregs=8 nlocals=3 pools=0 syms=6 reps=0
      000 OP_ENTER      1:0:0:0:0:0:0
      001 OP_GETUPVAR   R3      4       0
      002 OP_JMPNOT     R3      015
      003 OP_GETUPVAR   R3      2       0
      004 OP_MOVE       R4      R1              ; R1:n
      005 OP_SEND       R3      :[]     1
      006 OP_GETUPVAR   R4      2       0
      007 OP_MOVE       R5      R1              ; R1:n
      008 OP_SEND       R5      :-@     0
      009 OP_SUBI       R5      :-      1
      010 OP_SEND       R4      :[]     1
      011 OP_MOVE       R5      R1              ; R1:n
      012 OP_ADDI       R5      :+      1
      013 OP_SEND       R4      :^      1
      014 OP_EQ         R3      :==     1
      015 OP_SETUPVAR   R3      4       0
      016 OP_RETURN     R3      normal

irep 0x555555874b30 nregs=3 nlocals=1 pools=0 syms=2 reps=2
      000 OP_TCLASS     R1
      001 OP_LAMBDA     R2      I(+1)   method
      002 OP_METHOD     R1      :first
      003 OP_TCLASS     R1
      004 OP_LAMBDA     R2      I(+2)   method
      005 OP_METHOD     R1      :last
      006 OP_LOADSYM    R1      :last
      007 OP_RETURN     R0      normal

irep 0x555555874c20 nregs=5 nlocals=2 pools=0 syms=1 reps=0
      000 OP_ENTER      0:0:0:0:0:0:0
      001 OP_LOADSELF   R2
      002 OP_LOADI      R3      0
      003 OP_SEND       R2      :[]     1
      004 OP_RETURN     R2      normal

irep 0x555555874ce0 nregs=5 nlocals=2 pools=0 syms=1 reps=0
      000 OP_ENTER      0:0:0:0:0:0:0
      001 OP_LOADSELF   R2
      002 OP_LOADI      R3      -1
      003 OP_SEND       R2      :[]     1
      004 OP_RETURN     R2      normal


Sadly there is not decompiler for the bytecode. I spent to much time reading about RiteVM opcodes and play with the interactive mruby shell "mirb" to understand what the program does.

The program starts by printing "CRACKME!" to screen, sleeps a while (random seconds), prints "Let me check if you deserve a flag ...", sleeps a while again perform a test on found method result then prints "NO ! :(" and exits.

If the found method returns 1 then it loads the content of $salt global variable, append it to "\342\235\250\342\225\257\302\260\342\226\241\302\260\342\235\251\342\225\257\357\270\265\342\224\273\342\224\201\342\224\273", compute the md5 over it, hex encode it and prints flag is and the flag value.

If found returns 0, then "NO :(" is printed and the program exists.

The program author has extended the String class by adding 3 methods , first, last and found.

It is obvious that irep 0x555555874c20 is the implementation of "first" method since it returns the element with index -1 of an array.
irep 0x555555874ce0 is for "last" method because it returns the element with index -1 of an array.

irep 0x5555558743e0 is the implementation of found method.

It reads the second argument passed to the program using eval(ARGV[2]) then the argument value is checked if it is the expected value or not.

It reads the first element using the defined first method and check if it is equal to "W", if it is the case, it loads the last character and check if it is "a" if so, further checks is done.

Then the third character (index incremented by 2) is tested if it is equal to the first character.

Next, the index is decremented by 1 to test if the first character is equal to "0"

The fourth character must be equal to "4" + 1 = "5"

The fifth character must be equal to "9"

The sixth character must be "("

The seventh character must be "8"

Hence the correct password is W0W59(8a

Finally the :$salt global variable is set to eval(ARGV[2]) which is the second argument.

The function return 1 if the argument satisfies the test otherwise it returns 0.

The strange thing is that by feeding the correct input to the program it kept saying NO ! :(

And since I'm sure that what I did is correct ! I putted the flag in the requested format and I submitted it to the platform and BOM! it is accepted ! and that's why maybe players failed to solve it ! or maybe that the there is many solutions for this challenge also.

Flag was ECW{983b428e721bcfceabf6c77d9e819d8d}

And yes the author was right !

In [5]: print "\342\235\250\342\225\257\302\260\342\226\241\302\260\342\235\251\342\225\257\357\270\265\342\224\273\342\224\201\342\224\273"
❨╯°□°❩╯︵┻━┻




Another way to solve this challenge could be dealing with it as a blackbox by count the number of instruction executed for each input.

This could not work here since the characters are not checked in order. You need in this case to trace the program execution. After googling a while, I found an interesting module which is "mruby-debug-example" it hooks the VM function which fetches the opcodes and dump it.

The module can be downloaded from here https://github.com/masuidrive/mruby-debug-example

Add it to your build_config.rb and compile again using minirake.

Now by running the program you can get a full execution trace !

...
0x555555876eec: OP_LOADSELF     R3
0x555555876ef0: OP_LOADSELF     R4
0x555555876ef4: OP_LOADL        R5      L(1)
0x555555876ef8: OP_SEND R4      :rand   1
0x555555876efc: OP_SEND R3      :usleep 1
0x555555876f00: OP_LOADSELF     R3
0x555555876f04: OP_STRING       R4      "Let me check if you deserve a flag ..."
0x555555876f08: OP_SEND R3      :puts   1
0x5555555ebe6c: OP_ENTER        0:0:1:0:0:0:0
0x5555555ebe70: OP_LOADI        R3      0
0x5555555ebe74: OP_MOVE R6      R1
0x5555555ebe78: OP_SEND R6      :size   0
0x5555555ebe7c: OP_MOVE R4      R6
0x5555555ebe80: OP_JMP          021
0x5555555ebed4: OP_MOVE R6      R3
0x5555555ebed8: OP_MOVE R7      R4
0x5555555ebedc: OP_LT   R6      :<      1
0x5555555ebee0: OP_JMPIF        R6      -23
0x5555555ebe84: OP_MOVE R6      R1
0x5555555ebe88: OP_MOVE R7      R3
0x5555555ebe8c: OP_SEND R6      :[]     1
0x5555555ebe90: OP_SEND R6      :to_s   0
0x5555555ebe94: OP_MOVE R5      R6
0x5555555ebe98: OP_LOADSELF     R6
0x5555555ebe9c: OP_MOVE R7      R5
0x5555555ebea0: OP_SEND R6      :__printstr__   1
Let me check if you deserve a flag ...0x5555555ebea4: OP_MOVE   R6      R5
0x5555555ebea8: OP_LOADI        R7      -1
0x5555555ebeac: OP_SEND R6      :[]     1
0x5555555ebeb0: OP_STRING       R7      "\n"
0x5555555ebeb4: OP_SEND R6      :!=     1
0x5555555ebeb8: OP_JMPNOT       R6      004
0x5555555ebebc: OP_LOADSELF     R6
0x5555555ebec0: OP_STRING       R7      "\n"
0x5555555ebec4: OP_SEND R6      :__printstr__   1
...


The author maybe added the sleep methods to prevent bruteforce ! You can at this level modify mrb_sleep.c source file and modufy the usleep implementation and make it sleeps for 0 seconds for example.


93:    if (mrb_fixnum_p(argv[0]) && mrb_fixnum(argv[0]) >= 0) {
94:        usleep(0); //usleep(mrb_fixnum(argv[0]));
95:    } else {
96:        mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive");
97:    }


You can than write a sample python script to bruteforce the password !

Here is a python script which can be used to find the first character.


import subprocess

for i in range(32,127):
    s = chr(i)+"A"*7
    p = subprocess.Popen("./bin/mruby -b /root/red_diamond.mrb 0 0 '"+s+"'", shell=True, stdou$
    print "[+] %c -> %d"%(chr(i), len(p.stdout.readlines()))


...
[+] L -> 1821
[+] M -> 1821
[+] N -> 1821
[+] O -> 1821
[+] P -> 1821
[+] Q -> 1821
[+] R -> 1821
[+] S -> 1821
[+] T -> 1821
[+] U -> 1821
[+] V -> 1821
[+] W -> 1830
[+] X -> 1821
[+] Y -> 1821
[+] Z -> 1821
[+] [ -> 1821
[+] \ -> 1821
[+] ] -> 1821
[+] ^ -> 1821
[+] _ -> 1821
...


Found ! the first character is W.

But keep in mind that this way is good to quickly solve a CTF task but in general it is much leet to understand how things work (VM implementation etc..) !

That's all!

Follow me twitter

Maro

Kaspersky Industrial CTF Quals 2017 - rev700 - Web Keygen Writeup

Hi,

Typically this was not really a web task but a reversing one instead. The task implements a relatively small and straightforward custom VM interpreter using Javascript.

crackme! http://95.85.55.168/vmctf.html

Here is my solver in case you want to skip the explanation:
https://pastebin.com/2qKjQ7wy

Obviously, we need to reverse the VM implementation before we can start reversing the VM bytecode.

A top-down look at the obfuscated source code shows that CoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCoCo function fetch an opcode and dispatches the opcode to the corresponding operation.

Following is the list of the opcode with corresponding x86 operation.

1 - PUSH
2 -  MOV
3 - SUB
4 - CALL
5 - ADD
6 - CMP
7 - JNZ
8 - JMP
9 - JNO
10 - MOVU
11 - XOR
12 - DIV/MOD
13 - OR
14 - POP
15 - RET
16 - JZ
17 - AND
18 - SHR

To get an execution trace, we modify the code and add some logging messages to all operations.

Let's take the XOR operation as example.

    nextInst()
    {
        var opcode = this.fetch();
        switch(opcode)
        {
            case 11:
                var r1 = this.REGSZ();
                var r2 = this.REGSZ();                
                var p = r1.LOAD();
  var q = r2.LOAD();
                var acc = p ^ q;    
  console.log("XOR "+p+", "+q);
                r1.STORE(acc);             
                break;
 
        }
    }



It is enough to add logging messages to all operations and execute the script to get a readable trace and understand what the program does.

Here is the de-obfuscated version of the VM implementation


class Reg0
{
    constructor(vm)
    {
        this.stack = vm.stack;
        this.v3 = vm.fetch1();        
        this.utype = vm.fetch1();        
        this.v5 = vm.fetch1();
    }
    
    
    
    LOAD()
    {
        switch( this.utype )
        {
            case 1:
                return this.stack.getUint8(this.v3)*this.v5;
            case 2:
                return this.stack.getUint16(this.v3)*this.v5;
            case 4:
                return this.stack.getUint32(this.v3)*this.v5;
        }     
    }
    
    STORE(arg)
    {        
        switch( this.utype )
        {
            case 1:
               this.stack.setUint8(this.v3,arg);
               break;
            case 2:
               this.stack.setUint16(this.v3,arg);
               break;
            case 4:
               this.stack.setUint32(this.v3,arg);
               break;
        }
        this.v5 = 1;
    }    
}

class Reg1
{
    constructor(vm)
    {
        this.arg = vm.fetch4();
    }
    

    LOAD()
    {
        return this.arg;       
    }
    
    STORE(arg)
    {
    }
}

class Reg
{
    constructor(vm)
    {      
        this.v3 = 0;
        
        var arg = vm.fetch1(); 
        
        while( arg-- )
        {
            this.v3 += vm.fetch().LOAD();            
        }
        
        this.v3 &= 0xFFFFFFFF;
        
        this.val = vm.val;
        this.stack = vm.stack;
    }
}

class Reg8 extends Reg
{


    LOAD()
    {          
        return this.val.getUint8(this.v3);
    }
    
    STORE(arg)
    {
        this.val.setUint8(this.v3,arg);
    }        
}

class Reg32 extends Reg
{



    LOAD()
    {          
        return this.val.getUint32(this.v3);
    }
    
    STORE(arg)
    {
        this.val.setUint32(this.v3,arg);
    }        
}

class VM
{
    constructor(mem)
    {
        this.val = new DataView(mem.buffer);
        this.IP = 0;
        this.stack = new DataView(new ArrayBuffer(32));
        var loc = mem.length;
        this.stack.setInt32(16,loc);
        
        this.ZF = false;
        this.OF = false;        
    }
    
    
    fetch4()
    {
        var arg = this.val.getUint32(this.IP);
        this.IP += 4;
        return arg;        
    }
    
    fetch1()
    {
        var arg = this.val.getUint8(this.IP);
        this.IP++;
        return arg;
    }
    
    fetch()
    {
        var arg = this.fetch1();
        switch(arg )
        {
            case 1:
                return new Reg0(this);                
            case 2:
                return new Reg1(this);
            case 3:
                return new Reg8(this);
            case 4:
                return new Reg32(this);
        }
        return null;
    }
    
    
    push(arg)
    {
        var loc = this.stack.getInt32(16) - 4;        
        this.stack.setInt32(16,loc);
        this.val.setUint32(loc,arg)
        return loc;
    }
    
    pop()
    {
        var loc = this.stack.getInt32(16);
        var arg = this.val.getUint32(loc);
        loc += 4;
        this.stack.setInt32(16,loc);        
        return arg;
    }


    nextInst()
    {
        var opcode = this.fetch1();
        switch(opcode)
        {
            case 4:
                var r1 = this.fetch();                
                var acc = r1.LOAD();
                console.log("call, "+acc);
                this.push(this.IP);
                this.IP = acc;    
                break;
            case 2:
                var r1 = this.fetch();
                var r2 = this.fetch();                
                
    var p = r2.LOAD();   
    console.log("mov r1, "+p);
                r1.STORE(p);
                break;
            case 8:
                var r1 = this.fetch();                
                
                this.IP = r1.LOAD();
    console.log("jmp, "+this.IP);
                break;
            case 10:            
                var r1 = this.fetch();
                var r2 = this.fetch();                
                var q = r2.LOAD();
                r1.STORE(q>>>0);
    
    console.log("movu r1, "+ q);
                                
                break;
            case 5:
                var r1 = this.fetch();
                var r2 = this.fetch();                
                var p = r1.LOAD();
    var q = r2.LOAD();
                var acc = p + q;
    
    console.log("add "+p+", "+q);
                                
                this.OF = new Boolean(acc>>32);

                r1.STORE(acc);
                break;
            case 18:
                var r1 = this.fetch();
                var r2 = this.fetch();                
                var p = r1.LOAD();
    var q = r2.LOAD();
                var acc = p >>> q;
    
    console.log("rsh "+p+", "+q)
    
                r1.STORE(acc);     
                break;
            case 11:
                var r1 = this.fetch();
                var r2 = this.fetch();                
                var p = r1.LOAD();
    var q = r2.LOAD();
                var acc = p ^ q;
    
    console.log("xor "+p+", "+q);
                r1.STORE(acc);             
                break;
            case 3:        
                var r1 = this.fetch();
                var r2 = this.fetch();                
                var p = r1.LOAD();
    var q = r2.LOAD();
                var acc = p + ((~q) + 1);
    
    console.log("sub "+p+", "+q);
                this.OF = new Boolean(acc>>32);
                    
                r1.STORE(acc);
                break;
            case 15:
                var r1 = this.fetch();
                var acc = this.pop();                
                this.IP = acc;
    console.log("ret");
                break;
            case 14:
                var r1 = this.fetch();
                console.log("pop");
                var acc = this.pop();                                
                r1.STORE(acc);
                break;
            case 17:
                var r1 = this.fetch();
                var r2 = this.fetch();
                var p = r1.LOAD();
    var q = r2.LOAD();
    
                var acc = p & q; 

                console.log("and "+p+", "+q);    
                r1.STORE(acc);
                break;
            case 9:        
                var r1 = this.fetch();                     
                if(this.OF == false)                
                {
                    this.IP = r1.LOAD();    
                }                
                break;
            case 1:
                var r1 = this.fetch();                
                var p = r1.LOAD();
                this.push(p);
    console.log("push "+p);
                break;
            case 6:
                var r1 = this.fetch();
                var r2 = this.fetch();                
                var p = r1.LOAD();
    var q = r2.LOAD()
                this.ZF = ( p == q);
    
    console.log("cmp "+p+", "+q);
                
                var acc = r1.LOAD() + ((~r2.LOAD()) + 1);
                this.OF = new Boolean(acc>>32);
                break;
            case 7:                                
                var r1 = this.fetch();  
                
    console.log("jz "+this.IP);
    
                if(this.ZF == false)                
                {
                    this.IP = r1.LOAD();    
                }
    else
     console.log("[+] Correct Password");
                break;
            case 13:
                var r1 = this.fetch();
                var r2 = this.fetch();
                var p = r1.LOAD();
    var q = r2.LOAD()
                var acc = p | q;  
                console.log("or "+p+", "+q);    
                r1.STORE(acc);
                break;
            case 16:                
                var r1 = this.fetch();                
                if(this.ZF == true)          
                {
                    this.IP = r1.LOAD();         
     console.log("jnz "+this.IP);     
                }            
                break;
            case 12:
                var r1 = this.fetch();
                   
                var arg = (this.stack.getInt32(8) << 32) | this.stack.getInt32(0);
    var p = r1.LOAD();
                var loc = arg / p;
    
    console.log("div "+arg+", "+p); 
    
                this.stack.setInt32(0,loc);
    var p = r1.LOAD();
                var loc = arg % p;
    console.log("mod "+arg+", "+p); 
                this.stack.setInt32(8,loc);                
                break;
        }
    }
}

function GetFlag(input)
{
    var mem = new Uint8Array([1,1,20,4,1,2,1,20,4,1,1,16,4,1,3,1,16,4,1,2,0,0,0,44,1,1,24,4,1,2,3,2,2,255,255,255,212,1,20,4,1,2,0,0,0,115,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,1,2,0,0,0,20,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,2,2,0,0,0,32,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,3,2,0,0,0,23,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,4,2,0,0,0,2,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,5,2,0,0,0,98,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,6,2,0,0,0,42,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,7,2,0,0,0,119,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,8,2,0,0,0,121,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,9,2,0,0,0,29,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,10,2,0,0,0,33,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,11,2,0,0,0,113,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,12,2,0,0,0,112,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,13,2,0,0,0,103,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,14,2,0,0,0,94,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,15,2,0,0,0,6,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,16,2,0,0,0,0,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,17,2,0,0,0,30,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,18,2,0,0,0,91,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,19,2,0,0,0,113,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,20,2,0,0,0,125,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,21,2,0,0,0,103,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,22,2,0,0,0,95,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,23,2,0,0,0,113,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,24,2,0,0,0,123,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,25,2,0,0,0,111,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,26,2,0,0,0,80,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,27,2,0,0,0,2,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,28,2,0,0,0,119,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,29,2,0,0,0,103,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,30,2,0,0,0,90,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,31,2,0,0,0,115,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,32,2,0,0,0,9,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,33,2,0,0,0,25,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,34,2,0,0,0,39,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,35,2,0,0,0,1,2,3,3,2,255,255,255,212,1,20,4,1,2,0,0,0,36,2,0,0,0,5,1,2,0,0,0,8,2,1,0,4,1,4,2,2,0,0,0,8,1,20,4,1,1,1,0,4,1,1,2,18,52,86,120,4,2,0,0,4,199,5,1,16,4,1,2,0,0,0,12,6,1,0,4,1,2,51,229,174,64,7,2,0,0,4,164,2,4,2,2,255,255,255,252,1,20,4,1,2,0,0,0,0,2,4,2,2,255,255,255,252,1,20,4,1,2,0,0,0,0,8,2,0,0,3,217,2,1,4,4,1,4,2,2,255,255,255,252,1,20,4,1,5,1,4,4,1,2,0,0,0,1,2,4,2,2,255,255,255,252,1,20,4,1,1,4,4,1,6,4,2,2,255,255,255,252,1,20,4,1,2,0,0,0,37,9,2,0,0,4,149,2,1,8,4,1,4,2,2,255,255,255,252,1,20,4,1,10,1,4,4,1,3,3,2,255,255,255,212,1,20,4,1,1,8,4,1,2,1,0,4,1,4,2,2,255,255,255,252,1,20,4,1,11,1,8,4,1,1,8,4,1,2,1,24,4,1,2,0,0,0,8,12,1,24,4,1,2,1,0,4,1,4,2,2,0,0,0,8,1,20,4,1,10,1,8,4,1,3,2,1,0,4,1,1,8,4,1,11,1,4,4,1,1,8,4,1,2,1,0,4,1,4,2,2,0,0,0,12,1,20,4,1,5,1,0,4,1,4,2,2,255,255,255,252,1,20,4,1,2,3,1,1,0,4,1,1,7,1,1,8,2,0,0,3,175,11,1,0,4,1,1,0,4,1,8,2,0,0,4,174,13,1,0,4,1,2,255,255,255,255,14,1,24,4,1,2,1,16,4,1,1,20,4,1,14,1,20,4,1,15,2,0,0,0,0,1,1,20,4,1,2,1,20,4,1,1,16,4,1,3,1,16,4,1,2,0,0,4,8,2,4,2,2,255,255,251,248,1,20,4,1,2,0,0,0,0,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,4,2,119,7,48,150,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,8,2,238,14,97,44,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,12,2,153,9,81,186,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,16,2,7,109,196,25,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,20,2,112,106,244,143,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,24,2,233,99,165,53,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,28,2,158,100,149,163,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,32,2,14,219,136,50,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,36,2,121,220,184,164,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,40,2,224,213,233,30,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,44,2,151,210,217,136,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,48,2,9,182,76,43,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,52,2,126,177,124,189,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,56,2,231,184,45,7,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,60,2,144,191,29,145,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,64,2,29,183,16,100,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,68,2,106,176,32,242,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,72,2,243,185,113,72,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,76,2,132,190,65,222,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,80,2,26,218,212,125,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,84,2,109,221,228,235,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,88,2,244,212,181,81,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,92,2,131,211,133,199,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,96,2,19,108,152,86,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,100,2,100,107,168,192,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,104,2,253,98,249,122,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,108,2,138,101,201,236,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,112,2,20,1,92,79,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,116,2,99,6,108,217,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,120,2,250,15,61,99,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,124,2,141,8,13,245,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,128,2,59,110,32,200,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,132,2,76,105,16,94,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,136,2,213,96,65,228,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,140,2,162,103,113,114,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,144,2,60,3,228,209,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,148,2,75,4,212,71,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,152,2,210,13,133,253,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,156,2,165,10,181,107,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,160,2,53,181,168,250,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,164,2,66,178,152,108,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,168,2,219,187,201,214,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,172,2,172,188,249,64,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,176,2,50,216,108,227,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,180,2,69,223,92,117,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,184,2,220,214,13,207,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,188,2,171,209,61,89,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,192,2,38,217,48,172,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,196,2,81,222,0,58,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,200,2,200,215,81,128,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,204,2,191,208,97,22,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,208,2,33,180,244,181,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,212,2,86,179,196,35,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,216,2,207,186,149,153,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,220,2,184,189,165,15,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,224,2,40,2,184,158,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,228,2,95,5,136,8,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,232,2,198,12,217,178,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,236,2,177,11,233,36,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,240,2,47,111,124,135,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,244,2,88,104,76,17,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,248,2,193,97,29,171,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,0,252,2,182,102,45,61,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,0,2,118,220,65,144,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,4,2,1,219,113,6,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,8,2,152,210,32,188,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,12,2,239,213,16,42,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,16,2,113,177,133,137,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,20,2,6,182,181,31,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,24,2,159,191,228,165,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,28,2,232,184,212,51,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,32,2,120,7,201,162,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,36,2,15,0,249,52,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,40,2,150,9,168,142,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,44,2,225,14,152,24,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,48,2,127,106,13,187,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,52,2,8,109,61,45,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,56,2,145,100,108,151,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,60,2,230,99,92,1,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,64,2,107,107,81,244,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,68,2,28,108,97,98,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,72,2,133,101,48,216,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,76,2,242,98,0,78,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,80,2,108,6,149,237,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,84,2,27,1,165,123,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,88,2,130,8,244,193,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,92,2,245,15,196,87,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,96,2,101,176,217,198,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,100,2,18,183,233,80,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,104,2,139,190,184,234,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,108,2,252,185,136,124,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,112,2,98,221,29,223,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,116,2,21,218,45,73,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,120,2,140,211,124,243,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,124,2,251,212,76,101,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,128,2,77,178,97,88,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,132,2,58,181,81,206,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,136,2,163,188,0,116,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,140,2,212,187,48,226,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,144,2,74,223,165,65,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,148,2,61,216,149,215,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,152,2,164,209,196,109,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,156,2,211,214,244,251,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,160,2,67,105,233,106,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,164,2,52,110,217,252,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,168,2,173,103,136,70,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,172,2,218,96,184,208,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,176,2,68,4,45,115,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,180,2,51,3,29,229,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,184,2,170,10,76,95,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,188,2,221,13,124,201,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,192,2,80,5,113,60,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,196,2,39,2,65,170,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,200,2,190,11,16,16,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,204,2,201,12,32,134,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,208,2,87,104,181,37,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,212,2,32,111,133,179,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,216,2,185,102,212,9,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,220,2,206,97,228,159,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,224,2,94,222,249,14,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,228,2,41,217,201,152,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,232,2,176,208,152,34,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,236,2,199,215,168,180,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,240,2,89,179,61,23,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,244,2,46,180,13,129,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,248,2,183,189,92,59,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,1,252,2,192,186,108,173,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,0,2,237,184,131,32,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,4,2,154,191,179,182,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,8,2,3,182,226,12,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,12,2,116,177,210,154,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,16,2,234,213,71,57,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,20,2,157,210,119,175,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,24,2,4,219,38,21,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,28,2,115,220,22,131,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,32,2,227,99,11,18,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,36,2,148,100,59,132,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,40,2,13,109,106,62,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,44,2,122,106,90,168,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,48,2,228,14,207,11,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,52,2,147,9,255,157,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,56,2,10,0,174,39,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,60,2,125,7,158,177,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,64,2,240,15,147,68,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,68,2,135,8,163,210,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,72,2,30,1,242,104,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,76,2,105,6,194,254,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,80,2,247,98,87,93,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,84,2,128,101,103,203,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,88,2,25,108,54,113,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,92,2,110,107,6,231,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,96,2,254,212,27,118,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,100,2,137,211,43,224,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,104,2,16,218,122,90,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,108,2,103,221,74,204,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,112,2,249,185,223,111,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,116,2,142,190,239,249,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,120,2,23,183,190,67,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,124,2,96,176,142,213,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,128,2,214,214,163,232,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,132,2,161,209,147,126,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,136,2,56,216,194,196,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,140,2,79,223,242,82,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,144,2,209,187,103,241,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,148,2,166,188,87,103,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,152,2,63,181,6,221,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,156,2,72,178,54,75,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,160,2,216,13,43,218,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,164,2,175,10,27,76,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,168,2,54,3,74,246,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,172,2,65,4,122,96,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,176,2,223,96,239,195,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,180,2,168,103,223,85,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,184,2,49,110,142,239,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,188,2,70,105,190,121,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,192,2,203,97,179,140,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,196,2,188,102,131,26,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,200,2,37,111,210,160,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,204,2,82,104,226,54,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,208,2,204,12,119,149,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,212,2,187,11,71,3,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,216,2,34,2,22,185,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,220,2,85,5,38,47,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,224,2,197,186,59,190,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,228,2,178,189,11,40,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,232,2,43,180,90,146,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,236,2,92,179,106,4,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,240,2,194,215,255,167,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,244,2,181,208,207,49,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,248,2,44,217,158,139,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,2,252,2,91,222,174,29,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,0,2,155,100,194,176,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,4,2,236,99,242,38,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,8,2,117,106,163,156,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,12,2,2,109,147,10,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,16,2,156,9,6,169,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,20,2,235,14,54,63,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,24,2,114,7,103,133,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,28,2,5,0,87,19,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,32,2,149,191,74,130,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,36,2,226,184,122,20,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,40,2,123,177,43,174,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,44,2,12,182,27,56,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,48,2,146,210,142,155,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,52,2,229,213,190,13,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,56,2,124,220,239,183,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,60,2,11,219,223,33,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,64,2,134,211,210,212,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,68,2,241,212,226,66,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,72,2,104,221,179,248,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,76,2,31,218,131,110,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,80,2,129,190,22,205,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,84,2,246,185,38,91,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,88,2,111,176,119,225,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,92,2,24,183,71,119,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,96,2,136,8,90,230,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,100,2,255,15,106,112,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,104,2,102,6,59,202,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,108,2,17,1,11,92,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,112,2,143,101,158,255,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,116,2,248,98,174,105,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,120,2,97,107,255,211,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,124,2,22,108,207,69,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,128,2,160,10,226,120,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,132,2,215,13,210,238,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,136,2,78,4,131,84,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,140,2,57,3,179,194,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,144,2,167,103,38,97,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,148,2,208,96,22,247,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,152,2,73,105,71,77,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,156,2,62,110,119,219,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,160,2,174,209,106,74,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,164,2,217,214,90,220,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,168,2,64,223,11,102,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,172,2,55,216,59,240,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,176,2,169,188,174,83,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,180,2,222,187,158,197,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,184,2,71,178,207,127,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,188,2,48,181,255,233,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,192,2,189,189,242,28,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,196,2,202,186,194,138,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,200,2,83,179,147,48,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,204,2,36,180,163,166,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,208,2,186,208,54,5,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,212,2,205,215,6,147,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,216,2,84,222,87,41,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,220,2,35,217,103,191,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,224,2,179,102,122,46,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,228,2,196,97,74,184,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,232,2,93,104,27,2,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,236,2,42,111,43,148,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,240,2,180,11,190,55,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,244,2,195,12,142,161,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,248,2,90,5,223,27,2,4,3,2,255,255,251,248,1,20,4,1,2,0,0,3,252,2,45,2,239,141,2,1,0,4,1,4,2,2,0,0,0,12,1,20,4,1,2,4,2,2,255,255,255,252,1,20,4,1,1,0,4,1,2,1,4,4,1,4,2,2,0,0,0,8,1,20,4,1,11,1,4,4,1,2,255,255,255,255,2,4,2,2,0,0,0,8,1,20,4,1,1,4,4,1,2,1,8,4,1,4,2,2,0,0,0,16,1,20,4,1,2,4,2,2,255,255,255,248,1,20,4,1,1,8,4,1,2,1,0,4,1,4,2,2,0,0,0,16,1,20,4,1,3,1,0,4,1,2,0,0,0,1,2,4,2,2,0,0,0,16,1,20,4,1,1,0,4,1,6,4,2,2,255,255,255,248,1,20,4,1,2,0,0,0,0,16,2,0,0,28,40,2,1,4,4,1,4,2,2,255,255,255,252,1,20,4,1,10,1,8,4,1,3,1,1,4,4,1,11,1,8,4,1,4,2,2,0,0,0,8,1,20,4,1,17,1,8,4,1,2,0,0,0,255,2,1,0,4,1,4,2,2,0,0,0,8,1,20,4,1,18,1,0,4,1,2,0,0,0,8,11,1,0,4,1,4,3,2,255,255,251,248,1,20,4,1,1,8,4,4,2,4,2,2,0,0,0,8,1,20,4,1,1,0,4,1,2,1,4,4,1,4,2,2,255,255,255,252,1,20,4,1,5,1,4,4,1,2,0,0,0,1,2,4,2,2,255,255,255,252,1,20,4,1,1,4,4,1,8,2,0,0,27,36,2,1,0,4,1,4,2,2,0,0,0,8,1,20,4,1,11,1,0,4,1,2,255,255,255,255,2,1,16,4,1,1,20,4,1,14,1,20,4,1,15,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    var vm = new VM(mem);
    var loc = vm.stack.getInt32(16) - 38;        
    vm.stack.setInt32(16,loc);
    var flagadd = loc;
    var loc = vm.stack.getInt32(16) - 8;        
    vm.stack.setInt32(16,loc);
    var inputadd = loc;

    mem.set(new TextEncoder("utf-8").encode(input),inputadd);

    vm.push(flagadd);
    vm.push(inputadd);
    vm.push(0xFFFFFFFF);

    try
    {
        while(vm.IP != 0xFFFFFFFF)
        {
            vm.nextInst();
        }
    }
    catch(e)
    {    
    }

    if ( vm.stack.getInt32(0) >= 0 )
        return new TextDecoder("utf-8").decode(mem.subarray(flagadd,flagadd + 37));
    
    return "Failed";
}


Now let's run the script to acquire an execution trace.

GetFlag("maromaro")
web700.html:295 push 0
web700.html:197 mov r1, 11288
web700.html:256 sub 11288, 44
web700.html:295 push 0
web700.html:197 mov r1, 115
web700.html:197 mov r1, 20
web700.html:197 mov r1, 32
web700.html:197 mov r1, 23
web700.html:197 mov r1, 2
web700.html:197 mov r1, 98
web700.html:197 mov r1, 42
web700.html:197 mov r1, 119
web700.html:197 mov r1, 121
web700.html:197 mov r1, 29
web700.html:197 mov r1, 33
web700.html:197 mov r1, 113
web700.html:197 mov r1, 112
web700.html:197 mov r1, 103
web700.html:197 mov r1, 94
web700.html:197 mov r1, 6
web700.html:197 mov r1, 0
web700.html:197 mov r1, 30
web700.html:197 mov r1, 91
web700.html:197 mov r1, 113
web700.html:197 mov r1, 125
web700.html:197 mov r1, 103
web700.html:197 mov r1, 95
web700.html:197 mov r1, 113
web700.html:197 mov r1, 123
web700.html:197 mov r1, 111
web700.html:197 mov r1, 80
web700.html:197 mov r1, 2
web700.html:197 mov r1, 119
web700.html:197 mov r1, 103
web700.html:197 mov r1, 90
web700.html:197 mov r1, 115
web700.html:197 mov r1, 9
web700.html:197 mov r1, 25
web700.html:197 mov r1, 39
web700.html:197 mov r1, 1
web700.html:197 mov r1, 5
web700.html:295 push 8
web700.html:197 mov r1, 11304
web700.html:295 push 11304
web700.html:295 push 305419896
web700.html:188 call, 1223
web700.html:295 push 11288
web700.html:197 mov r1, 11220
web700.html:256 sub 11220, 1032
web700.html:197 mov r1, 0
web700.html:197 mov r1, 1996959894
web700.html:197 mov r1, 3993919788
web700.html:197 mov r1, 2567524794
web700.html:197 mov r1, 124634137
web700.html:197 mov r1, 1886057615
web700.html:197 mov r1, 3915621685
web700.html:197 mov r1, 2657392035
...
...
web700.html:197 mov r1, 3294710456
web700.html:197 mov r1, 1567103746
web700.html:197 mov r1, 711928724
web700.html:197 mov r1, 3020668471
web700.html:197 mov r1, 3272380065
web700.html:197 mov r1, 1510334235
web700.html:197 mov r1, 755167117
2web700.html:197 mov r1, 11304
web700.html:197 mov r1, 305419896
web700.html:246 xor 305419896, 4294967295
web700.html:197 mov r1, 3989547399
web700.html:197 mov r1, 8
web700.html:256 sub 8, 1
web700.html:197 mov r1, 7
web700.html:304 cmp 8, 0
web700.html:197 mov r1, 11304
web700.html:212 movu r1, 109
web700.html:246 xor 109, 3989547399
web700.html:281 and 3989547498, 255
web700.html:197 mov r1, 3989547399
web700.html:235 rsh 3989547399, 8
web700.html:246 xor 15584169, 1088359270
web700.html:197 mov r1, 1077067983
web700.html:197 mov r1, 11304
web700.html:222 add 11304, 1
web700.html:197 mov r1, 11305
web700.html:204 jmp, 6948
web700.html:197 mov r1, 7
web700.html:256 sub 7, 1
web700.html:197 mov r1, 6
web700.html:304 cmp 7, 0
web700.html:197 mov r1, 11305
web700.html:212 movu r1, 97
web700.html:246 xor 97, 1077067983
web700.html:281 and 1077067950, 255
web700.html:197 mov r1, 1077067983
web700.html:235 rsh 1077067983, 8
web700.html:246 xor 4207296, 829329135
web700.html:197 mov r1, 825146415
web700.html:197 mov r1, 11305
web700.html:222 add 11305, 1
web700.html:197 mov r1, 11306
web700.html:204 jmp, 6948
web700.html:197 mov r1, 6
web700.html:256 sub 6, 1
web700.html:197 mov r1, 5
web700.html:304 cmp 6, 0
web700.html:197 mov r1, 11306
web700.html:212 movu r1, 114
web700.html:246 xor 114, 825146415
web700.html:281 and 825146461, 255
web700.html:197 mov r1, 825146415
web700.html:235 rsh 825146415, 8
web700.html:246 xor 3223228, 366619977
web700.html:197 mov r1, 367723509
web700.html:197 mov r1, 11306
web700.html:222 add 11306, 1
web700.html:197 mov r1, 11307
web700.html:204 jmp, 6948
web700.html:197 mov r1, 5
web700.html:256 sub 5, 1
web700.html:197 mov r1, 4
web700.html:304 cmp 5, 0
web700.html:197 mov r1, 11307
web700.html:212 movu r1, 111
web700.html:246 xor 111, 367723509
web700.html:281 and 367723418, 255
web700.html:197 mov r1, 367723509
web700.html:235 rsh 367723509, 8
web700.html:246 xor 1436419, 282753626
web700.html:197 mov r1, 282038617
web700.html:197 mov r1, 11307
web700.html:222 add 11307, 1
web700.html:197 mov r1, 11308
web700.html:204 jmp, 6948
web700.html:197 mov r1, 4
web700.html:256 sub 4, 1
web700.html:197 mov r1, 3
web700.html:304 cmp 4, 0
web700.html:197 mov r1, 11308
web700.html:212 movu r1, 109
web700.html:246 xor 109, 282038617
web700.html:281 and 282038580, 255
web700.html:197 mov r1, 282038617
web700.html:235 rsh 282038617, 8
web700.html:246 xor 1101713, 565507253
web700.html:197 mov r1, 564411172
web700.html:197 mov r1, 11308
web700.html:222 add 11308, 1
web700.html:197 mov r1, 11309
web700.html:204 jmp, 6948
web700.html:197 mov r1, 3
web700.html:256 sub 3, 1
web700.html:197 mov r1, 2
web700.html:304 cmp 3, 0
web700.html:197 mov r1, 11309
web700.html:212 movu r1, 97
web700.html:246 xor 97, 564411172
web700.html:281 and 564411205, 255
web700.html:197 mov r1, 564411172
web700.html:235 rsh 564411172, 8
web700.html:246 xor 2204731, 112637215
web700.html:197 mov r1, 110563620
web700.html:197 mov r1, 11309
web700.html:222 add 11309, 1
web700.html:197 mov r1, 11310
web700.html:204 jmp, 6948
web700.html:197 mov r1, 2
web700.html:256 sub 2, 1
web700.html:197 mov r1, 1
web700.html:304 cmp 2, 0
web700.html:197 mov r1, 11310
web700.html:212 movu r1, 114
web700.html:246 xor 114, 110563620
web700.html:281 and 110563670, 255
web700.html:197 mov r1, 110563620
web700.html:235 rsh 110563620, 8
web700.html:246 xor 431889, 2181625025
web700.html:197 mov r1, 2181981136
web700.html:197 mov r1, 11310
web700.html:222 add 11310, 1
web700.html:197 mov r1, 11311
web700.html:204 jmp, 6948
web700.html:197 mov r1, 1
web700.html:256 sub 1, 1
web700.html:197 mov r1, 0
web700.html:304 cmp 1, 0
web700.html:197 mov r1, 11311
web700.html:212 movu r1, 111
web700.html:246 xor 111, 2181981136
web700.html:281 and 2181981119, 255
web700.html:197 mov r1, 2181981136
web700.html:235 rsh 2181981136, 8
web700.html:246 xor 8523363, 1541320221
web700.html:197 mov r1, 1532797054
web700.html:197 mov r1, 11311
web700.html:222 add 11311, 1
web700.html:197 mov r1, 11312
web700.html:204 jmp, 6948
web700.html:197 mov r1, 0
web700.html:256 sub 0, 1
web700.html:197 mov r1, 4294967295
web700.html:304 cmp 0, 0
web700.html:335 jnz 7208
web700.html:197 mov r1, 1532797054
web700.html:246 xor 1532797054, 4294967295
web700.html:197 mov r1, 11220
web700.html:269 pop
web700.html:265 ret
web700.html:222 add 11228, 12
web700.html:304 cmp 2762170241, 870690368
web700.html:312 jz 903
web700.html:327 or 2762170241, 4294967295
web700.html:269 pop
web700.html:197 mov r1, 11288
web700.html:269 pop
web700.html:265 ret
"Failed"

It is obvious that an encrypted string of size 37 is written in the beginning.
Then many constants are following, yes it is 32-bit CRC lookup table.
The next instructions compute the CRC of 8 bytes input string.

Here is a python implementation of the computation routine:


L = [0,1996959894,...,755167117] 
    
def myH(key):
    r = 305419896 ^ 4294967295  
    for c in key:
        r = ((r & 4294967295) >> 8) ^ L[(r ^ ord(c)) & 0xff]  
    return r ^ 4294967295  


Finally the computed CRC is compared to 870690368 (0x33E5AE40).

We use Z3 to find a 8 bytes string of CRC32 value is 0x33E5AE40.

yjlltzfo is a solution.

Let's run GetFlag("yjlltzfo") and see what happens

In addition to the first trace, we got:

cmp 870690368, 870690368
web700.html:312 jz 903
web700.html:319 [+] Correct Password
2web700.html:197 mov r1, 0
web700.html:204 jmp, 985
web700.html:304 cmp 0, 37
web700.html:197 mov r1, 0
web700.html:212 movu r1, 115
web700.html:197 mov r1, 0
web700.html:246 xor 0, 0
web700.html:197 mov r1, 8
web700.html:345 div 0, 8
web700.html:350 mod 0, 8
web700.html:197 mov r1, 11304
web700.html:212 movu r1, 121
web700.html:246 xor 115, 121
web700.html:197 mov r1, 11312
web700.html:222 add 11312, 0
web700.html:197 mov r1, 10
web700.html:204 jmp, 943
web700.html:197 mov r1, 0
web700.html:222 add 0, 1
web700.html:197 mov r1, 1
web700.html:304 cmp 1, 37
web700.html:197 mov r1, 1
web700.html:212 movu r1, 20
web700.html:197 mov r1, 1
web700.html:246 xor 1, 1
web700.html:197 mov r1, 8
web700.html:345 div 1, 8
web700.html:350 mod 1, 8
web700.html:197 mov r1, 11304
web700.html:212 movu r1, 106
web700.html:246 xor 20, 106
web700.html:197 mov r1, 11312
web700.html:222 add 11312, 1
web700.html:197 mov r1, 126
web700.html:204 jmp, 943
web700.html:197 mov r1, 1
web700.html:222 add 1, 1
web700.html:197 mov r1, 2
web700.html:304 cmp 2, 37
web700.html:197 mov r1, 2
web700.html:212 movu r1, 32
web700.html:197 mov r1, 2
web700.html:246 xor 2, 2
web700.html:197 mov r1, 8
web700.html:345 div 2, 8
web700.html:350 mod 2, 8
web700.html:197 mov r1, 11304
web700.html:212 movu r1, 108
web700.html:246 xor 32, 108
web700.html:197 mov r1, 11312
web700.html:222 add 11312, 2
web700.html:197 mov r1, 76
web700.html:204 jmp, 943
web700.html:197 mov r1, 2
web700.html:222 add 2, 1
web700.html:197 mov r1, 3
web700.html:304 cmp 3, 37
....
"
~L{v L ...

The password was accepted. However we got a garbage string. The entered password is used as a key to decrypt the flag.

According to the trace, here is a python implementation of decryption routine.

flag = [115, 20, 32, 23, 2, 98, 42, 119, 121, 29, 33, 113, 112, 103, 94, 6, 0, 30, 91, 113, 125, 103, 95, 113, 123, 111, 80, 2, 119, 103, 90, 115, 9, 25, 39, 1, 5]    
print "".join([chr(flag[i] ^ ord(password[i % 8])) for i in range(len(flag))])

We should find a valid password which is used to decrypt the flag starting with "KLCTF"

Finally We add the appropriate constraints to Z3 and we put all stuff together.

My solver:


# maro - Pwnium

from z3 import *
   
y = 0xedb88320
    
def H(pwd,size,prev=305419896):
 r = prev ^ 4294967295
 for i in range(0,size,8):
  r = r ^ (z3.LShR(pwd,i) & 0xFF)
  for _ in range(8):
   r = If(r & 1 == BitVecVal(1, size), z3.LShR(r,1) ^ y, z3.LShR(r,1))
 return r ^ 4294967295

size = 8 * 8
s = z3.Solver()
pwd = z3.BitVec('pwd',size)

inf = 32
sup = 126

flag = [115, 20, 32, 23, 2, 98, 42, 119, 121, 29, 33, 113, 112, 103, 94, 6, 0, 30, 91, 113, 125, 103, 95, 113, 123, 111, 80, 2, 119, 103, 90, 115, 9, 25, 39, 1, 5]      

def C(bv):
    return And( (LShR(bv, 0) & 0xff) == ord("K")^ flag[0],
               (LShR(bv, 8) & 0xff) == ord("L")^ flag[1],
               (LShR(bv, 16) & 0xff) == ord("C")^ flag[2],
               (LShR(bv, 24) & 0xff) == ord("T")^ flag[3],                              
               (LShR(bv, 32) & 0xff) == ord("F")^ flag[4],
               inf <= (LShR(bv, 40) & 0xff), (LShR(bv, 40) & 0xff) <= sup,
               inf <= (LShR(bv, 48) & 0xff), (LShR(bv, 48) & 0xff) <= sup,
               inf <= (LShR(bv, 56) & 0xff), (LShR(bv, 56) & 0xff) <= sup,)  


s.add(C(pwd))
s.add(H(pwd,size) == 870690368)

while s.check() == sat:  
    sol =  str(hex(int(str(s.model()[pwd]))))[2:].decode("hex")[::-1]
    print "[+] pwdsword: "+sol
    print "[+] Flag: "+"".join([chr(flag[i] ^ ord(sol[i % 8])) for i in range(len(flag))])
    s.add(Or(pwd != s.model()[pwd]))


The password is 8XcCDUhG and flag is KLCTF7B0AEB2426A8F829276C73A32241ADBA

That's all :))

Follow me on Twitter  

DefCamp CTF Qualification 2017 - Chio rev360 Writeup


Hi,

The task worths 360 pts. We were the first solvers to earn bonus points, but, I didn't like the fact of releasing hint few hours before the end of the CTF. since there were few teams already solved the challenge without hints and with a lot of guessing and this is totally unfair.

The hardest part of the challenge was to determine the target architecture of the provided file.

The given binary is a Chip8 ROM file. This information was not mentioned in the task statement, however the task title gave me a hint about the target CPU.

Disassemble the binary with a Chip8 disassembler

        start:
0x120a|         JP 522
0x6861|         LD V8, 97
0x7665|         ADD V6, 101
0x6675|         LD V6, 117
0x6e21|         LD V14, 33
        adr_522:
0x6002|         LD V0, 2
0x6102|         LD V1, 2
0xa04b|         LD I, 75
0xd015|         DRW V0, V1, 21
0xa00b|         LD I, 11
0x6103|         LD V1, 3
0xd011|         DRW V0, V1, 17
0x6102|         LD V1, 2
0x6007|         LD V0, 7
0xa032|         LD I, 50
0xd015|         DRW V0, V1, 21
0x600c|         LD V0, 12
0xa019|         LD I, 25
0xd015|         DRW V0, V1, 21
0x6011|         LD V0, 17
0xd015|         DRW V0, V1, 21
0x6016|         LD V0, 22
0xa023|         LD I, 35
0xd015|         DRW V0, V1, 21
0xa006|         LD I, 6
0x6105|         LD V1, 5
0xd011|         DRW V0, V1, 17
0x8120|         LD V2, V1
0x8230|         LD V3, V2
0x8340|         LD V4, V3
0x8450|         LD V5, V4
0x8730|         LD V3, V7
0x8990|         LD V9, V9
0x8561|         OR V5, V6
0x8320|         LD V2, V3
0x8440|         LD V4, V4
0x8652|         AND V6, V5
0x8322|         AND V3, V2
0x8563|         XOR V5, V6
0x8230|         LD V3, V2
0x8560|         LD V6, V5
0x8280|         LD V8, V2
0x8560|         LD V6, V5
0x8883|         XOR V8, V8
0x8450|         LD V5, V4
0x8540|         LD V4, V5
0x8320|         LD V2, V3
0x8650|         LD V5, V6
0x8441|         OR V4, V4
0x8433|         XOR V4, V3
0x8432|         AND V4, V3
0x8326|         SHR V3
0x8460|         LD V6, V4
0x8547|         SUBN V5, V4
0x8310|         LD V1, V3
0x8540|         LD V4, V5
0x8990|         LD V9, V9
0x8941|         OR V9, V4
0xf00a|         LD V0, K
0xf10a|         LD V1, K
0xf20a|         LD V2, K
0xf30a|         LD V3, K
0xf40a|         LD V4, K
0xf50a|         LD V5, K
0xf60a|         LD V6, K
0xf70a|         LD V7, K
0xf80a|         LD V8, K
0xf90a|         LD V9, K
0xfa0a|         LD V10, K
0xfb0a|         LD V11, K
0xfc0a|         LD V12, K
0xfd0a|         LD V13, K
0xfe0a|         LD V14, K
0xff0a|         LD V15, K
0x8014|         ADD V0, V1
0x8024|         ADD V0, V2
0x8034|         ADD V0, V3
0x8044|         ADD V0, V4
0x8054|         ADD V0, V5
0x8064|         ADD V0, V6
0x8074|         ADD V0, V7
0x8084|         ADD V0, V8
0x8094|         ADD V0, V9
0x80a4|         ADD V0, V10
0x80b4|         ADD V0, V11
0x80c4|         ADD V0, V12
0x80d4|         ADD V0, V13
0x80e4|         ADD V0, V14
0x3101|         SE V1, 1
0x1338|         JP 824
0x320d|         SE V2, 13
0x1338|         JP 824
0x330e|         SE V3, 14
0x1338|         JP 824
0x340c|         SE V4, 12
0x1338|         JP 824
0x3500|         SE V5, 0
0x1338|         JP 824
0x360d|         SE V6, 13
0x1338|         JP 824
0x370e|         SE V7, 14
0x1338|         JP 824
0x380d|         SE V8, 13
0x1338|         JP 824
0x390b|         SE V9, 11
0x1338|         JP 824
0x3a0e|         SE V10, 14
0x1338|         JP 824
0x3b0a|         SE V11, 10
0x1338|         JP 824
0x3c07|         SE V12, 7
0x1338|         JP 824
0x3d05|         SE V13, 5
0x1338|         JP 824
0x3e03|         SE V14, 3
0x1338|         JP 824
0xe0|           CLS
0x6002|         LD V0, 2
0x6102|         LD V1, 2
0xf229|         LD F, V2
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0xf329|         LD F, V3
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0xf429|         LD F, V4
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0xf529|         LD F, V5
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0xf629|         LD F, V6
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0xf729|         LD F, V7
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0xf829|         LD F, V8
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0xf929|         LD F, V9
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0xfa29|         LD F, V10
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0xfb29|         LD F, V11
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0xfc29|         LD F, V12
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0xfd29|         LD F, V13
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0x0|            GOTO adr:0
        adr_824:
0xe0|           CLS
0x6002|         LD V0, 2
0x6102|         LD V1, 2
0x6f0b|         LD V15, 11
0xff29|         LD F, V15
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0x6f00|         LD V15, 0
0xff29|         LD F, V15
0xd015|         DRW V0, V1, 21
0x7005|         ADD V0, 5
0xd015|         DRW V0, V1, 21
0x0|            GOTO adr:0


Reffering to Chip8 Instruction set,

When the program starts, it draws PA557 on the screen, prompting to enter the password.
Using DRW instruction, it reads n bytes from memory, starting at the address stored in I. These bytes are then displayed as sprites on screen at coordinates (Vx, Vy). Sprites are XORed onto the existing screen.

Then using LD instruction, it waits for a key press, stores the value of the key in V1 to V14 registers.

After 14 key presses, the program compares each register V1 to V14 to an expected values, and if they are not equal, it jumps to label 824 where the program clears the display and draws a bad password message.

Hence, the first keypress stored at register V1 should be equal to 1, next keypress should be 13 and so on and so forth.

According to the documentation,computers which originally used the Chip8 language had a 16-key hexadecimal keypad. After several tries, emulating the ROM file, I built the keymap mapping each keycode to my keyboard.

'1': 0,
'2': 1,
'3': 2,
'4': 3,
'q': 4,
'w': 5,
'e': 6,
'r': 7,
'a': 8,
's': 9,
'd': 10,
'f': 11,
'z': 12,
'x': 13,
'c': 14,
'v': 15,

Hence, the requested key presses are the following 2xcw1xcxfcdrz4f.

Entering this cheatcode should make the program jump to addr_522 label where the screen is cleared and a sprite series are loaded and printed to screen.

The string was DEC0DEDBEA75.

Finally, as the task states, after find the flag, you should make it compatible yourself.

The flag is DCTF{SHA256("dec0dedbea75")} = DCTF{d3b9bd4dcdd5e697ee29c1dc8c9c4174558dd46dca22a7b7f3af5404c04164e2}

That's all :)










CSAW CTF Qualification Round 2017:realism rev400 writeup

Hi,
This is a quick and dirty writeup for realism task.
The binary is a 16-bits bootloader.
The flag checking function is based on PSADBW instruction.
According to documentation, the instruction computes the absolute value of the difference of 8 unsigned byte integers from the source operand (second operand) and from the destination operand (first operand). These 8 differences are then summed to produce an unsigned word integer result that is stored in the destination operand.
In the given program the instruction operates on xmm2 and xmm5 registers.
When operating on 128-bit operands, two packed results are computed. Here, the 8 low-order bytes of the source and destination operands are operated on to produce a word result that is stored in the low word of the destination operand, and the 8 high-order bytes are operated on to produce a word result that is stored in bits 64 through 79 of the destination operand. The remaining bytes of the destination operand are cleared.
Then the computed sum of absolute differences are compared against excpected result. 2 chars are compared at one time.

Following is my solver.



from z3 import *


def psadbw(v1,v2):
    s = 0
    for i in range(len(v1)):
        s+= abs(v1[i] - v2[i])
    return s
    
def zabs(x):
    return If(x >= 0,x,-x)
   
def symabs(v1,v2):
    s = 0
    for i in range(len(v1)):
        s+= zabs(v1[i] - v2[i])
    return s
    

m1 = [0x22, 0x0f, 0x02, 0xc8, 0x83, 0xfb, 0xe0, 0x83] 
m2 = [0xc0, 0x20, 0x0f, 0x10, 0xcd, 0x00, 0x13, 0xb8]

X = [34,15,2,-324,131,251,224,0]
      
r = psadbw(X, m1)
print "0x%x"%r

 



  

s = Solver()



f1 = Int('f1') 
f2 = Int('f2') 
f3 = Int('f3') 
f4 = Int('f4') 
f5 = Int('f5') 
f6 = Int('f6') 
f7 = Int('f7') 
f8 = Int('f8')
g1 = Int('g1') 
g2 = Int('g2') 
g3 = Int('g3') 
g4 = Int('g4') 
g5 = Int('g5') 
g6 = Int('g6') 
g7 = Int('g7') 
g8 = Int('g8')



'''
s.add(f1 >= 32,f1 <=126)
s.add(f2 >= 32,f2 <=126)
s.add(f3 >= 32,f3 <=126)
s.add(f4 >= 32,f4 <=126)
s.add(f5 >= 32,f5 <=126)
s.add(f6 >= 32,f6 <=126)
s.add(f7 >= 32,f7 <=126)
s.add(f8 >= 32,f8 <=126)
'''



'''
0x2df028f
0x290025d
0x2090221
0x27b0278
0x1f90233
0x25e0291
0x2290255
0x2110270
'''




s.add( zabs(f1-m1[0])+zabs(f2-m1[1])+zabs(f3-m1[2])+zabs(f4-m1[3])+zabs(f5-m1[4])+zabs(f6-m1[5])+zabs(f7-m1[6])+zabs(m1[7]) == 0x28f  )
s.add( zabs(f1)+zabs(f2)+zabs(f3)+zabs(f4)+zabs(f5)+zabs(f6)+zabs(0x2)+zabs(f8-0x8f) == 0x25d  )
s.add( zabs(f1)+zabs(f2)+zabs(f3)+zabs(f4)+zabs(f5)+zabs(0)+zabs(f7-0x2)+zabs(f8-0x5d) == 0x221  )
s.add( zabs(f1)+zabs(f2)+zabs(f3)+zabs(f4)+zabs(0)+zabs(f6)+zabs(f7-0x2)+zabs(f8-0x21) == 0x278  )
s.add( zabs(f1)+zabs(f2)+zabs(f3)+zabs(0)+zabs(f5)+zabs(f6)+zabs(f7-0x2)+zabs(f8-0x78) == 0x233  )
s.add( zabs(f1)+zabs(f2)+zabs(0)+zabs(f4)+zabs(f5)+zabs(f6)+zabs(f7-0x2)+zabs(f8-0x33) == 0x291  )
s.add( zabs(f1)+zabs(0)+zabs(f3)+zabs(f4)+zabs(f5)+zabs(f6)+zabs(f7-0x2)+zabs(f8-0x91) == 0x255  )
s.add( zabs(0)+zabs(f2)+zabs(f3)+zabs(f4)+zabs(f5)+zabs(f6)+zabs(f7-0x2)+zabs(f8-0x55) == 0x270  )


s.add( zabs(g1-m2[0])+zabs(g2-m2[1])+zabs(g3-m2[2])+zabs(g4-m2[3])+zabs(g5-m2[4])+zabs(g6-m2[5])+zabs(g7-m2[6])+zabs(m2[7]) == 0x2df  )
s.add( zabs(g1)+zabs(g2)+zabs(g3)+zabs(g4)+zabs(g5)+zabs(g6)+zabs(0x2)+zabs(g8-0xdf) == 0x290  )
s.add( zabs(g1)+zabs(g2)+zabs(g3)+zabs(g4)+zabs(g5)+zabs(0)+zabs(g7-0x2)+zabs(g8-0x90) == 0x209  )
s.add( zabs(g1)+zabs(g2)+zabs(g3)+zabs(g4)+zabs(0)+zabs(g6)+zabs(g7-0x2)+zabs(g8-0x09) == 0x27b  )
s.add( zabs(g1)+zabs(g2)+zabs(g3)+zabs(0)+zabs(g5)+zabs(g6)+zabs(g7-0x2)+zabs(g8-0x7b) == 0x1f9  )
s.add( zabs(g1)+zabs(g2)+zabs(0)+zabs(g4)+zabs(g5)+zabs(g6)+zabs(g7-0x1)+zabs(g8-0xf9) == 0x25e  )
s.add( zabs(g1)+zabs(0)+zabs(g3)+zabs(g4)+zabs(g5)+zabs(g6)+zabs(g7-0x2)+zabs(g8-0x5e) == 0x229  )
s.add( zabs(0)+zabs(g2)+zabs(g3)+zabs(g4)+zabs(g5)+zabs(g6)+zabs(g7-0x2)+zabs(g8-0x29) == 0x211  )

s.add(g1 >= 32,g1 <=126)
s.add(g2 >= 32,g2 <=126)
s.add(g3 >= 32,g3 <=126)
s.add(g4 >= 32,g4 <=126)
s.add(g5 >= 32,g5 <=126)
s.add(g6 >= 32,g6 <=126)
s.add(g7 >= 32,g7 <=126)
s.add(g8 >= 32,g8 <=126)
s.add(f1 >= 32,f1 <=126)
s.add(f2 >= 32,f2 <=126)
s.add(f3 >= 32,f3 <=126)
s.add(f4 >= 32,f4 <=126)
s.add(f5 >= 32,f5 <=126)
s.add(f6 >= 32,f6 <=126)
s.add(f7 >= 32,f7 <=126)
s.add(f8 >= 32,f8 <=126)



'''
s.add( pabs(g1-m2[0])+pabs(g2-m2[1])+pabs(g3-m2[2])+pabs(g4-m2[3])+pabs(g5-m2[4])+pabs(g6-m2[5])+pabs(g7-m2[6])+pabs(0x00-m2[7]) == 0x2df)
s.add(  (pabs(g1-m2[0])+pabs(g2-m2[1])+pabs(g3-m2[2])+pabs(g4-m2[3])+pabs(g5-m2[4])+pabs(g6-m2[5])+pabs(0x00-m2[6])+pabs(g8-m2[7]))  == 0x290)
s.add(  (pabs(g1-m2[0])+pabs(g2-m2[1])+pabs(g3-m2[2])+pabs(g4-m2[3])+pabs(g5-m2[4])+pabs(0x00-m2[5])+pabs(g7-m2[6])+pabs(g8-m2[7]))  == 0x209)
s.add  ((pabs(g1-m2[0])+pabs(g2-m2[1])+pabs(g3-m2[2])+pabs(g4-m2[3])+pabs(0x00-m2[4])+pabs(g6-m2[5])+pabs(g7-m2[6])+pabs(g8-m2[7])) == 0x27b)
s.add(  (pabs(g1-m2[0])+pabs(g2-m2[1])+pabs(g3-m2[2])+pabs(0x00-m2[3])+pabs(g5-m2[4])+pabs(g6-m2[5])+pabs(g7-m2[6])+pabs(g8-m2[7]))  == 0x1f9)
s.add(  (pabs(g1-m2[0])+pabs(g2-m2[1])+pabs(0x00-m2[2])+pabs(g4-m2[3])+pabs(g5-m2[4])+pabs(g6-m2[5])+pabs(g7-m2[6])+pabs(g8-m2[7]))  == 0x25e)
s.add( (pabs(g1-m2[0])+pabs(0x00-m2[1])+pabs(g3-m2[2])+pabs(g4-m2[3])+pabs(g5-m2[4])+pabs(g6-m2[5])+pabs(g7-m2[6])+pabs(g8-m2[7])) == 0x229)
#s.add( (pabs(0x00-m2[0])+pabs(g2-m2[1])+pabs(g3-m2[2])+pabs(g4-m2[3])+pabs(g5-m2[4])+pabs(g6-m2[5])+pabs(g7-m2[6])+pabs(g8-m2[7])) == 0x211)

#s.add(g1 >= -256,g1 <=256)
s.add(g1 == 0x7d, g1 == -0x7d)
#s.add(g2 >= -256,g2 <=256)
#s.add(g3 >= -256,g3 <=256)
#s.add(g4 >= -256,g4 <=256)
#s.add(g5 >= -256,g5 <=256)
#s.add(g6 >= -256,g6 <=256)
#s.add(g7 >= -256,g7 <=256)
#s.add(g8 >= -256,g8 <=256)
'''


s.check()

print s.model()


The flag was flag{4r3alz_m0d3_y0}

Cheers :))

Bugs_Bunny CTF 2017 - Maze Runner - Rev400 Writeup

Hello,

I solved the task by statically analyzing the given program. The goal was to pass 2 checks, isValid() and ValidAgAin().

If you import the binary to IDApro, you get the Call Graph of isValid() Function :



It looks hard to reverse-engineer it but it is really simple. The function is obfuscated since there is a lot of unnecessary checks and fake tests.

The check algorithm controls the execution flow based on Finite-State Machine model.

To solve the function we have to find the correct input which leads the execution to the correct final state, the node/state which returns 1 and avoid states returning 0 result.

The EAX register holds the current state value. The initial state value is 0x4DC7551E. The question is what is the following correct state ? I mean what will be the transition if EAX register is equal to  0x4DC7551E ?

We can just take the disassembly and search for 0x4DC7551E value.


As we can see from the above disassembly if the state is equal to 0x4DC7551E than the input character (held by DL register) at current index held by RDI register is checked against a set of candidate characters (0x48, 0x35, 0x77, 0x22 ..).

After several fuzzing attempts, I figured out that we need to pass only the first check (cmp dl, 0x48) and ignore the remaining one. This means that the first flag char is 'H'. Than the control is transferred to  loc_402B37.


The next state is 0x2C5928F3. We ask the same question: what will be the following state if 0x2C5928F3 state is reached ? We search again for 0x2C5928F3.


To reach the state the second input character is tested against 0x65 ,0x4F, 0x59..and as we said we should focus only on the first check. Thus, the second flag char is 'e' and so on and so forth !

0x4DC7551E  -> 0x48  ->  'H'
0x2C5928F3   -> 0x65  ->  'e'
0xEFCD27A9 -> 0x72  ->  'r'
0x707CE1DD -> 0x65  ->  'e'
0x0A4E69255 -> 0x2d  ->  '-' <- You should pay intention that the check is made using JNZ instead of JZ

And the first par of the flag is revealed ! "Here-"

The next state is 0x69241B56. To reach this state a new check mechanism is introduced.


The first 2 instructions in the disassembly above checks if the following char is number or not. Giving any number at this level is fine.  Remember that always we need to pas the first check !

The next states are:
0x7F202C0Ah  -> 1
0x9958FF9Bh  ->  1
0x56A7CE11h  -> 1
0x78AB8DFCh -> -

And so on and so forth !

The input Here-1111-Is-My-5EcreT-11-HH should pass the first test.

IsValid() accepts many solutions, just change numeric values.

IsValidAgAin() is made to make the program accepts only one input.

Decompile the function. Note I removed many unnecessary checks !




Conclusion drawn from the above code:
The flag length is 28
Chars at index 23 and 24 must  '4'
Chars at index 5,6,7 and 8 must '1'
Char at index 0 must be equal to 'H'

The flag is  Here-1111-Is-My-5EcreT-44-HH

The following video contains detailed steps !





That's all :)