(http://1.bp.blogspot.com/-Kaj4GWRPSTo/VNQZifsmy3I/AAAAAAAAAT8/PolYUA2eVOU/s1600/test.png) (http://1.bp.blogspot.com/-Kaj4GWRPSTo/VNQZifsmy3I/AAAAAAAAAT8/PolYUA2eVOU/s1600/test.png)
by hdbreaker
Hace algún tiempo tuve la mala fortuna de estar envuelto en un accidente de trafico algo grave, donde yo por viajar en moto, me lleve la peor parte. Totalmente en contra a lo que esperaba, el responsable del accidente no se detuvo a asistirme, por su parte prefirió darse a la fuga.
Luego de todos los protocolos médicos, unos cuantos moretones y tras no encontrar respuestas en la policía por falta de testigos, decidí comenzar una búsqueda personal de identificación del vehículo con el único dato que había logrado divisar en el golpe.
###su numero de patente###
Por cuestiones de confidencialidad no utilizare la patente real del agresor sino una que alcance a leer en el registro del automotor mientras realizaba los tramites del seguro.
¿La pregunta? Existe algún sistema que me permita consultar los datos y el estado de un vehículo que transita en la calle actualmente? La respuesta es si!
Luego de algunas consultas a google, logre dar con un servicio de Rentas en la provincia de Buenos Aires que nos permite consultar el estado de deuda de patentes de un vehículo.
https://lbserver02.agip.gob.ar/ConsultaPat/index.html (https://lbserver02.agip.gob.ar/ConsultaPat/index.html)
El mismo tiene dos formas de funcionar, si no eres el propietario solamente puedes obtener los datos correspondiente a deudas sobre el automóvil pero el sistema no te permite acceder a las secciones que identifica a la persona registrada en el Registro del Automotor como titular del vehículo.
Por otro lado, para comprobar la titularidad del vehículo, el sistema solicita ingresar un numero de verificación especial
único que solo el dueño del automóvil debe poseer, ya que el mismo sirve para imprimir boletas de pago de deudas que incluyen los datos personales del propietario del automotor, de esta forma garantiza la privacidad de los datos de los usuarios.
(http://3.bp.blogspot.com/-qB9xNkqbtHs/VNQfJe_tVKI/AAAAAAAAAUM/70QsGT-fpeQ/s1600/num.png) (http://3.bp.blogspot.com/-qB9xNkqbtHs/VNQfJe_tVKI/AAAAAAAAAUM/70QsGT-fpeQ/s1600/num.png)
Lo primero que podemos analizar en el sitio, es que el dígito especial y verificador del sistema, solo acepta valores que van desde 00 a 99 (el valor no es tan único como uno cree)
En fin, la patente a estudiar en esta entrada sera
JMO089, luego de realizar algunas pruebas manuales podemos apreciar que el captcha del sistema nunca es actualizado una vez que nos encontramos asociado a una sesión, permitiéndonos probar de forma manual las 99 combinaciones posibles hasta dar con la correcta.
(http://2.bp.blogspot.com/-lCSRLVEmFNI/VNQhXub3esI/AAAAAAAAAUY/I81TL06CM9Y/s1600/Sin%2Bnombre.png) (http://2.bp.blogspot.com/-lCSRLVEmFNI/VNQhXub3esI/AAAAAAAAAUY/I81TL06CM9Y/s1600/Sin%2Bnombre.png)
En la imagen podemos apreciar que el captcha no cambia a medida que vamos probando posibles combinaciones numéricas hasta lograr dar con el correcto, por lo que da la posibilidad de programar un Brute Forcer que valla probando todos los valores posibles hasta dar con el indicado. Pero un ataque así representa un problema al tener que enfrentarnos con un captcha, cosa que no estaba dispuesto por una falta de tiempo para programar un
OCR (http://webscraping.com/blog/Solving-CAPTCHA/).
La pregunta que me formule fue:
Cual es la forma en que el sistema valida el valor correcto del dígito verificador?Lo primero que pensé es que el sistema validaba el valor del lado del servidor luego de la consulta, por lo que me puse a comprobar las peticiones que realizaba el sitio al momento de enviar el formulario. Para esto utilice
Live HTTP headers(http://1.bp.blogspot.com/-wi2c_1oB0sk/VNQkcg_JOZI/AAAAAAAAAUk/qz6SK1EJIA8/s1600/ajax.png) (http://1.bp.blogspot.com/-wi2c_1oB0sk/VNQkcg_JOZI/AAAAAAAAAUk/qz6SK1EJIA8/s1600/ajax.png)
Al encontrarme con esto, no podía creer lo que estaba viendo, técnicamente hablando si una validación no presenta una petición web hacia el Backend, quiere decir que la validación se esta realizado del lado del cliente osea:
EL SISTEMA VALIDA POR JAVASCRIPT!
Esto implica que el algoritmo de validación del código verificador se encuentra servido en algún archivo
javascript del lado del navegador, por lo que me puse a analizar el source html del documento para lograr identificar algún indicio de la validación. Lo primero que analice fueron los siguientes archivos:
(http://4.bp.blogspot.com/-KjLsz9ou-FM/VNQmEVvOV2I/AAAAAAAAAUw/2AguNFy0xFk/s1600/ttt.png) (http://4.bp.blogspot.com/-KjLsz9ou-FM/VNQmEVvOV2I/AAAAAAAAAUw/2AguNFy0xFk/s1600/ttt.png)
Dentro del archivo
consultaDatos.js encontré la siguiente función con un nombre revelador:
validaDatos
(http://1.bp.blogspot.com/-mK0b28HlMos/VNQmv5XUaQI/AAAAAAAAAU4/BX-qrWpYwEA/s1600/validator.png) (http://1.bp.blogspot.com/-mK0b28HlMos/VNQmv5XUaQI/AAAAAAAAAU4/BX-qrWpYwEA/s1600/validator.png)
if (!check.checked && patente.valido(dom1) != true)
En la misma función se puede apreciar en las lineas remarcadas la estructura donde se decide el mensaje de patente valida cumpliendo los requisitos de que el
checkbox se encuentre marcado y el resultado de la función
patente.valido() sea el necesario para resolver de forma correcta la estructura de decisión
if().
El problema resulto que la función
patente.valido() no se encontraba dentro del mismo documento, por lo que debía encontrar el fichero donde se encontraba la misma.
Para lo que no conozcan el funcionamiento de javascript, les aclaro que los ficheros js representan un gran código estructurado dividido en distintos archivos para mejorar su organización, pero siempre que estos archivos sean incluidos en el html los mismos pueden realizar llamadas a las funciones definidas entre ellos como si todos fueran miembros de la misma clase.
Luego de buscar un poco, llegue al siguiente archivo:
(http://3.bp.blogspot.com/-VzGAp_0Rm0M/VNQpOUC5f2I/AAAAAAAAAVE/uBs_0swkoFA/s1600/pat.png) (http://3.bp.blogspot.com/-VzGAp_0Rm0M/VNQpOUC5f2I/AAAAAAAAAVE/uBs_0swkoFA/s1600/pat.png)
Dentro del mismo podemos obtener la estructura del código validador:
(http://2.bp.blogspot.com/-h0CKawpkx_Q/VNQpyo9SWII/AAAAAAAAAVM/yqNczRJ7AZI/s1600/getdv.png) (http://2.bp.blogspot.com/-h0CKawpkx_Q/VNQpyo9SWII/AAAAAAAAAVM/yqNczRJ7AZI/s1600/getdv.png)
Función Completa: http://pastebin.com/gYTdC9Yh (http://pastebin.com/gYTdC9Yh)
Luego de analizar detenida mente el código pude develar el comportamiento final del mismo.
El código calcula el dígito verificador en base a la patente del vehículo, sustituyendo las letras por números especiales para formar una cadena decimal, que luego suma según su indice, pares por un lado e impares por otro, como si de un array se tratase.
(http://1.bp.blogspot.com/-Ie58vHIagQY/VNQrEziWUUI/AAAAAAAAAVY/pX2M3Zc9uOw/s1600/tetete.png) (http://1.bp.blogspot.com/-Ie58vHIagQY/VNQrEziWUUI/AAAAAAAAAVY/pX2M3Zc9uOw/s1600/tetete.png)
Luego si estos valores separados (digi1 y digi2) tienen un largo superior a un dígito (0 a 9), vuelve a sumarlos respectivamente hasta obtener 2 números de forma independiente con un largo de un dígito (0 a 9).
Y luego los concatena para obtener el numero mágico verificador:
(http://1.bp.blogspot.com/-B7iqpLnp82I/VNQr4qxNCXI/AAAAAAAAAVg/5uRIZdU7AfM/s1600/salida.png) (http://1.bp.blogspot.com/-B7iqpLnp82I/VNQr4qxNCXI/AAAAAAAAAVg/5uRIZdU7AfM/s1600/salida.png)
Lo que resulta algo cómico es que esta función no tiene ninguna protección, y puede ser llamada desde la consola de desarrollo de Google Chrome o Firefox:
(http://4.bp.blogspot.com/-ImRsGXuhKfc/VNQseJUbl1I/AAAAAAAAAVo/WpdGiwnySNE/s1600/call.png) (http://4.bp.blogspot.com/-ImRsGXuhKfc/VNQseJUbl1I/AAAAAAAAAVo/WpdGiwnySNE/s1600/call.png)
Con este numero verificador podemos realizar la consulta de forma exitosa:
(http://2.bp.blogspot.com/-rnPrnoDRUjk/VNQtCQ-CziI/AAAAAAAAAVw/9sXsescIvw8/s1600/principal.png) (http://2.bp.blogspot.com/-rnPrnoDRUjk/VNQtCQ-CziI/AAAAAAAAAVw/9sXsescIvw8/s1600/principal.png)
Al momento de solicitar una factura podemos apreciar los datos personales como el nombre del titular registrado y la dirección residencial del mismo:
(http://1.bp.blogspot.com/-Sm6PzSW1M8U/VNQtS3TmFjI/AAAAAAAAAV4/aQ6q8AI22ok/s1600/datos.png) (http://1.bp.blogspot.com/-Sm6PzSW1M8U/VNQtS3TmFjI/AAAAAAAAAV4/aQ6q8AI22ok/s1600/datos.png)
Realizando un poco de ingienería inversa desarrolle el siguientes scripts que permiten calcular cualquier dígito verificador solo con el numero de patente:
(Próximamente estaré agregando su versión en Python desarrollada por [Q]3rv[0]):
Ruby:
require 'colorize' #by hdbreaker
class Calculate
def initialize()
#inicializo array asociativo de clase
@letrasValidas ={'A' => '14','B' => '01','C' => '00','D' => '16','E' => '05','F' => '20','G' => '19',
'H' => '09','I' => '24','J' => '07','K' => '21','L' => '08','M' => '04','N' => '13',
'O' => '25','P' => '22','Q' => '18','R' => '10','S' => '02','T' => '06','U' => '12',
'V' => '23','W' => '11','X' => '03','Y' => '15','Z' => '17',' ' => '60',};
end
#Funcion para calcular el numero de patente
def calculate(patente)
patAux = patente.upcase;
pares = 0;
impares = 0;
#Bloque para sustituir las letras por los numeros correspondisntes
@letrasValidas.each { |key|
if(patAux.include? key[0])
patAux = patAux.gsub(key[0], key[1]);
end
}
#Sumo los imares por un lado y los pares por el otro
for x in (0...patAux.length)
if (x % 2 == 0)
pares += patAux[x].to_i;
else
impares += patAux[x].to_i;
end
end
#Si la sumatoria de los pares da un numero mayor a 1 digito, los sumo nuevamente hasta obtener 1 digito
digi1 =pares.to_s;
while (digi1.length > 1)
pares = 0;
for x in (0...digi1.length)
pares += digi1[x].to_i;
end
digi1 = pares.to_s;
end
#Si la sumatoria de los impares da un numero mayor a 1 digito, los sumo nuevamente hasta obtener 1 digito
digi2 =impares.to_s;
while (digi2.length > 1)
impares = 0;
for x in (0...digi2.length)
impares += digi2[x].to_i;
end
digi2 = impares.to_s;
end
###############Salida en Pantalla###############
puts "\n############## Rentas Ciudad de Buenos Aires ##############".green
puts "URL: ".green+"https://lbserver02.agip.gob.ar/ConsultaPat/index.html".red
puts "Dominio: ".green+patente.red
puts "Verificador: ".green+digi1.red+""+digi2.red
puts "\n"
end
end
if(ARGV.length==1)
obj = Calculate.new()
obj.calculate(ARGV[0].to_s)
else
puts "Usage: ruby calculate.rb [patente]"
end
(http://1.bp.blogspot.com/-qYYlvHTBrt4/VNQx_GXRnNI/AAAAAAAAAWE/MbP8fPDnWQ0/s1600/jmo.png) (http://1.bp.blogspot.com/-qYYlvHTBrt4/VNQx_GXRnNI/AAAAAAAAAWE/MbP8fPDnWQ0/s1600/jmo.png)
Espero que esta entrega sirva para concientizar sobre la seguridad de nuestros datos personales, ya que recordemos que el fallo se encuentra en una red gubernamental que expone de forma descarada los datos personales de las personas.
Y si eres conductor... no vallas por la calle creyéndote intocable, nunca sabes con quien te puedes cruzar ni para que pueda utilizar tus datos, tal vez te encuentres con una persona que en vez de reportar el fallo utilice tu información para encontrarte, ir hacia tu casa y romperte las piernas.
Saludos!
Fuente: http://www.securitysignal.tk/2015/02/quien-te-choco-hackeado-patentes.html (http://www.securitysignal.tk/2015/02/quien-te-choco-hackeado-patentes.html)
Interesante aporte, buscaba algo asi y no lo pude encontrar !!
Muy interesante, la verdad lo leere cuando tenga tiempo. Eres de las personas que mas valoro sus aportes en esta comunidad me gusta sobre todo a parte de la presentación que su contenido es atractivo me quito el sombrero antes usted.
Un saludo!
No tienes permitido ver los links.
Registrarse o Entrar a mi cuenta
Muy interesante, la verdad lo leere cuando tenga tiempo. Eres de las personas que mas valoro sus aportes en esta comunidad me gusta sobre todo a parte de la presentación que su contenido es atractivo me quito el sombrero antes usted.
Un saludo!
Muchas gracias! y gracias a todos los lectores q valoran el trabajo de un researcher, da gusto compartir información y estudiar nuevas vulnerabilidades o simplemente curiosidades cuando los lectores agradecen, comparten o simplemente dan su opinion al respecto, creo q una comunidad esta para eso, para que entre todos podamos obtener una vista mucho mas objetiva y profesional sobre un fallo! Te invito pases a mi blog!
Madre mía, menuda ñapa hacer eso desde el lado del cliente... jajajaja. Enorme la idea de automatizarlo, HD!
No tienes permitido ver los links.
Registrarse o Entrar a mi cuenta
Madre mía, menuda ñapa hacer eso desde el lado del cliente... jajajaja. Enorme la idea de automatizarlo, HD!
En el blog esta el codigo en Python tambien!
Terrible post! Es increíble todo, desde encontrar la vulnerabilidad, explotarla y encima automatizarla! ;D
Sin duda fue un excelente trabajo!
Tremendo post!!!! Felicidades muy buen aporte, aca en mexico es diferente ya que para consultar necesitas el numero de matricula mas aparte los ultimos tres digitos(dependiendo de la ciudad) de el numero de tarjeta de circulacion del vehiculo estos numeros son unicos y no se de que manera se calcula un numero de circulacion, pero felicidades me gusto bastante.
Estos posts en forma de relato son cojonudos. Me pregunto qué otros sitios institucionales de allí tienen la misma implementación...
Kudos hdbreaker
Esto está muy bueno! Peeero me genera este error
/usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require': cannot load such file -- colorize (LoadError)
from /usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from funca.rb:1:in `<main>'
Alguna idea???? saludos y muchas gracias!
pd; le saqué la primer línea del código y me genera entonces este error
funca.rb:56:in `calculate': undefined method `green' for "\n############## Rentas Ciudad de Buenos Aires ##############":String (NoMethodError)
from funca.rb:66:in `<main>'
No tienes permitido ver los links.
Registrarse o Entrar a mi cuenta
Esto está muy bueno! Peeero me genera este error
/usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require': cannot load such file -- colorize (LoadError)
from /usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from funca.rb:1:in `<main>'
Alguna idea???? saludos y muchas gracias!
pd; le saqué la primer línea del código y me genera entonces este error
funca.rb:56:in `calculate': undefined method `green' for "\n############## Rentas Ciudad de Buenos Aires ##############":String (NoMethodError)
from funca.rb:66:in `<main>'
Huep! Sorry por la respuesta, no ando muchos por estos pagos, el problema lo tienes porq te falta la gema colorize, prueba:
sudo gem install colorize
y cuando termine la instalación, vuelve a ejecutar el código. Saludos!
Excelente nota.
Muy didáctica, muy bien explicada.
Estimado, le solicito permiso para desarrollarla como ejemplo, con fuente, por supuesto, en mis clases de capacitación.
Pienso que puede servir especialmente para motivar a que las personas aprendan la importancia de entender Javascript, Ruby y las herramientas de desarrollo del navegador, de una forma amena y divertida.
No tienes permitido ver los links.
Registrarse o Entrar a mi cuenta
Excelente nota.
Muy didáctica, muy bien explicada.
Estimado, le solicito permiso para desarrollarla como ejemplo, con fuente, por supuesto, en mis clases de capacitación.
Pienso que puede servir especialmente para motivar a que las personas aprendan la importancia de entender Javascript, Ruby y las herramientas de desarrollo del navegador, de una forma amena y divertida.
Si karancho, no tengo problema, un gusto que compartas mis estudios, pensamiento distribuido y open source es lo que le falta al mundo.
PD: Eres karancho de Lugmen Mendoza? de ser así hemos compartido mesa en algun momento de la vida, saludos!
Un excelente aporte. sigue asi y muchos exitos...!
Excelente post!!! además bien explicado y detallado
Enviado desde mi GT-I9300 mediante Tapatalk
la unica palabra que puedo decir esto es "IMPRESIONANTE" y la duda que tengo es
para que usaste sus datos personales? tiene las piernas rotas?
Genial! mas allá del (conocimiento + ganas de compartir), el enfoque de fallo de vulnerabilidad que le das, cuando comúnmente esta todo plagado de "vamos a hachear y romper todo" (que es lo que busca la mayoría de la gente).
Slds!
sinceramente, muy buen aporte, aunque soy un novato todavía (y siempre lo seré ;D) me atrapo la forma de explicar que tienes la facilidad con la que me ayudo a entender lo que hiciste es increíble... muy buen aporte gracias por compartirlo :D ;D
No tienes permitido ver los links.
Registrarse o Entrar a mi cuenta
sinceramente, muy buen aporte, aunque soy un novato todavía (y siempre lo seré ;D) me atrapo la forma de explicar que tienes la facilidad con la que me ayudo a entender lo que hiciste es increíble... muy buen aporte gracias por compartirlo :D ;D
No te tires para abajo, todos empezamos siendo novatos!
grandioso es leer estos aporte por parte de usted , saludos
maneje con cuidado
Excelente nota,a mi me paso algo parecido pero buscando un poco había una persona que hizo lo mismo que vos y creo una web donde pones la patente y te da el código de 2 dígitos para acceder a los datos personales.
Saludos.
Entonces a romperle las piernas. ;-)
Tremendo aporte brother, seguro no sólo en el ambito de patentes existen este tipo de descuidos o desconocimiento por parte de los programadores encargados.
Muy bien explicado y completo.
Saludos!
como lo hiciste con la consola del navegador? no me resulta
Hay colega que buen aportarte se merece un pedazo de felicitación :D :D
Aunque esto es de hace algún tiempo, al leerlo no deja de sorprender el ingenio y conocimiento aplicados a un objetivo. Felicitaciones hdbreaker, me es muy ejemplificador y útil.
Saludos!
Gracias por compartir el conocimiento hermano, pero no entendi el tema de sacar el codigo verificador mediante la patente. Podrias ayudarme? Te mande privado. Saludos
Enviado desde mi SNE-LX3 mediante Tapatalk
Ya pude sacar el digito verificador, pero de igual manera no te lanza el nombre y apellido del propietario del auto, sino que te dice la consecionaria donde lo compro y todo. pero en ningun lado (ni contancia ni emprimiedo deuda) te dice el nombre del titular del auto. alguna nueva forma de hacerlo?
Muy buena temática y buenas respuestas por parte de la comunidad