Peretasan Google Translation API

Sebagai bagian dari Google Cloud-nya, Google menawarkan Google Translation API dengan struktur biaya berbasis penggunaan. Ada juga API tidak berdokumen yang dapat digunakan tanpa kunci , tetapi menolak untuk bekerja setelah beberapa permintaan. Saat menggunakan fungsi terjemahan situs web Google Chrome, terlihat bahwa halaman dapat diterjemahkan dengan kualitas yang sangat baik tanpa batasan yang nyata.


Rupanya model nmt lanjutan sudah digunakan di sini. Tetapi API mana yang digunakan Google Chrome secara internal untuk menerjemahkan konten dan dapatkah API ini juga ditangani secara langsung - bahkan di sisi server? Untuk menganalisis lalu lintas jaringan, alat seperti Wireshark atau Telerik Fiddler , yang juga dapat menganalisis lalu lintas terenkripsi, direkomendasikan. Tetapi Chrome bahkan mengirimkan permintaan yang dikirimkannya untuk terjemahan halaman secara gratis: Mereka dapat dengan mudah dilihat menggunakan Chrome DevTools:

Jika Anda melakukan terjemahan, tangkap permintaan POST penting ke https://translate.googleapis.com melalui "Salin> Salin sebagai cURL (bash)" dan jalankan di alat seperti Postman , misalnya, Anda dapat mengirim permintaan lagi tanpa masalah:

Arti dari parameter URL juga sangat jelas:

KunciContoh nilaiBerarti
anno3Mode anotasi (mempengaruhi format pengembalian)
kliente_libInformasi klien (bervariasi, nilainya adalah "webapp" melalui antarmuka web Google Terjemahan; berpengaruh pada format pengembalian dan pembatasan tarif)
formathtmlFormat string (penting untuk menerjemahkan tag HTML)
v1.0Nomor versi Google Terjemahan
kunciAIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgwKunci API (lihat di bawah)
logldvTE_20200210_00Versi protokol
sldeBahasa sumber
tlenBahasa target
spnmtModel ML
tc1tidak diketahui
sr1tidak diketahui
tk709408.812158Token (lihat di bawah)
Mode1tidak diketahui

Beberapa header permintaan juga disetel - tetapi ini sebagian besar dapat diabaikan. Setelah secara manual membatalkan pilihan semua header, termasuk yang berasal dari agen pengguna , masalah encoding ditemukan saat memasukkan karakter khusus (di sini saat menerjemahkan " Hello World "):

Jika Anda mengaktifkan kembali agen pengguna (yang umumnya tidak membahayakan), API mengirimkan karakter yang dikodekan UTF-8:

Apakah kita sudah berada di sana dan apakah kita memiliki semua informasi untuk menggunakan API ini di luar Google Chrome? Jika Anda mengubah string yang akan diterjemahkan (bidang data q permintaan POST) dari, misalnya, “Hello world” menjadi “Hello world ! “, Kami mendapatkan pesan kesalahan:

Kami sekarang menerjemahkan yang dimodifikasi ini lagi dalam Google Chrome menggunakan fungsi terjemahan situs web dan menemukan bahwa, selain parameter q , parameter tk juga berubah (semua parameter lainnya tetap sama):

Jelas, ini adalah token yang bergantung pada string, yang strukturnya tidak mudah dilihat. Saat Anda memulai terjemahan situs web, file berikut dimuat:

  • 1 file CSS: translateelement.css
  • 4 grafik: translate_24dp.png (2x), gen204 (2x)
  • 2 file JS: main_de.js , element_main.js

Kedua file JavaScript dikaburkan dan dikecilkan. Alat seperti JS Nice dan de4js sekarang membantu kami membuat file ini lebih mudah dibaca. Untuk men- debugnya secara langsung, kami merekomendasikan Ekstensi Chrome Requestly, yang menggabungkan file jarak jauh secara lokal dengan cepat:

Sekarang kita dapat men-debug kode ( CORS harus diaktifkan terlebih dahulu di server lokal). Bagian kode yang relevan untuk membuat token tampaknya tersembunyi di file element_main.js di bagian ini:

b7739bf50b2edcf636c43a8f8910def9

Di sini teks di-hash dengan bantuan beberapa pergeseran bit . Namun sayangnya kami masih kehilangan satu bagian dari teka-teki: Selain argumen a (yang merupakan teks yang akan diterjemahkan), argumen lain b diteruskan ke fungsi Bp () - semacam benih yang tampaknya berubah dari waktu ke waktu dan itu juga termasuk mengalir ke hashing. Tapi dari mana asalnya? Jika kita melompat ke pemanggilan fungsi Bp () , kita menemukan bagian kode berikut:

b7739bf50b2edcf636c43a8f8910def9

Fungsi Hq dideklarasikan sebelumnya sebagai berikut:

b7739bf50b2edcf636c43a8f8910def9

Di sini Deobfuscater meninggalkan beberapa sampah; Setelah kita mengganti String.fromCharCode ('...') dengan string karakter masing-masing, hapus a () yang sudah usang dan satukan pemanggilan fungsi [c (), c ()] , hasilnya adalah:

b7739bf50b2edcf636c43a8f8910def9

Atau bahkan lebih mudah:

b7739bf50b2edcf636c43a8f8910def9

Fungsi yq sebelumnya didefinisikan sebagai:

b7739bf50b2edcf636c43a8f8910def9

Benih tampaknya berada di objek global google.translate._const._ctkk , yang tersedia saat runtime. Tapi di mana itu diatur? Di sisi lain, file JS main_de.js yang dimuat sebelumnya , setidaknya itu juga tersedia di awal. Kami menambahkan yang berikut di awal:

b7739bf50b2edcf636c43a8f8910def9

Di konsol kami benar-benar mendapatkan benih saat ini:

Ini meninggalkan Google Chrome sendiri, yang tampaknya menyediakan benih, sebagai opsi terakhir. Untungnya, kode sumbernya (Chromium, termasuk komponen Terjemahan) adalah sumber terbuka dan oleh karena itu tersedia untuk umum. Kami menarik repositori secara lokal dan menemukan panggilan fungsi TranslateScript :: GetTranslateScriptURL di file translate_script.cc di folder components / translate / core / browser:

b7739bf50b2edcf636c43a8f8910def9

Variabel dengan URL ditentukan dengan pasti di file yang sama:

b7739bf50b2edcf636c43a8f8910def9

Jika sekarang kita memeriksa file element.js lebih dekat (setelah deobfuscate lagi), kita menemukan entri hard-set c._ctkk - objek google.translate juga disetel sesuai dan pemuatan semua aset yang relevan (yang telah kita temukan sebelumnya) dipicu:

b7739bf50b2edcf636c43a8f8910def9

Sekarang kunci parameter tetap untuk dipertimbangkan (dengan nilai AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw). Tampaknya itu adalah kunci API browser umum (yang juga dapat ditemukan di beberapa hasil Google ). Sudah diatur di Chromium di file translate_url_util.cc di folder komponen / terjemahkan / inti / browser:

b7739bf50b2edcf636c43a8f8910def9

Kunci dibuat di google_apis / google_api_keys.cc dari nilai dummy:

b7739bf50b2edcf636c43a8f8910def9

Namun, pengujian menunjukkan bahwa panggilan API berfungsi sama tanpa parameter kunci ini. Jika Anda bereksperimen dengan API, Anda akan mendapatkan kode status 200 kembali jika Anda berhasil. Jika Anda kemudian menemui batas, Anda mendapatkan kode status 411 kembali dengan pesan " Permintaan POST memerlukan header panjang konten ". Oleh karena itu, disarankan untuk menyertakan header ini (yang secara otomatis ditetapkan sebagai header sementara di Postman).

Format pengembalian dari string yang diterjemahkan tidak biasa jika ada beberapa kalimat dalam satu permintaan. Kalimat individual diapit oleh tag i- / b-HTML:

Selain itu, Google Chrome tidak mengirim seluruh HTML ke API, tetapi menyimpan nilai atribut seperti href dalam permintaan (dan sebagai gantinya menyetel indeks sehingga tag nantinya dapat ditetapkan di sisi klien):

Jika Anda mengubah nilai klien kunci POST dari te_lib (Google Chrome) di webapp ( situs web Google Terjemahan ), Anda mendapatkan string terjemahan terakhir:

Masalahnya adalah Anda lebih cenderung mengalami pembatasan kecepatan daripada melalui te_lib (sebagai perbandingan: dengan webapp ini dicapai setelah 40.000 karakter, dengan te_lib tidak ada pembatasan kecepatan). Jadi kita perlu melihat lebih dekat bagaimana Chrome mengurai hasilnya. Kami akan menemukannya di sini di element_main.js:

b7739bf50b2edcf636c43a8f8910def9

Jika Anda mengirim seluruh kode HTML ke API, atribut dalam respons diterjemahkan. Oleh karena itu, kami tidak harus meniru seluruh perilaku parse, tetapi hanya mengekstrak string terjemahan terakhir dari respons. Untuk melakukannya, kami membuat parser tag HTML kecil yang membuang tag <i> terluar termasuk kontennya dan menghapus <b> tag terluar. Dengan pemikiran ini, sekarang kita dapat membuat versi sisi server dari API terjemahan:

b7739bf50b2edcf636c43a8f8910def9

Berikut ini adalah hasil pengujian awal yang dilakukan pada lima sistem berbeda dengan bandwidth dan alamat IP berbeda:

KarakterKarakter per permintaanDurasiTingkat kesalahanBiaya melalui API resmi
13.064.662~25003:36:170%237,78€
24.530.510~25011:09: 13h0%446,46€
49.060.211~25020:39: 10j0%892,90€
99.074.487~100061: 24: 37h0%1803,16€
99.072.896~100062: 22: 20h0%1803,13€
Σ284.802.766~ Ø550Σ159: 11: 37h0%Σ € 5183,41

Catatan: Entri blog ini termasuk semua skrip ditulis untuk tujuan pengujian saja. Jangan menggunakan script untuk penggunaan produktif, bukan bekerja dengan resmi API Google Terjemahan .

Kembali