nookstop 2.0 [web]

solved by not_really

Writeup by not_really

Okay okay, they got back to me and they tell me that we’re using some new technology. Can you give it a try now?


Author: ian5v

Site mirror: nookstop2.chal.uiuc.tf.zip

So like the first version, we set the secret_backend_service cookie to true and an Access (Beta) button shows up.


Ah yes, emscripten, and probably webm. Let’s check the network sources to find the files.


There’s a decrypt function that seems to print something like a flag but it doesn’t really print out all the way. index.js is going to be boring emscripten code so we can ignore that. But the .wasm file is where the real code is at. Also, there seems to be a flag file. Let’s copy the url of these and download them somewhere.

It does mention some xor encryption, and we do have a flag file that might have something to do with it. But instead of just guessing, why bother if we have the code?

To view the contents of the wasm file, let’s use great tools like wasm2wat and wasm-decompile from wabt.

If we run wasm-decompile first, we get something like this:


This looks like mostly garbage, but we do see some strings from the output we saw earlier.

There’s lots and lots of code here that I’m not going to look through, however we do know that there is some xoring going on. There are quite a few functions lying around, but f_k, one of the first functions, seems to have an xor in it. Let’s edit the code and see if that xor is the one we’re thinking of.

We can use wasm2wat for this.

  (func (;10;) (type 3) (param i32 i32) (result i32)
    (local i32 i32 i32 i32 i32 i32 i32 i32)
    global.get 0
    local.set 2
    i32.const 16
    local.set 3
    local.get 2
    local.get 3
    local.set 4
    local.get 4
    local.get 0
    i32.store offset=12
    local.get 4
    local.get 1
    i32.store offset=8
    local.get 4
    i32.load offset=12
    local.set 5
    local.get 4
    i32.load offset=8
    local.set 6
    local.get 5
    local.get 6
    local.set 7
    i32.const 3
    local.set 8
    local.get 7

To test this out, we’ll change i32.xor to i32.and.

Now for running the program. Convert the wat back to a wasm with wat2wasm. Download index.js and abd (rename abd.html) from the server. Have the flag file in a folder called a9bc27ff-0b0c-494d-9377-14c95ca94b67 next to the wasm file. This should match the structure of the original server.


Now just set up a python -m http.server and connect.


Haha! Our luck, one of the first functions was actually the function we were looking for.

Let’s look at the decompiled code for that function again.

function f_k(a:int, b:int):int {
  var c:int = g_a;
  var d:int = 16;
  var e:int = c - d;
  e[3]:int = a;
  e[2]:int = b;
  var f:int = e[3]:int;
  var g:int = e[2]:int;
  var h:int = f ^ g;
  var i:int = 3;
  var j:int = h | i;
  return j;

For some reason after we xor, we or the result with 3. And also, the characters printed earlier seemed sort of like they could be 3 characters away. Let’s try removing that. The easiest way would be changing the 3 in i32.const 3 to 0 in the wat.


We got it! The whole thing was just simple xor. Of course there was the flag file, but where was the other part?

If you look back at the decompiled code again you’ll see this line at the top:

data d_b(offset: 2048) = "\12\e8\f3\e9\09\1a\b3\8f>\bb\c1h\19\0ai#\

That string there is what you need to xor with the flag.


Also, this same removing or of 3 works on nookstop 3.0 as well. However if you want to xor manually, it’s a little different. It stores the xor key in a different place/format.

If you look at nookstop 3.0 decompiled, you’ll see this later down the line on d_b:


For some reason there are 0s separating all the values (or maybe 2 byte vals?), but if we remove the 00s and convert it all to hex:

5D 68 D9 03 34 86 AB 47 49 04 D4 D7 2C 94 1B A8


So it was basically the same problem.