Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
renbou committed Nov 11, 2023
2 parents bf720c6 + 7dff6cf commit bcc61bd
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 14 deletions.
44 changes: 30 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
# ad-boilerplate

[![check-services](https://github.com/C4T-BuT-S4D/ad-boilerplate/actions/workflows/check-services.yml/badge.svg?branch=master&event=push)](https://github.com/C4T-BuT-S4D/ad-boilerplate/actions/workflows/check-services.yml)

Development workflow:
# BRICS+ CTF 2023 | Finals

The contest was held on November 11, 2023. Services and infrastructure by C4T BuT S4D. Organized by ITMO University and ACISO.

Repository contains source code of services, checkers and exploits.

## Results

![Top](scoreboard/top.png)

[Full scoreboard](scoreboard/full.png)

## Services

| Service | Language | Checker | Sploits | Authors |
|------------------------------------|---------------|-------------------------------|------------------------------|-------------------------------------------------------------------------------------|
| **[notify](services/notify/)** | Rust | [Checker](checkers/notify/) | [Sploits](sploits/notify/) | [@renbou](https://github.com/renbou) |
| **[restmenu](services/restmenu/)** | Kotlin & Java | [Checker](checkers/restmenu/) | [Sploits](sploits/restmenu/) | [@jnovikov](https://github.com/jnovikov) |
| **[leakless](services/leakless/)** | Go | [Checker](checkers/leakless/) | [Sploits](sploits/leakless/) | [@falamous](https://github.com/falamous) |
| **[notes](services/notes/)** | Python & C | [Checker](checkers/notes/) | [Sploits](sploits/notes/) | [@user39043346](https://github.com/user39043346) |

## Infrastructure

- DevOps: [@pomo_mondreganto](https://github.com/pomo-mondreganto)
- Checksystem: [ForcAD](https://github.com/pomo-mondreganto/ForcAD)

1) Create branch named `$SERVICE`.
2) Write your code in `services/$SERVICE`, `checkers/$SERVICE`, `sploits/$SERVICE` and `internal/$SERVICE` (if needed).
3) Validate your service with `SERVICE=$SERVICE ./check.py validate`.
4) Up your service with `SERVICE=$SERVICE ./check.py up`.
5) Check your service with `SERVICE=$SERVICE RUNS=200 ./check.py check`.
6) Down your service with `SERVICE=$SERVICE ./check.py down`.
7) Push your code and create pull request to master branch.
## Writeups

Don't forget to:
1) Add your checker requirements to `checkers/requirements.txt`.
2) Use `dedcleaner` container to delete old files if needed. Example can be found in `services/example/docker-compose.yml`.
3) Add info about your checker to `Checker` class. Example can be found in `checkers/example/checker.py`, line 11.
- [notify](/sploits/notify/)
- [restmenu](/sploits/restmenu/)
- [leakless](/sploits/leakless/)
- [notes](/sploits/notes/)
Binary file added scoreboard/full.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added scoreboard/top.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 49 additions & 0 deletions sploits/restmenu/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## Restmenu

### SSRF via Markdown render

The `restmenu` service allows you to create a menu, the data you entered will be used to generate a markdown file.
You can also render the menu as PDF file, to do so the service will use the generated markdown, convert it to HTML and
then to PDF.

So, overall algorithm is:

1. User enters data using the API (written in Kotlin).
2. The API generates a markdown file on create and update.
3. If the user wants to render the menu as PDF, the API will call the "renderer" service (written in Java) that will
perform:
1. Read the menu by ID.
2. Convert markdown to HTML using [commonmark-java](https://github.com/commonmark/commonmark-java).
3. Convert HTML to PDF using the [OpenHTMLtoPDF library](https://github.com/danfickle/openhtmltopdf).

The suspicious thing is that the renderer service is not checking any permissions and suppose to be internal only, so if
we would be able to call the `/api/render/<attack_data_id>` endpoint we could get the PDF file we don't have access to.

From the API (and checkers traffic) we can clearly see that the renderer can render the images.

The second suspicious thing is that the image input is the only input that has poor validation. Instead of checking
the user-input as a regex, it's checked by using Java's `URI` class.

So, if we bypass the `URI` check, we would be able to inject the markdown we want and trigger the SSRF.

Well, we won't really benefit from the blind SSRF, so we need to find a way to leak the response.
Thankfully, the "OpenHTMLtoPDF" have some weird logic
to [embed the .pdf files in the HTML "<a>" attributes](https://github.com/danfickle/openhtmltopdf/blob/780ba564839f1ad5abfa5df12e4aebb9dd6782d2/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxReplacedElementFactory.java#L82)
.

Using this, the solution itself can be described as:

1. Create a markdown that will result with HTML that will have "<a>" tag with the href set
to "http://localhost:8081/api/render/<attack_data_id>#.pdf".
2. To make this markdown, we need to bypass the `URI` check. That can be done by putting the payload in the query
string.

Final payload: `test/?a=)![t](http://localhost:8081/api/render/{hint}#.pdf)`

Specifying this in our menu and rendering it after will result with the victim PDF embedded into our PDF, so we can read
the
flag by extracting it from the PDF.

[Full exploit](./injection_ssrf.py)


0 comments on commit bcc61bd

Please sign in to comment.