# Slowly Downward

> We've found what appears to be a schizophrenic alien's personal blog. Poke
> around and see if you can find anything interesting.  
>  
> http://slow.martiansonly.net  
>  
> Author: liabell

Solution:

No source file(s) given...let's check the challenge site.

![image](https://raw.githubusercontent.com/pspspsps-
ctf/writeups/main/2024/Space%20Heroes%202024/Web/Slowly%20Downward/1.png)

Interesting, it loads via iframe. Let's grab the link and use that instead.

![image](https://raw.githubusercontent.com/pspspsps-
ctf/writeups/main/2024/Space%20Heroes%202024/Web/Slowly%20Downward/2.png)

Alright, that's much better. Let's check the `SMALL THOUGHTS` first.

![image](https://raw.githubusercontent.com/pspspsps-
ctf/writeups/main/2024/Space%20Heroes%202024/Web/Slowly%20Downward/3.png)

Hmm, nothing important, even though there are hidden items in the list. It
will simply display an alert message.

Let's go back and check `A BIT WORRIED`.

![image](https://raw.githubusercontent.com/pspspsps-
ctf/writeups/main/2024/Space%20Heroes%202024/Web/Slowly%20Downward/4.png)

Interesting, there's a login form. `flag.txt` can be seen in the source as
well.

```javascript  
<script>  
let sessionToken;

// Function to fetch the session token from the server  
function fetchSessionToken() {  
fetch('/get-session-token')  
.then(response => {  
if (!response.ok) {  
throw new Error('Failed to fetch session token.');  
}  
return response.json();  
})  
.then(data => {  
sessionToken = data.token;  
// Call the function that initiates your application after fetching the
session token  
initApplication();  
})  
.catch(error => {  
console.error('Error fetching session token:', error);  
});  
}

// Function to initiate your application after fetching the session token  
function initApplication() {  
// Function to handle form submission for login  
document.getElementById('loginForm').addEventListener('submit',
function(event) {  
event.preventDefault();  
const username = this.querySelector('input[name="username"]').value.trim();  
const password = this.querySelector('input[name="password"]').value.trim();

// Fetch user credentials using the session token  
fetch('/text/credentials/user.txt', {  
headers: {  
'Authorization': `Bearer ${sessionToken}`  
}  
})  
.then(response => {  
if (!response.ok) {  
throw new Error('Failed to fetch user credentials.');  
}  
return response.text();  
})  
.then(userContent => {  
// Fetch password credentials using the session token  
fetch('/text/credentials/pass.txt', {  
headers: {  
'Authorization': `Bearer ${sessionToken}`  
}  
})  
.then(response => {  
if (!response.ok) {  
throw new Error('Failed to fetch password credentials.');  
}  
return response.text();  
})  
.then(passContent => {  
const storedUsername = userContent.trim();  
const storedPassword = passContent.trim();

if (username === storedUsername && password === storedPassword) {  
document.getElementById('uploadForm').style.display = 'block';  
document.getElementById('loginForm').style.display = 'none';  
} else {  
alert('Incorrect credentials. Please try again.');  
}  
})  
.catch(error => {  
alert(error.message);  
});  
})  
.catch(error => {  
alert(error.message);  
});  
});

// Function to handle file name input blur event  
document.getElementById('fileNameInput').addEventListener('blur', function() {  
const fileName = this.value.trim();  
if (fileName.includes('arbiter.txt; cat /secret/flag.txt') ||
fileName.includes('carts.txt; cat /secret/flag.txt') ||
fileName.includes('arbiter.txt; cat secret/flag.txt') ||
fileName.includes('carts.txt; cat secret/flag.txt') ||
fileName.includes('arbiter.txt;cat secret/flag.txt') ||
fileName.includes('carts.txt;cat secret/flag.txt')){  
// Fetch secret flag using the session token  
fetch('/text/secret/flag.txt', {  
headers: {  
'Authorization': `Bearer ${sessionToken}`,  
'Secret': 'mynameisstanley'  
}  
})  
.then(response => {  
if (!response.ok) {  
throw new Error('File not found.');  
}  
return response.text();  
})  
.then(fileContent => {  
document.getElementById('fileContent').innerText = fileContent;  
})  
.catch(error => {  
alert(error.message);  
});  
} else if (fileName.includes('carts.txt; cat arbiter.txt') ||
fileName.includes('carts.txt;cat arbiter.txt') ||
fileName.includes('arbiter.txt; cat arbiter.txt') ||
fileName.includes('arbiter.txt;cat arbiter.txt')) {  
fetch('/text/arbiter.txt', {  
headers: {  
'Authorization': `Bearer ${sessionToken}`  
}  
})  
.then(response => {  
if (!response.ok) {  
throw new Error('File not found.');  
}  
return response.text();  
})  
.then(fileContent => {  
document.getElementById('fileContent').innerText = fileContent;  
})  
.catch(error => {  
alert(error.message);  
});  
}  
else if (fileName.includes('arbiter.txt; cat carts.txt') ||
fileName.includes('arbiter.txt;cat carts.txt') ||
fileName.includes('carts.txt; cat carts.txt') ||
fileName.includes('carts.txt;cat carts.txt')) {  
fetch('/text/carts.txt', {  
headers: {  
'Authorization': `Bearer ${sessionToken}`  
}  
})  
.then(response => {  
if (!response.ok) {  
throw new Error('File not found.');  
}  
return response.text();  
})  
.then(fileContent => {  
document.getElementById('fileContent').innerText = fileContent;  
})  
.catch(error => {  
alert(error.message);  
});  
}  
else if (fileName.includes('flag.txt')) {  
alert('Sorry, you are not allowed to access that file.');  
this.value = '';  
} else {  
if (fileName !== '') {  
// Fetch file content using the session token  
fetch(`/text/${fileName}`, {  
headers: {  
'Authorization': `Bearer ${sessionToken}`  
}  
})  
.then(response => {  
if (!response.ok) {  
throw new Error('File not found.');  
}  
return response.text();  
})  
.then(fileContent => {  
document.getElementById('fileContent').innerText = fileContent;  
})  
.catch(error => {  
alert(error.message);  
});  
} else {  
alert('Please enter a file name.');  
}  
}  
});

// Function to handle file upload form submission  
document.getElementById('fileUploadForm').addEventListener('submit',
function(event) {  
event.preventDefault();  
const fileNameInput = document.getElementById('fileNameInput');  
const fileName = fileNameInput.value.trim();

if (fileName !== '' && !fileName.includes('flag.txt')) {  
// Fetch file content using the session token  
fetch(`/text/${fileName}`, {  
headers: {  
'Authorization': `Bearer ${sessionToken}`  
}  
})  
.then(response => {  
if (!response.ok) {  
throw new Error('File not found.');  
}  
return response.text();  
})  
.then(fileContent => {  
document.getElementById('fileContent').innerText = fileContent;  
})  
.catch(error => {  
alert(error.message);  
});  
} else {  
alert('Please enter a file name.');  
}  
});  
}

// Call the function to fetch the session token when the page loads  
window.addEventListener('load', fetchSessionToken);  
</script>  
```

So it calls `fetchSessionToken` then `initApplication` when the whole document
was loaded.

Looking at `initApplication`, we can see it fetches the correct username and
password then compares it with our input. So we can check the network requests
and retrieve the correct credentials.

![image](https://raw.githubusercontent.com/pspspsps-
ctf/writeups/main/2024/Space%20Heroes%202024/Web/Slowly%20Downward/5.png)

![image](https://raw.githubusercontent.com/pspspsps-
ctf/writeups/main/2024/Space%20Heroes%202024/Web/Slowly%20Downward/6.png)

So it's `4dm1n` and `p4ssw0rd1sb0dy5n4tch3r5`

Alright, let's use it.

![image](https://raw.githubusercontent.com/pspspsps-
ctf/writeups/main/2024/Space%20Heroes%202024/Web/Slowly%20Downward/7.png)

So looking at the source, we can call any of the following to get the flag.

```javascript  
if (fileName.includes('arbiter.txt; cat /secret/flag.txt') ||
fileName.includes('carts.txt; cat /secret/flag.txt') ||
fileName.includes('arbiter.txt; cat secret/flag.txt') ||
fileName.includes('carts.txt; cat secret/flag.txt') ||
fileName.includes('arbiter.txt;cat secret/flag.txt') ||
fileName.includes('carts.txt;cat secret/flag.txt')){  
```

![image](https://raw.githubusercontent.com/pspspsps-
ctf/writeups/main/2024/Space%20Heroes%202024/Web/Slowly%20Downward/8.png)

There's the flag!

Flag: `shctf{sh0w_m3_th3_w0r1d_a5_id_lov3_t0_s33_1t}`

@rnhrdtbndct noticed an uninteded solution lol:  
\- when using http://srv3.martiansonly.net:4444/text/secret/flag.txt , an
error appears  
\- but, if you add `/`,
http://srv3.martiansonly.net:4444/text/secret/flag.txt/ , then it works  
no session token and secret header needed haha

![image](https://raw.githubusercontent.com/pspspsps-
ctf/writeups/main/2024/Space%20Heroes%202024/Web/Slowly%20Downward/9.png)  

Original writeup (https://github.com/pspspsps-
ctf/writeups/tree/main/2024/Space%20Heroes%202024/Web/Slowly%20Downward).