Membongkar PRNG Go untuk Kesenangan dan Keuntungan (Virtual)

lgosuper slot login

indo 36 slot

brownlow betting market

download higgs slot mod apk

Seorang teman baru-baru ini membangun Mongobucks, sebuah aplikasi rekreasional Golang yang memungkinkan pengguna bertukar dan berjudi dengan mata uang virtual. Setiap pengguna memulai dengan sejumlah token virtual tetap, dan mereka dapat memberikan atau menerima token ini dari pengguna lain. Aplikasi ini juga menyertakan fitur "judi" dasar. Fitur ini memungkinkan Anda untuk mempertaruhkan sejumlah token, dan kemudian bertaruh pada hasil dari lemparan koin virtual. Tidak lama sebelum ini, saya mendengar sebuah cerita tentang peretas Rusia yang mampu membobol mesin slot kasino dengan mengeksploitasi generator angka acak yang lemah, dan saya penasaran apakah hal serupa mungkin dilakukan di sini.

Kode sumber aplikasi tersedia untuk umum, yang memungkinkan saya menyelidiki internal aplikasi. Logika perjudian menggunakan paket `math/rand` Go untuk menghasilkan hasil lemparan koin virtual, yang menarik minat saya. Tentu saja, aplikasi apa pun yang peduli dengan keamanan harus menggunakan generator angka acak yang aman secara kriptografis, yang disediakan Go sebagai bagian dari paket `crypto/rand`. Namun, sebagai tantangan pribadi, saya ingin melihat seberapa sulit untuk membobol generator angka default Go dan mengalahkan sistem perjudian aplikasi.

Arsitektur Aplikasi

Struktur aplikasi Mongobucks sangat sederhana. Ada satu server yang menangani permintaan masuk untuk mentransfer uang antar pengguna, atau untuk mengeksekusi taruhan baru. Ada database backend yang menyimpan informasi pengguna dan mencatat operasi. Setiap taruhan yang terjadi, dan hasilnya, akan disimpan beserta stempel waktu kapan taruhan itu terjadi. Pengguna dapat berinteraksi dengan aplikasi melalui bot Slack atau antarmuka web. Dengan mengikis API web publik, dimungkinkan untuk mendapatkan daftar lengkap dan terurut dari semua taruhan yang pernah terjadi. Server aplikasi menggunakan generator angka acak global tunggal untuk mensimulasikan lemparan koin virtual, jadi hipotesis awal saya sangat sederhana: setiap taruhan sesuai dengan satu generasi dari generator angka acak internal aplikasi. Ini membentuk dasar pendekatan peretasan awal saya: diberikan urutan nilai yang dihasilkan oleh generator angka acak internal, cari cara untuk memprediksi nilai berikutnya yang akan dihasilkan. Ini akan memungkinkan saya memprediksi hasil taruhan apa pun dengan akurasi sempurna. Dalam sisa posting ini, saya akan merujuk pada urutan taruhan sebagai urutan biner, karena setiap taruhan, dan output generator angka acak yang sesuai, adalah kepala atau ekor yaitu 0 atau 1.

Benih yang Buruk

Antarmuka ke generator angka acak Go disediakan dalam `math/rand/rand`. Algoritma generator angka acak semu inti Go (`math/rand/rng`) tidak terlalu terdokumentasi dengan baik tetapi setelah beberapa pencarian tampaknya itu adalah implementasi dari algoritma terkenal, Generator Fibonacci Lagged Aditif. Ini adalah artikel bagus yang menjelaskan beberapa detail internal generator angka Go.

Sebuah "sumber" generator angka acak adalah contoh dari generator angka acak dengan keadaan internal yang dienkapsulasi. Sumber RNG yang berbeda dapat dijalankan secara independen satu sama lain tanpa mempengaruhi keadaan internal sumber yang berbeda. Untuk memberi benih pada sumber, Go menyediakan fungsi berikut

func (r *Rand) Seed(seed int64)

yang mengambil bilangan bulat 64-bit sebagai argumennya. Benih generator angka acak adalah cara untuk menginisialisasi sumber generator ke keadaan deterministik. Ini berarti bahwa dua sumber terpisah, jika diinisialisasi dengan benih yang sama, akan menghasilkan urutan output yang sama. Fungsi `rand` bergantung pada fungsi internal lain, fungsi `Seed` di `math/rand/rng`, yang menjalankan logika pembenihan inti:

// Seed menggunakan nilai benih yang diberikan untuk menginisialisasi generator ke status deterministik.
func (rng *rngSource) Seed(seed int64) {
rng = 0
rng = _LEN - _TAP
seed = seed % _M
if seed < 0 {
seed += _M
}
if seed == 0 {
seed = 89482311
}
x := int32(seed)
for i := -20; i < _LEN; i++ {
x = seedrand(x)
if i >= 0 {
var u int64
u = int64(x) << 40
x = seedrand(x)
u ^= int64(x) << 20
x = seedrand(x)
u ^= int64(x)
u ^= rng_cooked[i]
rng[i] = u
}
}
}

Detail aritmetika benih tidak terlalu penting, tetapi ada satu bagian yang menarik. Variabel yang digarisbawahi yang muncul dalam fungsi ini adalah konstanta yang didefinisikan di bagian atas file yang sama:

const (
_LEN = 607
_TAP = 273
_MAX = 1 << 63
_MASK = _MAX - 1
_A = 48271
_M = (1 << 31) - 1
_Q = 44488
_R = 3399
)

Nilai `_M` terlihat mencurigakan yaitu baris 6 dari fungsi `Seed` di atas: `seed = seed % _M`. Argumen benih yang diberikan diambil modulo `_M = (1 << 31) - 1` (2^31 - 1). Jadi, meskipun argumen benih diberikan sebagai bilangan bulat 64-bit, hanya 31 bit yang benar-benar digunakan. Dengan kata lain, hanya ada 2^31 - 1 benih unik, karena argumen benih mengalami operasi modulo sebelum digunakan dalam logika pembenihan yang sebenarnya. Ini tampak agak aneh. Ketika saya kembali melihat dokumentasi resmi Go, saya menyadari bahwa detail ini sebenarnya disebutkan. Namun, akan mudah terlewatkan, terutama jika Anda menggunakan fungsi `Seed` hanya dengan melihat tanda tangan fungsinya. Dokumentasi Go untuk `math/rand` berbunyi:

Seed menggunakan nilai benih yang diberikan untuk menginisialisasi Sumber default ke status deterministik. Jika Seed tidak dipanggil, generator berperilaku seolah-olah dibenih oleh Seed(1). Nilai benih yang memiliki sisa yang sama ketika dibagi dengan 2^31-1 menghasilkan urutan pseudo-acak yang sama.

Temuan ini menginspirasi pendekatan baru. Dengan 2^64 kemungkinan benih, sebelumnya tampak tidak mungkin bagi saya untuk mencoba pendekatan brute force untuk menemukan benih asli. Dengan hanya 2^31 kemungkinan benih, itu tampak lebih masuk akal.

Menemukan Benih

Jika saya bisa mengetahui benih awal, maka saya akan memiliki cara untuk mengetahui seluruh urutan taruhan di masa depan. Server aplikasi memberikan benih pada generator angka acak global sekali saat startup, dan menghasilkan angka acak untuk taruhan berdasarkan benih awal itu, sampai proses server dihentikan dan dimulai lagi. Seperti yang saya sebutkan di atas, saya dapat mengkompilasi urutan terurut dari semua taruhan yang pernah terjadi. Di bagian berikut saya akan merujuk pada urutan global taruhan ini sebagai GamblaSeq.

Jika server telah dimulai ulang beberapa kali selama masa pakai aplikasi, harus ada posisi dalam GamblaSeq di mana urutan tersebut dibenih ulang. Jika saya bisa menemukan titik pembenihan ulang yang paling baru, dan benihnya, maka saya akan dapat memprediksi semua output masa depan GamblaSeq dengan melanjutkan dari titik pembenihan ulang.

Untuk menemukan titik pembenihan ulang dalam urutan, saya mencoba menggunakan awalan dari urutan angka acak sebagai cara untuk "sidik jari" urutan acak. Karena hanya ada 2^31 - 1 benih unik, pasti ada tidak lebih dari 2^31 - 1 urutan angka acak unik. Jadi, setiap urutan harus memiliki awalan 31-bit yang unik.

Bahkan jika ada tabrakan awalan antara urutan (yang saya anggap sangat tidak mungkin), urutan dengan awalan yang bertabrakan dapat dengan mudah dibedakan dengan melihat awalan urutan yang lebih panjang. Dengan pemikiran ini, saya membuat tabel pencarian yang memetakan awalan urutan panjang 31 ke benih yang menghasilkannya. Tabel akhir terlihat seperti berikut:

Awalan UrutanBenih
01110001011000000101010000111000
00100111011010011101000101011011
00110010101001101000000011011012
......
01101100101000001100000000010112147483647

Setiap kunci adalah nilai 31-bit, dan setiap nilai adalah benih 64-bit. Untuk kesederhanaan, keduanya disimpan sebagai nilai 64-bit, jadi setiap pasangan kunci-nilai memakan sekitar 16 byte (8 byte untuk setiap bilangan bulat 64-bit). Ada 2^31 - 1 benih unik, jadi seluruh tabel memakan sekitar: 2^31 benih * 16 byte/entri = 34.359.738.368 byte ≈ 32 GB

Saya menghasilkan tabel pencarian menggunakan skrip Go yang memasukkan pasangan kunci-nilai sebagai dokumen dalam database MongoDB. Butuh waktu sekitar satu jam untuk menghasilkan pada workstation Linux Ubuntu 12-core (Intel i7-4930K CPU @ 3.40GHz).

Tabel pencarian ini memberi saya kemampuan untuk secara efisien menemukan benih untuk setiap awalan urutan 31-bit yang diberikan. Untuk menemukan posisi pembenihan ulang di GamblaSeq, saya memindai GamblaSeq melihat suburutan panjang 31 dan mencari benih yang sesuai di tabel. Saya kemudian akan memeriksa apakah benih menghasilkan urutan yang benar di luar suburutan 31 elemen. Jika tidak, saya menganggapnya sebagai positif palsu yaitu itu sebenarnya bukan titik pembenihan ulang. Sayangnya, pendekatan ini tidak memberikan hasil yang saya harapkan. Saya tidak dapat menemukan titik dalam urutan di mana benih menghasilkan suburutan yang melampaui 31 elemen.

Ketika saya tidak dapat menghasilkan hasil yang memuaskan dengan pendekatan ini, saya kembali ke papan gambar dan mencoba memverifikasi bahwa semua asumsi saya tentang bagaimana urutan angka dihasilkan adalah benar.

Interferensi Acak

Kode sumber aplikasi tersedia, jadi saya dapat mengunduhnya dan menjalankannya secara lokal. Saya ingin memeriksa asumsi saya bahwa setiap taruhan yang dieksekusi sesuai dengan 1 pembangkitan angka acak. Ini adalah asumsi dasar yang menjadi andalan pendekatan pertama saya yaitu bahwa saya mengamati urutan hasil taruhan yang berdekatan dan karena itu output generator angka acak yang berdekatan. Saat menjalankan aplikasi di Macbook saya dan mensimulasikan beberapa taruhan, saya dapat memverifikasi bahwa setiap taruhan memajukan generator acak global tepat 1 generasi. Setelah menjalankan aplikasi untuk sementara dan menggunakan berbagai perilaku lain, ini tetap berlaku. Karena ini tampaknya tidak sesuai dengan apa yang saya amati terhadap aplikasi nyata, saya mencoba memastikan bahwa saya meniru lingkungan yang tepat dari aplikasi yang digunakan.

Aplikasi produksi berjalan dalam wadah Docker berbasis Linux, jadi saya menjalankan aplikasi secara lokal di dalam konfigurasi wadah Docker yang sama. Pengaturan ini menghasilkan perilaku yang berbeda secara signifikan mengenai cara aplikasi menghasilkan angka acak. Untuk setiap eksekusi taruhan, saya akan memeriksa apakah RNG melewatkan satu generasi. Tampaknya, pada interval konstan, setiap sekitar 30 detik, RNG akan melompat maju, rata-rata, 12-13 generasi. Ini tampak aneh. Karena aplikasi menggunakan generator angka acak global Go, kode lain apa pun yang melakukan panggilan ke sana akan mempengaruhi keadaan generator. Tidak banyak paket Go di luar pustaka standar yang digunakan oleh kode perjudian. Namun, setelah mencari basis kode Go sedikit, saya menemukan beberapa tempat yang menonjol yang melakukan panggilan ke generator angka acak global. Salah satu yang tampak signifikan adalah dalam logika resolusi DNS Go. Cuplikan kode ringkas berikut adalah fungsi di dalam `net/dnsclient_unix.go`:

// exchange mengirimkan query pada koneksi dan mengharapkan respons.
func exchange(ctx contextt, server, name string, qtype uint16, timeout timeon) (*dnsMsg, error) {
// ...
// KODE DIHILANGKAN
// ...
for _, network := range []string{"udp", "tcp"} {
ctx, cancel := contextadline(ctx, time().Add(timeout))
defer cancel()
c, err := dS(ctx, network, server)
if err != nil {
return nil, err
}
defer c()
if d, ok := ctxne(); ok && !d() {
cdline(d)
}
out = uint16(rand()) ^ uint16(time().UnixNano())
in, err := cndTrip(&out)
if err != nil {
return nil, mapErr(err)
}
if inted { // lihat RFC 5966
continue
}
return in, nil
}
return nil, errors("tidak ada jawaban dari server DNS")
}

Pada baris 21 dalam cuplikan kode di atas, ada panggilan ke fungsi `rand` global yang digunakan untuk menghasilkan id paket DNS acak. Ini menjanjikan, karena tampaknya resolusi DNS bisa menjadi bagian kode yang panas untuk apa pun yang membuat permintaan jaringan. Jika bagian kode ini sebenarnya adalah sumber interferensi RNG dalam aplikasi produksi, masih ada dua pertanyaan yang harus dijawab:

  1. Mengapa lompatan ini hanya diamati saat dijalankan di wadah Docker, tetapi tidak saat pengujian lokal di Mac saya?
  2. Apa yang menjelaskan lompatan generasi yang terjadi pada interval 30 detik yang teratur?

Jawaban 1: Resolusi DNS yang Bergantung pada Platform

Hipotesis kerja saya adalah bahwa kode resolusi DNS menyuntikkan lompatan ekstra ke dalam generator angka global, tetapi saya ingin membuat tes yang akan memvalidasi ini. Ternyata tes ini juga berfungsi sebagai cara untuk melihat mengapa perilaku aplikasi berbeda antara wadah Docker dan Macbook saya. Saya membuat skrip Go sederhana ini:

package main

import "fmt"
import "net/http"
import "math/rand"

func main() {
var seed int64 = 42
rand(seed)
fmt("Dibenih 'rand' dengan %d\n", seed)

fmt("Sebelum permintaan HTTP: %d\n", rand())
http("http://google")
fmt("Setelah permintaan HTTP: %d\n", rand())
}

Skrip ini memberikan benih `math/rand` dengan benih tetap dan arbitrer, menghasilkan satu angka, membuat permintaan HTTP, dan kemudian menghasilkan angka kedua. Dalam dokumentasi Go tentang resolusi DNS, ada catatan tentang keberadaan dua resolver DNS yang berbeda. Anda dapat secara opsional menggunakan resolver DNS pustaka C asli, atau resolver Go murni, dan ini dapat dikonfigurasi melalui variabel lingkungan `GODEBUG`. Ini adalah output terminal dari skrip di atas ketika dijalankan dengan dua resolver DNS yang berbeda:

Sebelum permintaan HTTP: 3440579354231278675
Setelah permintaan HTTP: 608747136543856411 (dengan resolver cgo)

Sebelum permintaan HTTP: 3440579354231278675
Setelah permintaan HTTP: 3534334367214237261 (dengan resolver go)

Outputnya berbeda, tetapi mengapa? Menjadi jelas jika kita melihat output dari program Go yang mencetak 6 angka pertama dari urutan acak yang dihasilkan dengan benih 42:

Generasi 0: 3440579354231278675
Generasi 1: 608747136543856411
Generasi 2: 5571782338101878760
Generasi 3: 1926012586526624009
Generasi 4: 404153945743547657
Generasi 5: 3534334367214237261

Saat menggunakan resolver DNS `cgo`, permintaan HTTP tidak mempengaruhi generator angka acak, tetapi saat menggunakan resolver `go`, permintaan HTTP melompatkan generator angka acak maju sebanyak 4 generasi! Ini tampak seperti tanda yang sangat jelas bahwa resolver DNS adalah penyebab yang mungkin untuk interferensi generator acak. Dokumentasi Go untuk paket `net` mendukung hipotesis ini:

Metode untuk menyelesaikan nama domain... bervariasi menurut sistem operasi. Pada sistem Unix, resolver memiliki dua opsi untuk menyelesaikan nama. Ia dapat menggunakan resolver Go murni yang mengirim permintaan DNS langsung ke server yang terdaftar di /etc/resolv, atau ia dapat menggunakan resolver berbasis cgo yang memanggil rutin pustaka C seperti getaddrinfo dan getnameinfo. Secara default, resolver Go murni digunakan... resolver berbasis cgo digunakan sebagai gantinya di bawah berbagai kondisi: pada sistem yang tidak mengizinkan program membuat permintaan DNS langsung (Mac OS X),...

Ini cocok dengan perilaku yang saya amati. Di Macbook saya, jika resolver C digunakan, itu tidak akan memanggil kode Go, dan karena itu generator angka acak global tidak akan terpengaruh. Di Linux, bagaimanapun, resolver DNS akan memajukan keadaan generator angka global, mempengaruhi output angka acak yang saya amati. Ini berfungsi sebagai penjelasan untuk interferensi generator angka acak yang saya amati saat menjalankan aplikasi di wadah Docker Linux.

Jawaban 2: Driver Database MongoDB mgo

Setelah menentukan bahwa resolver DNS adalah penyebab paling mungkin untuk lompatan generasi, saya ingin mencari tahu mengapa itu terjadi pada interval yang tampaknya teratur. Jika aplikasi tidak aktif yaitu tidak ada pengguna yang aktif, tampaknya hanya ada sedikit komponen yang mungkin membuat permintaan jaringan dan karena itu menyebabkan pencarian DNS. Namun, satu kandidat adalah driver database. Untuk menyimpan berbagai jenis data aplikasi, server, saat startup, membuat koneksi ke set replika MongoDB Atlas, melalui driver mgo. Saya ingin melihat apakah driver tersebut berpotensi mengeksekusi permintaan pada beberapa utas latar belakang, bahkan ketika tidak ada aktivitas pengguna yang eksplisit. Saya mencoba memonitor lalu lintas jaringan saat aplikasi berjalan secara lokal, dan saya menelusuri kode sumber mgo sedikit, dengan mengingat interval waktu 30 detik. Logika ini, di `mgo/cluster`, tampaknya menjadi kandidat yang baik:

// Berapa lama menunggu untuk pemeriksaan topologi cluster jika tidak ada hal lain
// yang memicu sinkronisasi sebelumnya.
const syncServersDelay = 30 * time
const syncShortDelay = 500 * timeecond

// syncServersLoop berulang selama cluster masih hidup untuk menjaga idenya
// tentang topologi server tetap terbaru. Ini harus dipanggil hanya sekali dari
// newCluster. Loop ini berulang sekali syncServersDelay telah berlalu, atau
// jika seseorang menyuntikkan nilai ke dalam channel cluster untuk memaksa
// sinkronisasi. Satu iterasi loop akan menghubungi semua server secara paralel,
// menanyai mereka tentang rekan yang dikenal dan peran mereka sendiri dalam
// cluster, dan kemudian mencoba melakukan hal yang sama dengan semua rekan
// yang diambil.
func (cluster *mongoCluster) syncServersLoop() {
...
}

Logika pemeriksaan status ini berjalan sekali setiap 30 detik. Ini cocok dengan interval lompatan generasi, dan juga dengan jumlah lompatan yang saya lihat, yang sekitar 12 rata-rata. Permintaan HTTP melompatkan generator angka acak maju 4 iterasi, dan jika driver mgo terhubung ke set replika 3-node untuk pemeriksaan status, itu akan cocok dengan 4 generasi * 3 koneksi = 12 generasi per pemeriksaan status. Saya juga memverifikasi perilaku ini dengan mengamati lalu lintas jaringan aplikasi secara lokal. Jelas bahwa itu akan mencoba membuat koneksi ke anggota cluster MongoDB secara periodik.

Ini adalah penjelasan yang memuaskan untuk interferensi acak yang saya amati dalam output RNG. Sekarang saya hanya perlu menerapkan temuan saya ke pendekatan baru untuk membobol sistem perjudian.

Menyatukan Semuanya

Saya sekarang memiliki pemahaman yang tampaknya lengkap tentang bagaimana urutan angka acak yang saya amati dihasilkan. Model saya adalah sebagai berikut:

Saya dapat mengamati sebagian urutan angka acak yang berdekatan, tetapi akan ada lompatan yang diselingi, di samping titik pembenihan ulang potensial. Saya harus memperhitungkan ini saat mencoba memprediksi output di masa depan.

Sidik Jari Suburutan

Inti dari pendekatan saya masih melibatkan menemukan titik pembenihan ulang terbaru dan nilai benihnya. Alih-alih mencari awalan dari urutan yang dihasilkan, saya berpikir bahwa jika saya dapat mengamati suburutan yang berdekatan dengan panjang yang cukup (misalnya ~64 elemen), ini juga dapat bertindak sebagai sidik jari untuk urutan acak, bahkan jika itu bukan awalan. Pemikiran saya adalah bahwa sangat tidak mungkin dua urutan acak yang berbeda (dari beberapa panjang terbatas yang wajar) mengandung suburutan 64 elemen yang persis sama. Ada 2^64 kemungkinan urutan biner panjang 64, tetapi, dalam urutan biner acak dengan panjang, katakanlah, 5000, hanya ada sekitar 5000 suburutan berbeda yang muncul (pikirkan menggeser jendela 64 elemen di sepanjang urutan 5000). Jadi, dalam satu urutan panjang N, Anda hanya melihat sekitar N dari 2^64 kemungkinan suburutan panjang 64. Ini berarti probabilitas suburutan panjang 64 tertentu muncul dalam urutan panjang N harus sangat rendah (≈ N/2^64), selama N << 2^64.

Membangun Bot Autotaruhan

Untuk mengetahui benih terbaru, kita dapat memasukkan sejumlah besar taruhan ke dalam sistem untuk memastikan bahwa kita mengamati urutan output yang berdekatan yaitu tidak ada lompatan generasi. Jika kita dapat memprediksi, secara kasar, kapan server terakhir dimulai ulang, kita dapat memperkirakan berapa banyak generasi yang telah berlalu secara total karena pemeriksaan status periodik. Kita kemudian dapat memiliki skrip Go yang menghasilkan urutan acak setidaknya sepanjang itu, dan kita dapat mencari suburutan yang diamati dalam urutan yang dihasilkan oleh setiap benih. Jika kita menemukan suburutan yang diamati dalam suatu urutan, maka kita harus memiliki benih kita.

Ada sesuatu yang penting untuk dicatat di sini. Sejak awal, saya melihat bahwa aplikasi sebenarnya memungkinkan Anda mengeksekusi taruhan dengan taruhan 0 token. Ini memberitahu Anda hasil lemparan koin taruhan, tetapi tidak ada uang yang pernah diperoleh atau hilang. Ini adalah salah satu penemuan asli yang menginspirasi investigasi saya ke dalam generator angka acak. Ini bisa, bisa dibilang, dianggap sebagai bug, tetapi itu adalah sesuatu yang tidak benar-benar merugikan atau membantu pengguna jahat. Dalam hal ini, karena generator angka acak aplikasi yang lemah, itu memungkinkan kebocoran informasi, tetapi, dengan generator angka yang kuat secara kriptografis, ini tidak akan menjadi masalah. Perilaku halus ini, bagaimanapun, memungkinkan saya untuk memperoleh informasi yang berguna tentang keadaan generator angka internal.

Setelah kita menentukan benih, kita dapat mulai bertaruh. Karena kita tahu bahwa setiap urutan generator angka acak yang berdekatan akan terganggu secara periodik, kita memperhitungkannya saat menyusun strategi taruhan. Pada dasarnya, strateginya adalah sebagai berikut:

  1. Masukkan sejumlah kecil taruhan ke dalam sistem secepat mungkin, sehingga menghasilkan serangkaian taruhan, sebut saja Primer, dengan (semoga) tanpa lompatan generator angka acak.
  2. Karena kita tahu urutan angka acak penuh (karena kita menemukan benih), gunakan urutan Primer untuk menemukan posisi kita dalam urutan. Seharusnya mudah untuk memperkirakan di mana kita berada dalam urutan karena kita dapat memperkirakan berapa lama sejak server dimulai.
  3. Setelah kita menentukan generasi RNG saat ini, kita mulai bertaruh, menggunakan setiap output berikutnya dari urutan angka acak sebagai prediksi kita. Kita bertaruh terus menerus hingga kekalahan pertama, pada tingkat risiko yang diinginkan. Setelah kita kalah, kita berasumsi bahwa pemeriksaan status periodik mengganggu rangkaian generasi berkelanjutan kita.
  4. Tunggu sebentar hingga pemeriksaan status selesai. Kemudian kembali ke langkah 1 dan ulangi.

Strategi ini, bahkan dengan kekalahan sesekali, atau gangguan tak terduga, pada akhirnya berhasil, sebagaimana dibuktikan oleh saldo akhir Mongobucks saya, yang jauh melampaui tanda satu miliar token.

Kesimpulan

Bagi saya, ini adalah eksplorasi yang menarik dari generator angka acak Go dan beberapa perilaku tak terduganya. Generator angka acak default harus selalu dianggap tidak aman, tetapi saya ingin melihat apa yang sebenarnya diperlukan untuk mengalahkan salah satu yang menggunakan algoritma yang tidak sepele. Ternyata ini adalah latihan yang baik dalam pemrograman, debugging, dan pengujian penetrasi.

bigo slot login

▲ Kembali ke atas

Platform Lainnya

casino carpet for sale

slot no limit city demo

i gamble

pajak 88 slot

Berita Piala Dunia

bet pramuka dipasang dimana

aloha slots

intertops classic casino

pas777 slot

Jika Anda memiliki pertanyaan, silakan kirim email ke [email protected]

▲ Kembali ke atas