Loteria flagowa - PWNing2016
Loteria flagowa
Punkty: 100 Rozwiązań: 44
Znaleźliśmy w internecie loterię flagową. W zgodzie z ustawą o grach hazardowych zostanie ona zaraz zablokowana, ale spróbuj przed zamknięciem wyciągnąć z niej flagę.
Let’s go
Na samym początku widzimy zakładkę SERVER SOURCE
i mamy tam kod źródłowy naszej aplikacji:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
var express = require("express");
var app = express();
var expressWs = require('express-ws')(app);
var fs = require("fs");
var flag = fs.readFileSync("../flag").toString();
app.use(express.static('.'));
app.ws('/', function(ws, req) {
var seed = new Date().valueOf() & 0xFFFFFFFF;
var rnd = betterRand(seed)
var userId = new Buffer(seed.toString()+","+rnd.next().value).toString("base64")
var numbers = Array.from(Array(6)).map(() => Math.floor(rnd.next().value * 89 + 10))
ws.on('message', function(msg) {
try {
var m = JSON.parse(msg.replace("'", '').replace("'", ''));
var resp = {"numbers": numbers}
if(JSON.stringify(resp.numbers) === JSON.stringify(m.numbers))
resp.flag = flag;
console.log(resp);
ws.send(JSON.stringify(resp));
} catch(err) { }
ws.close()
});
console.log("[*] Peer connected!");
ws.send(JSON.stringify({"userId": userId}))
});
console.log("[*] Listening on port 5555...")
app.listen(5555);
function* betterRand(seed) {
var m = 25, a = 11, c = 17, z = seed || 3;
for(;;) yield (z=(a*z+c)%m)/m;
}
Widzimy, że po nawiązaniu połączenia WebSocket jest nam losowany seed i przekazywany do funkcji betterRand
, z której następnie są losowane nasze szczęśliwe liczby i porównywane. Pozostaje przepisać kod i odpalić z wygenerowanym już przez program ziarnem. Ziarno:
1
2
$ echo "LTgzNTI4OTgyMywtMC40NA==" | base64 -d
> -835289823,-0.44
Pierwsza wartość to nasze ziarno a druga to “losowa liczba”, teraz wystarczy podstawić nasz seed pod skrypt i otrzymamy liczby jakie wybrał sobie serwer:
1
2
3
4
5
6
7
8
function* betterRand(seed) {
var m = 25, a = 11, c = 17, z = seed || 3;
for(;;) yield (z=(a*z+c)%m)/m;
}
var rnd = betterRand(-835230646)
rnd.next().value // pominięcie pierwszej liczby, która jest dołączana do userID
console.log(Array.from(Array(6)).map(() => Math.floor(rnd.next().value * 89 + 10)))
Pozostało nam tylko wpisać liczby i przesłać. Niestety frontend apki nie puści nas z ujemnymi liczbami więc w tym celu wykorzystałem postmana. Nawiązałem połączenie, wygenerowałem liczby i przesłałem je do serwera: