Post

Interceptor

Use Burp or interception knowledge to modify the traffic and pwn the machine.

Interceptor

image-1285

Scenario

MediaHub appears to be a normal internal portal used by journalists to manage content. Everything seems protected behind a login and verification system, but the real story lies in how the application communicates with its backend APIs.

Your task is to assume the role of an attacker and closely observe traffic between the browser and the server. Using your proxy skills, intercept the requests, analyse how the application processes them, and experiment with modifying the data being sent.

If you understand the flow well enough, a small change in the request might be all it takes to bypass the intended controls. Fire up your proxy, intercept the traffic, and see if you can manipulate the requests to take control of the system.

Questions

image-1286


Reconnaissance

rustscan -a 10.48.166.24 -- -sV -sC

image-1287

image-1288

Ports 22 (SSH), 53 (DNS), 80 (HTTP) are open.

So, let’s start with website enumeration first.

image-1289

image-1291

Then I will use gobuster to find hidden directory.

image-1299image-1292


Find the Password

We found an interesting dir, login.php.bak, which seems to be a backup file, so let’s download this file first.

login.php.bak:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php
include "header.php";

/*
|--------------------------------------------------------------------------
| Developer Note (temporary)
|--------------------------------------------------------------------------
| Admin test account for staging environment
| Email: admin@mediahub.thm
|
| Password policy reminder:
| Admin password follows company format:
| MediaHub + any year
|
| TODO: remove before production deployment
*/
?>

<div class="row justify-content-center">
  <div class="col-md-5">
    <div class="card p-4">

      <h4 class="mb-3">Login</h4>

      <form id="loginForm">
        <input class="form-control mb-3" name="email" placeholder="Email" required>

        <input class="form-control mb-3" name="password" type="password" placeholder="Password" required>

        <button id="btnLogin" class="btn btn-primary w-100" type="submit">
          Login
        </button>
      </form>

      <div id="msg" class="mt-3"></div>

    </div>
  </div>
</div>

<script>
const form = document.getElementById("loginForm");
const msg  = document.getElementById("msg");
const btn  = document.getElementById("btnLogin");

form.addEventListener("submit", async (e) => {
  e.preventDefault();

  msg.innerHTML = `<div class="text-muted">Signing in...</div>`;
  btn.disabled = true;

  const payload = new FormData(form);

  try {
    const res = await fetch("api_login.php", {
      method: "POST",
      body: payload
    });

    const data = await res.json();

    if (!data.ok) {
      msg.innerHTML = `<div class="alert alert-danger py-2 mb-0">${data.error}</div>`;
      btn.disabled = false;
      return;
    }

    msg.innerHTML = `<div class="alert alert-success py-2 mb-0">${data.message}</div>`;
    setTimeout(() => window.location = data.redirect, 400);

  } catch (err) {
    msg.innerHTML = `<div class="alert alert-danger py-2 mb-0">Something went wrong.</div>`;
    btn.disabled = false;
  }
});
</script>

<?php include "footer.php"; ?>  

image-1297

It shows important information like the admin email and password format MediaHub + YEAR, so we can create a custom word list to brute-force on the login page.

1
2
3
for y in {1990..2035}; do
    echo "MediaHub$y"
done > mediahub-years.txt

I use a simple for loop to create wordlists containing custom passwords following the format.

image-1300

I use a simple script to use the curl command and check which password is correct

image-1301

Password is MediaHub2026

image-1295

image-1302


OTP Bypass

After login, it asks for an OTP sent to the email. I inspect this page’s script, and we can see that if we succeed, it will redirect to dashboard.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<script>
const form = document.getElementById("otpForm");
const msg  = document.getElementById("msg");
const btn  = document.getElementById("btnVerify");

form.addEventListener("submit", async (e) => {
  e.preventDefault();

  msg.innerHTML = `<div class="text-muted">Verifying...</div>`;
  btn.disabled = true;

  const payload = new FormData(form);

  try {
    const res = await fetch("verify_otp.php", {
      method: "POST",
      body: payload
    });

    const data = await res.json();

    // UI: show only message/error on DOM
    if (!data.ok) {
      msg.innerHTML = `<div class="alert alert-danger py-2 mb-0">${data.error}</div>`;
      btn.disabled = false;
      return;
    }

    msg.innerHTML = `<div class="alert alert-success py-2 mb-0">${data.message}</div>`;

    setTimeout(() => {
      window.location = "dashboard.php";
    }, 700);

  } catch (err) {
    msg.innerHTML = `<div class="alert alert-danger py-2 mb-0">Something went wrong.</div>`;
    btn.disabled = false;
  }
});
</script>

So, I try putting in some numbers and use burpsuite to inspect the response

image-1303

“is_verified:false” is interesting. I will use this to bypass otp verification. So, I use burp intercept and put is_verified and set its value to true and send the request.

image-1304

Now, it says redirecting… so I change the path to /dashboard.php, and now we are in.

image-1305

image-1306


Import Feed

Inside, we can use upload and Import feed. This might be vulnerable.

But it seems like picture upload is filtered to allow only pictures, so let’s focus on the import feed features

image-1307

we can see from the error that they use the curl command.

Now, I try to do command injection by fetching back to their localhost ip.

image-1310

“Private network access blocked”, so let’s bypass by using 127.1 instead

image-1311

Now it works!

image-1312

but it doesn’t work. From the error message “Could not resolve host: id”, this might mean we have to put a file path instead of a command.

image-1313

I try http://127.1 ; file:///etc/passwd, and now it works. This means we can fetch files directly via this injection

since the question asked for /var/www/user.txt

Use http://127.1 ; file:///var/www/user.txt

image-1316

and we got the flag!

DONE!!!


This post is licensed under CC BY 4.0 by the author.