AoC3#06: Patch Management Is Hard

I’m continuing on with the write ups for the Advent of Cyber 2021 capture the flag challenge, hosted by TryHackMe.

I’ve already covered the very simple first five days of the advent challenge.

We left off with some XSS (cross site scripting) on day 5, but we’re going straight in with some local file inclusion vulnerabilities here on day 6.

Day 6 Web Exploitation: Patch Management Is Hard

A quick scan of the landing page shows that the error message we’re seeing on the screen appears to come from a named file in the URL. A quick tweak of that value confirms it may be an LFI vulnerability (Local File Inclusion exploit)

I change the error.txt value to ‘../../../../../etc/passwd’, to see if we get any directory traversal.

root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh lp:x:7:7:lp:/var/spool/lpd:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh proxy:x:13:13:proxy:/bin:/bin/sh www-data:x:33:33:www-data:/var/www:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh list:x:38:38:Mailing List Manager:/var/list:/bin/sh irc:x:39:39:ircd:/var/run/ircd:/bin/sh gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh nobody:x:65534:65534:nobody:/nonexistent:/bin/sh libuuid:x:100:101::/var/lib/libuuid:/bin/sh mysql:x:101:102:MySQL Server,,,:/nonexistent:/bin/false 

So that works then!

We can use the entry point (the variable we changed to get LFI) as answer to the first question. The 2nd question can be grabbed by traversing to the path specified in the challenge.

This server has sensitive information. Note All actions to this server are logged in! THM{d29e0...6c4c06} 

For the next challenge, if we try and include the index.php page as part of the local file inclusion, we PHP trying to execute it. Not what we want at the moment.

This doesn’t help:


… but this filter reveals the source code:


We just save that to a file…

…and decode it with base64.

That shows the flag embedded in the source code. Excellent.

To get McSkidy’s password, which is hard coded in a PHP source file as well, we just need to modify the previous URL query. Use their credentials to login and recover the next flag under Recovery Password too.

Remote code exeuction

Now we’re asking to dial it up a bit, to get remote code execution on the server. We can leverage LFI and access to the server logs to achieve some PHP log poisoning.

We’re told the logs store the following fields upon requests:


So if we manipulate the user-agent part of our HTTP request, we can get some PHP into the log files.

Use curl -H “User-agent: …” to specify a user-agent payload.

We can then review the log files again…

McSkidy: (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0:/manage.php

McSkidy: (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0:/logs.php


McSkidy: (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0:/logs.php

… and the value is there.

Can we drop PHP in there? We create a simple harmless payload and then attempt to use this as part of our user-agent in the previous curl request.

curl -H "User-agent: <?php echo getcwd(); ?>"

Inspecting the logs again we see a gap where our guests user-agent should be. That’s fine.

We now need to traverse up and use our LFI to directly access and execute that page; i.e. index.php?err=./includes/logs/app_access.log

Gecko/20100101 Firefox/78.0:/login.php admin: (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0:/login.php Guest: McSkidy: (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0:/logs.php admin: (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0:/index.php admin: (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0:/index.php?err=error.txt admin: (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0:/index.php?err=./includes/logs/app_access.log 

We can see that our getcwd() (get current working directory) is evaluated and reports back the path; /var/www/html

In hindsight I should have read the question closer, as I could have simply used gethostname() instead of getcwd() as a proof of concept. Oh well.

We change our payload and get the hostname displayed in our LFI vulnerable log files.

FYI gethostname() as a payload didn’t work. Subsequent checks prove this machine is using a really old version of PHP 5.2, which didn’t yet have the command. The function phpinfo gave up the hostname just fine.

With that, we complete Day 6 of the Advent of Cyber CTF challenge. This one was pretty cool – a noticeable increase in difficult from Day 5.

Day 7 will be linked here when it’s written up; which it now is. Head over to Day 7 to read about MongoDB SQLi.

Leave a Reply

Your email address will not be published. Required fields are marked *