Bypass “Slider Captcha” dengan NodeJS dan Puppeteer

Aminudin
3 min readJul 10, 2021

--

https://monoplasty.github.io/vue-monoplasty-slide-verify/

Pada artikel kali ini saya akan membahas bagaimana cara bypass “captcha slider” seperti gambar diatas, ok langsung aja.

yang dibutuhkan adalah :

  • NodeJS
  • Imagemagick
  • Puppeteer

Untuk mencobanya saya menggunakan captcha dari https://monoplasty.github.io/vue-monoplasty-slide-verify/.

Untuk konsepnya sendiri adalah kita mempunya 2 Images yang pertama itu gambar captchanya itu sendiri dan yang kedua adalah bagian dari captcha nya itu sendiri yang bisa disebut sebagai ( sub images )

Setelah kita punya gambar itu semua lalu kita gunakan tools Imagemagick compare, yaitu untuk compare dua gambar. Seperti case diatas kita compare images dengan sub images lalu nantinya akan kita dapatkan titik coordinate dimana letak sub images pada imagesnya, lalu setelah kita dapatkan titik coordinatenya kita gunakan Puppeteer untuk menggerakan slider ke titik coordinate yang sudah kita tentukan.

Namun, ada kelemahan dari cara diatas yaitu kadang ada Sub Images yang tidak sesuai dengan Imagesnya entah dari background atau blur imagenya jadi harus banyak case atau ngga kalian bisa cari terus captcha yang sesuai.

Itu untuk konsepnya, next kita coba.

Pertama buat code seperti ini

const puppeteer = require('puppeteer');(async() => {const browser = await puppeteer.launch({headless: false,args: ["--start-maximized","--disable-popup-blocking","--allow-popups-during-page-unload"]});const page = await browser.newPage();await page.goto("https://monoplasty.github.io/vue-monoplasty-slide-verify/", { waitUntil: 'networkidle2' });const element = await page.$('#slideVerify > canvas:nth-child(2)');await element.screenshot({path: 'images.png'});})();

Pertama yang kita lakukan adalah screenshot Images captchanya lalu kita simpan dengan nama images.png.

Setelah itu kita gambar bounding boxnya dimana nantinya mouse akan kita handle kesitu

const puppeteer = require('puppeteer');(async() => {const browser = await puppeteer.launch({headless: false,args: ["--start-maximized","--disable-popup-blocking","--allow-popups-during-page-unload"]});const page = await browser.newPage();await page.goto("https://monoplasty.github.io/vue-monoplasty-slide-verify/", { waitUntil: 'networkidle2' });const element = await page.$('#slideVerify > canvas:nth-child(2)');await element.screenshot({path: 'images.png'});await page.waitForSelector(".slide-verify-slider-mask-item", { visibe: true, timeout: 5000 });const sliderHandler = await page.$('.slide-verify-slider-mask-item');const handler = await sliderHandler.boundingBox();})();

Kalau sudah kita coba dulu untuk compare images dengan sub imagenya dengan command

magick compare -metric RMSE -subimage-search images.png punjul.png result.png

Lalu kita cek resultnya di result-0.png, dan ini sample resultnya :

Kalau yang sesuai itu imagesnya akan di block merah pada bagian yang mirip dengan sub imagesnya kalau tidak sesuai block merahnya mencar kemana mana hahaha.

Kalau sudah sesuai sekarang kita tambahkan code untuk run command magick compare pada script yang tadi sudah kita buat dan kita tambahkan juga script untuk menggerakan slidernya, ini full scriptnya :

const puppeteer = require('puppeteer');const fs = require("fs");const exec = require('child_process').exec;(async() => {const browser = await puppeteer.launch({headless: false,args: ["--start-maximized","--disable-popup-blocking","--allow-popups-during-page-unload"]});const page = await browser.newPage();await page.goto("https://monoplasty.github.io/vue-monoplasty-slide-verify/", { waitUntil: 'networkidle2' });const element = await page.$('#slideVerify > canvas:nth-child(2)');await element.screenshot({path: 'images.png'});await page.waitForSelector(".slide-verify-slider-mask-item", { visibe: true, timeout: 5000 });const sliderHandler = await page.$('.slide-verify-slider-mask-item');const handler = await sliderHandler.boundingBox();exec("compare -metric RMSE -subimage-search images.png punjul.png result.png", async (result, _, _1) => {const x = result.toString().split('@')[result.toString().split('@').length-1].trim().split(',')[0];const y = result.toString().split('@')[result.toString().split('@').length-1].trim().split(',')[1];await page.mouse.move(handler.x, handler.y);await page.mouse.down();const valueData = (parseInt(x))let currentPosition = 0for (let index = 0; index < valueData; index++) {await page.mouse.move(handler.x+currentPosition, handler.y);currentPosition = index++}await page.mouse.move(handler.x+currentPosition, handler.y, {stpes:10});await page.mouse.up();});})();

Selebihnya tinggal sesuaikan sub images valueDatanya, Terimakasih banyak yang sudah baca :D

--

--

Responses (1)