Hello again :),
Ok folks, you managed to get to level 2.
Let's begin,
The challenge
We are presented with a JavaScript file:
//-------------------------------------------------------------------------------------------------- // // stage 2 of 3 // // challenge: // reveal the solution within VM.mem // // disclaimer: // tested in ie 9, firefox 6, chrome 14 and v8 shell (http://code.google.com/apis/v8/build.html), // other javascript implementations may or may not work. // //-------------------------------------------------------------------------------------------------- var VM = { cpu: { ip: 0x00, r0: 0x00, r1: 0x00, r2: 0x00, r3: 0x00, cs: 0x00, ds: 0x10, fl: 0x00, firmware: [0xd2ab1f05, 0xda13f110] }, mem: [ 0x31, 0x04, 0x33, 0xaa, 0x40, 0x02, 0x80, 0x03, 0x52, 0x00, 0x72, 0x01, 0x73, 0x01, 0xb2, 0x50, 0x30, 0x14, 0xc0, 0x01, 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xab, 0xd9, 0xa1, 0x9f, 0xa7, 0x83, 0x83, 0xf2, 0xb1, 0x34, 0xb6, 0xe4, 0xb7, 0xca, 0xb8, 0xc9, 0xb8, 0x0e, 0xbd, 0x7d, 0x0f, 0xc0, 0xf1, 0xd9, 0x03, 0xc5, 0x3a, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xa9, 0xcd, 0xdf, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0x26, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0x7d, 0x1f, 0x15, 0x60, 0x4d, 0x4d, 0x52, 0x7d, 0x0e, 0x27, 0x6d, 0x10, 0x6d, 0x5a, 0x06, 0x56, 0x47, 0x14, 0x42, 0x0e, 0xb6, 0xb2, 0xb2, 0xe6, 0xeb, 0xb4, 0x83, 0x8e, 0xd7, 0xe5, 0xd4, 0xd9, 0xc3, 0xf0, 0x80, 0x95, 0xf1, 0x82, 0x82, 0x9a, 0xbd, 0x95, 0xa4, 0x8d, 0x9a, 0x2b, 0x30, 0x69, 0x4a, 0x69, 0x65, 0x55, 0x1c, 0x7b, 0x69, 0x1c, 0x6e, 0x04, 0x74, 0x35, 0x21, 0x26, 0x2f, 0x60, 0x03, 0x4e, 0x37, 0x1e, 0x33, 0x54, 0x39, 0xe6, 0xba, 0xb4, 0xa2, 0xad, 0xa4, 0xc5, 0x95, 0xc8, 0xc1, 0xe4, 0x8a, 0xec, 0xe7, 0x92, 0x8b, 0xe8, 0x81, 0xf0, 0xad, 0x98, 0xa4, 0xd0, 0xc0, 0x8d, 0xac, 0x22, 0x52, 0x65, 0x7e, 0x27, 0x2b, 0x5a, 0x12, 0x61, 0x0a, 0x01, 0x7a, 0x6b, 0x1d, 0x67, 0x75, 0x70, 0x6c, 0x1b, 0x11, 0x25, 0x25, 0x70, 0x7f, 0x7e, 0x67, 0x63, 0x30, 0x3c, 0x6d, 0x6a, 0x01, 0x51, 0x59, 0x5f, 0x56, 0x13, 0x10, 0x43, 0x19, 0x18, 0xe5, 0xe0, 0xbe, 0xbf, 0xbd, 0xe9, 0xf0, 0xf1, 0xf9, 0xfa, 0xab, 0x8f, 0xc1, 0xdf, 0xcf, 0x8d, 0xf8, 0xe7, 0xe2, 0xe9, 0x93, 0x8e, 0xec, 0xf5, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x7a, 0x07, 0x11, 0x1f, 0x1d, 0x68, 0x25, 0x32, 0x77, 0x1e, 0x62, 0x23, 0x5b, 0x47, 0x55, 0x53, 0x30, 0x11, 0x42, 0xf6, 0xf1, 0xb1, 0xe6, 0xc3, 0xcc, 0xf8, 0xc5, 0xe4, 0xcc, 0xc0, 0xd3, 0x85, 0xfd, 0x9a, 0xe3, 0xe6, 0x81, 0xb5, 0xbb, 0xd7, 0xcd, 0x87, 0xa3, 0xd3, 0x6b, 0x36, 0x6f, 0x6f, 0x66, 0x55, 0x30, 0x16, 0x45, 0x5e, 0x09, 0x74, 0x5c, 0x3f, 0x29, 0x2b, 0x66, 0x3d, 0x0d, 0x02, 0x30, 0x28, 0x35, 0x15, 0x09, 0x15, 0xdd, 0xec, 0xb8, 0xe2, 0xfb, 0xd8, 0xcb, 0xd8, 0xd1, 0x8b, 0xd5, 0x82, 0xd9, 0x9a, 0xf1, 0x92, 0xab, 0xe8, 0xa6, 0xd6, 0xd0, 0x8c, 0xaa, 0xd2, 0x94, 0xcf, 0x45, 0x46, 0x67, 0x20, 0x7d, 0x44, 0x14, 0x6b, 0x45, 0x6d, 0x54, 0x03, 0x17, 0x60, 0x62, 0x55, 0x5a, 0x4a, 0x66, 0x61, 0x11, 0x57, 0x68, 0x75, 0x05, 0x62, 0x36, 0x7d, 0x02, 0x10, 0x4b, 0x08, 0x22, 0x42, 0x32, 0xba, 0xe2, 0xb9, 0xe2, 0xd6, 0xb9, 0xff, 0xc3, 0xe9, 0x8a, 0x8f, 0xc1, 0x8f, 0xe1, 0xb8, 0xa4, 0x96, 0xf1, 0x8f, 0x81, 0xb1, 0x8d, 0x89, 0xcc, 0xd4, 0x78, 0x76, 0x61, 0x72, 0x3e, 0x37, 0x23, 0x56, 0x73, 0x71, 0x79, 0x63, 0x7c, 0x08, 0x11, 0x20, 0x69, 0x7a, 0x14, 0x68, 0x05, 0x21, 0x1e, 0x32, 0x27, 0x59, 0xb7, 0xcf, 0xab, 0xdd, 0xd5, 0xcc, 0x97, 0x93, 0xf2, 0xe7, 0xc0, 0xeb, 0xff, 0xe9, 0xa3, 0xbf, 0xa1, 0xab, 0x8b, 0xbb, 0x9e, 0x9e, 0x8c, 0xa0, 0xc1, 0x9b, 0x5a, 0x2f, 0x2f, 0x4e, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ], exec: function() { // virtual machine architecture // ++++++++++++++++++++++++++++ // // segmented memory model with 16-byte segment size (notation seg:offset) // // 4 general-purpose registers (r0-r3) // 2 segment registers (cs, ds equiv. to r4, r5) // 1 flags register (fl) // // instruction encoding // ++++++++++++++++++++ // // byte 1 byte 2 (optional) // bits [ 7 6 5 4 3 2 1 0 ] [ 7 6 5 4 3 2 1 0 ] // opcode - - - // mod - // operand1 - - - - // operand2 - - - - - - - - // // operand1 is always a register index // operand2 is optional, depending upon the instruction set specified below // the value of mod alters the meaning of any operand2 // 0: operand2 = reg ix // 1: operand2 = fixed immediate value or target segment (depending on instruction) // // instruction set // +++++++++++++++ // // Notes: // * r1, r2 => operand 1 is register 1, operand 2 is register 2 // * movr r1, r2 => move contents of register r2 into register r1 // // opcode | instruction | operands (mod 0) | operands (mod 1) // -------+-------------+------------------+----------------- // 0x00 | jmp | r1 | r2:r1 // 0x01 | movr | r1, r2 | rx, imm // 0x02 | movm | r1, [ds:r2] | [ds:r1], r2 // 0x03 | add | r1, r2 | r1, imm // 0x04 | xor | r1, r2 | r1, imm // 0x05 | cmp | r1, r2 | r1, imm // 0x06 | jmpe | r1 | r2:r1 // 0x07 | hlt | N/A | N/A // // flags // +++++ // // cmp r1, r2 instruction results in: // r1 == r2 => fl = 0 // r1 < r2 => fl = 0xff // r1 > r2 => fl = 1 // // jmpe r1 // => if (fl == 0) jmp r1 // else nop throw "VM.exec not yet implemented"; } }; //-------------------------------------------------------------------------------------------------- try { VM.exec(); } catch(e) { alert('\nError: ' + e + '\n'); } //--------------------------------------------------------------------------------------------------
Okay, the challenge consist in implementing a virtual CPU that will be able to execute the bytecode and decrypt the parts that interest us.
The VM
Hell, I am not a Web guy so I do not master JavaScript ... who said I had to use JavaScript?
Thus I coded my VM in C, it is included in the archive at the end of the post (600-700 lines of code is too much for a post :)).
I implemented the VM, a disassembler and some debug stuffs.
The disassembled byte code
Before executing any code:
== DISASM (before) 0x0000: movr r1, 4 0x0002: movr r3, 170 0x0004: movm r0, [ds:r2] 0x0006: xor r0, r3 0x0008: movm [ds:r2], r0 0x000a: add r2, 1 0x000c: add r3, 1 0x000e: cmp r2, 80 0x0010: movr r0, 20 0x0012: jmpe r0 0x0013: jmp r1 0x0014: xor r0, r0 0x0016: jmp 16:r0 0x0018: jmp r0 0x0019: jmp r0 0x001a: jmp r0 [...] 0x00fa: jmp r0 0x00fb: jmp r0 0x00fc: jmp r0 0x00fd: jmp r0 0x00fe: jmp r0 0x00ff: jmp r0 0x0100: xor r0, 171 0x0102: jmpe 161:r1 0x0104: invalid 0x0106: xor r3, r3 0x0108: hlt 0x0109: cmp r1, 52 0x010b: invalid 0x010d: invalid 0x010f: cmp r0, 201 0x0111: cmp r0, 14 0x0113: cmp ds, 125 0x0115: invalid 0x0116: jmpe r0 0x0117: hlt 0x0118: jmpe 3:r1 0x011a: invalid 0x011b: movr r2, 198 0x011d: invalid 0x011e: jmpe r0 0x011f: jmpe r1 0x0120: jmpe r2 0x0121: jmpe r3 0x0122: invalid 0x0123: invalid 0x0124: invalid 0x0125: invalid
As you can see you have a first loop from address 0x0 to 0x16.
The second loop is completely junk as we have invalid instructions.
The first loop will loop till r2 is 80.
Basically, it will decode 80 bytes of the "data section" with keys ranging from 170 to 250.
The data section is located at offset 256 and the code section at offset 0.
Once we decrypted 80 bytes, we change our code section so it points at offset 256.
We basically decoded a second payload.
The code at the end:
== DISASM (after) 0x0000: movr r1, 4 0x0002: movr r3, 170 0x0004: movm r0, [ds:r2] 0x0006: xor r0, r3 0x0008: movm [ds:r2], r0 0x000a: add r2, 1 0x000c: add r3, 1 0x000e: cmp r2, 80 0x0010: movr r0, 20 0x0012: jmpe r0 0x0013: jmp r1 0x0014: xor r0, r0 0x0016: jmp 16:r0 0x0018: jmp r0 0x0019: jmp r0 0x001a: jmp r0 [...] 0x00fa: jmp r0 0x00fb: jmp r0 0x00fc: jmp r0 0x00fd: jmp r0 0x00fe: jmp r0 0x00ff: jmp r0 0x0100: movr r2, 0 0x0102: add ds, 12 0x0104: movr r1, 8 0x0106: movr r3, 50 0x0108: movm r0, [ds:r2] 0x010a: xor r0, r3 0x010c: movm [ds:r2], r0 0x010e: add r2, 1 0x0110: add r3, 3 0x0112: cmp r2, 0 0x0114: jmpe r3 0x0115: cmp r0, 0 0x0117: movr r0, 27 0x0119: jmpe r0 0x011a: jmp r1 0x011b: hlt 0x011c: jmp r0 0x011d: jmp r0 [...] 0x0130: jmp r0 0x0131: jmp r0 0x0132: add ds, 16 0x0134: jmp r1 0x0135: jmp r0 0x0136: jmp r0 0x0137: jmp r0 0x0138: jmp r0 0x0139: jmp r0 0x013a: jmp r0 0x013b: jmp r0 0x013c: jmp r0 0x013d: jmp r0 0x013e: jmp r0 0x013f: jmp r0 0x0140: invalid 0x0141: jmp r0 0x0142: jmp r0 0x0143: jmp r0 0x0144: jmp r0 0x0145: jmp r0 0x0146: jmp r0 0x0147: jmp r0 0x0148: jmp r0
Now at offset 0x100, we can see our decoded payload.
It is a second decoding loop ;).
It changes ds so it points to the encoded payload.
It stop decoding as soon as it reaches the end of the decoded string: '\0'.
The thing is ... we still have 256 bytes that we have no idea of what it is as we can seen from the dumps.
28 : 0x1c0 : 47 45 54 20 2f 64 61 37 35 33 37 30 66 65 31 35 | GET /da75370fe15 29 : 0x1d0 : 63 34 31 34 38 62 64 34 63 65 65 63 38 36 31 66 | c4148bd4ceec861f 30 : 0x1e0 : 62 64 61 61 35 2e 65 78 65 20 48 54 54 50 2f 31 | bdaa5.exe HTTP/1 31 : 0x1f0 : 2e 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | .0.............. 32 : 0x200 : 37 7a 07 11 1f 1d 68 25 32 77 1e 62 23 5b 47 55 | 7z....h%2w.b#[GU 33 : 0x210 : 53 30 11 42 f6 f1 b1 e6 c3 cc f8 c5 e4 cc c0 d3 | S0.B............ 34 : 0x220 : 85 fd 9a e3 e6 81 b5 bb d7 cd 87 a3 d3 6b 36 6f | .............k6o 35 : 0x230 : 6f 66 55 30 16 45 5e 09 74 5c 3f 29 2b 66 3d 0d | ofU0.E^.t\?)+f=. 36 : 0x240 : 02 30 28 35 15 09 15 dd ec b8 e2 fb d8 cb d8 d1 | .0(5............ 37 : 0x250 : 8b d5 82 d9 9a f1 92 ab e8 a6 d6 d0 8c aa d2 94 | ................ 38 : 0x260 : cf 45 46 67 20 7d 44 14 6b 45 6d 54 03 17 60 62 | .EFg }D.kEmT..`b 39 : 0x270 : 55 5a 4a 66 61 11 57 68 75 05 62 36 7d 02 10 4b | UZJfa.Whu.b6}..K 40 : 0x280 : 08 22 42 32 ba e2 b9 e2 d6 b9 ff c3 e9 8a 8f c1 | ."B2............ 41 : 0x290 : 8f e1 b8 a4 96 f1 8f 81 b1 8d 89 cc d4 78 76 61 | .............xva 42 : 0x2a0 : 72 3e 37 23 56 73 71 79 63 7c 08 11 20 69 7a 14 | r>7#Vsqyc|.. iz. 43 : 0x2b0 : 68 05 21 1e 32 27 59 b7 cf ab dd d5 cc 97 93 f2 | h.!.2'Y......... 44 : 0x2c0 : e7 c0 eb ff e9 a3 bf a1 ab 8b bb 9e 9e 8c a0 c1 | ................ 45 : 0x2d0 : 9b 5a 2f 2f 4e 4e 00 00 00 00 00 00 00 00 00 00 | .Z//NN.......... 46 : 0x2e0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ 47 : 0x2f0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
So you can see our decoded string is GET ...
[+] Initializing VM CPU [+] Executing bytecode [+] Finished executing bytecode [+] Answer: 'GET /da75370fe15c4148bd4ceec861fbdaa5.exe HTTP/1.0'
But after the GET, we have 256+ bytes that has not been modified in any way ...
Someone found what it is? (and no it does not seem to be a valid 7zip file :().
Conclusion
This level was more interesting and more programming related.
Implementing a VM was something I never did before ... but was fun :).
Any person who did some "Computer Science" should thus be able to solve this level without much difficulties.
To be continued on the next level ...
m_101
- My solutions: here
Aucun commentaire :
Enregistrer un commentaire