Monday, September 9, 2019

CyBot on Microsoft Teams

By Tony Lee

Does your organization have a threat intel chatbot to do your bidding? If not, you should give CyBot (https://github.com/cylance/CyBot) a try. It is designed not only for threat intel groups, but also incident responders, and SOCs.  CyBot was born in HipChat, then migrated to Slack after the merger, and now finally adapted to work for Microsoft Teams. Don't get me wrong, this article is not an endorsement for using Microsoft Teams, but you don't always get to pick your chat platform--especially when Microsoft has the ability to bundle Teams with o365 subscriptions. The upside is that the Teams platform does seem to be improving over time as its market share grows (largely a result of the previously mentioned bundling). In fact, in July of 2019, Microsoft announced that they surpassed Slack in number of daily users. Due to these factors, with the herculean help of Igor Vasilcovsky, we looked into getting CyBot’s underlying Errbot platform onto Microsoft Teams. Warning:  Due to Microsoft’s rapid (and sometimes frustrating) development efforts, this integration could break or change at a moment’s notice—caveat emptor.  😐

https://www.theverge.com/2019/7/11/20689143/microsoft-teams-active-daily-users-stats-slack-competition






Figure 1:  CyBot Working in Microsoft Teams

Article Outline


  • Our Setup Assumptions
  • Install and initialize Errbot
  • Install and Configure nginx Reverse Proxy
  • Generate and Install a Valid SSL Certificate
  • Create the Microsoft Bot Channel
  • Download and Configure the Botframework Backend
  • Modifying the botframework plugin
  • Preliminary Test
  • Add your Bot to Microsoft Teams
  • Package the Bot
  • Use Microsoft Teams App Studio

Our Setup Assumptions


  • Hosting Errbot in AWS on Ubuntu 18.04
  • Using Microsoft’s “Bot Channels Registration” to link Errbot to Teams
  • Even though documentation states that Bot Channels Registration is free, we could not get it to work with a free subscription.  It appears to cost 50 cents per 1,000 messages.
  • Domain name purchased VIA AWS Route 53 (reasonably priced)
  • nginx reverse proxy
  • Free (but legitimate) SSL certificate provisioned via letsencrypt.org Certbot
  • Errbot installation path used in our examples:  /home/ubuntu/errbot-root/
  • If using the Bot Framework Emulator for testing/troubleshooting, you may need to sign up for a free ngrok account to tunnel traffic remotely
Pro-tip:  Use the screen command to run errbot in since it continues to run even when you are disconnected from the terminal.


Known Limitations
Solved


Not solved

  • Messages must be direct messages (not group chat)
  • Copy and paste from Teams adds extra CR LF characters which break the errbot recognition
  • Admin restrictions and private plugins need to be handled
  • Teams mobile app ignores \r\n formatting (web and desktop client do not)



Traffic Flow
The below diagram shows the resulting traffic flow from Microsoft to our errbot server.


Figure 2:  Flow of traffic

Install and initialize Errbot

After setting up the Ubuntu 18.04 EC2 instnce and purchasing our domain, we installed Errbot using the following:

sudo apt update
sudo apt install python3-dev libssl-dev libffi-dev
sudo apt install python3-pip
sudo pip3 install errbot
mkdir ~/errbot-root
cd ~/errbot-root
errbot --init

After the initialization, we need to test errbot and load the errbot Webserver plugin:

errbot

>>> !plugin config Webserver
>>> !webstatus
>>> !webhook test /echo

Note: If the above webhook test did not work (result in a 200), try the following:

>>> !plugin config Webserver {'HOST': '0.0.0.0', 'PORT': 3141, 'SSL': {'certificate': '', 'enabled': False, 'host': '0.0.0.0', 'key': '', 'port': 3142}}
>>> !shutdown --confirm

Note:  Before continuing with the next section, have your domain name purchased and forwarding traffic to your server. We used AWS Route 53 for our domain name purchase since we were also hosting the instance in AWS, but feel free to use any service that allows you to direct or transparently forward the domain to your host.  Note:  Godaddy’s domain forwarding did not work with our SSL certificate.

Install and Configure nginx Reverse Proxy

Interestingly enough, errbot cannot directly receive HTTPS communication from Microsoft Bot Channels for some reason so a reverse proxy is required.  For this task, we will use nginx due to its lightweight and flexible nature. To install and initialize, we used the following:

sudo apt install nginx
sudo nginx -s reload

Test for port 80 being open:

netstat -plant | grep :80

Note:  You may need to temporarily open TCP 80 and 443 on the AWS firewall to test nginx and register for the SSL certificate.

To ensure external access, use a browser to navigate to the server’s port 80 to see the default nginx page.

Determine the default nginx install location using the following command:

sudo nginx -t


ubuntu@ip-xxx-xx-xx-xx:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful


Now that we know the default location (for us it was /etc/nginx/nginx.conf), let’s create our test port and redirection to errbot:

sudo vim /etc/nginx/conf.d/cybot.conf


server {
  listen 3143;
  server_name www.yourdomain.com;

  location / {
      proxy_pass http://localhost:3141/;
  }
}



After creating this test port and opening the Amazon firewall for port 3143, restart nginx and use a web browser to navigate to http://www.yourdomain.com:3143 to test the unencrypted nginx forwarding on to the errbot Web Server listener.

sudo service nginx restart



Figure 3:  This is an expected message and means the redirection from nginx to the errbot webserver is working

Generate and Install a Valid SSL Certificate

WARNING:  Microsoft’s Bot Channels Registration, Azure portal Web chat, and Bot emulator do not work with self-signed certs—thus you need a legitimate SSL certificate. We will create a free, but legitimate letsencrypt.org certificate using certbot. Please remember to have your domain name purchased and ready to assign to this certificate, plus port 80 and 443 on your AWS firewall open to this host.

Prep for Certbot

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update

Install Certbot

sudo apt-get install certbot python-certbot-nginx

Use Certbot to generate and configure nginx
Note:  When asked for the CN, make sure you use the Fully Qualified Domain Name (FQDN) of your server.  Ex:  www.yourdomain.com

sudo certbot --nginx


Hopefully creating the certificate was successful and we can modify our config file to include it.

sudo vim /etc/nginx/conf.d/cybot.conf


server {
  #listen 3143;
  listen 3142 ssl;
  server_name www.yourdomain.com;

  ssl_certificate /etc/letsencrypt/live/<yoursite>/fullchain.pem; # managed by Certbot
  ssl_certificate_key /etc/letsencrypt/live/<yoursite>/privkey.pem; # managed by Certbot

  location / {
      proxy_pass http://localhost:3141/;
  }
}



The above config commented our port 3143 which we use as an unencrypted test port.  3142 is the SSL receiver for the Microsoft communications which then forwards the traffic on to localhost 3141. If for whatever reason, you need to test the functionality without the complexity of encryption (i.e. using Bot Framework Emulator), feel free to uncomment the test port 3143 and restart nginx.

Create the Microsoft Bot Channel

Warning:  Microsoft seems to indicate that this integration is free, but we could not get this integration working with the free trial.  After the free trial was over, we had to select a paid tier and it worked.  We found this to be annoying.


Source:  https://azure.microsoft.com/en-us/pricing/details/bot-service/ 

Create the Microsoft Bot Channel

  1. Go to Azure Portal - https://portal.azure.com/
  2. Go to "Create a Resource" 
  3. Search the Marketplace > "Bot Channel" > Bot Channels Registration > Create
  4. Fill the form and wait for the resource to be created
  5. Note for Messaging endpoint:
    1. https://<yoursite>:3142/botframework



Figure 4:  Creating the Bot Channels Registration

Obtain appId and appPassword for errbot integration

When finished with Bot Channels creation, save off the application id (Dashboard -> Your Bot name -> Settings -> MSFT App ID)
ex:  7635snip-snip-snip-snip-snip4cf15a0f

Obtain and save the appPassword as well (Dashboard -> Your Bot name -> Settings -> Manage (next to MSFT App ID) -> New Client Secret
ex:  9@snipsnipsnipsnipsnipsnipCg6F


Figure 5:  Obtaining the appId and appPassword

Download and Configure the Botframework Backend

First of all…  A huge thanks goes out to Igor Vasilcovsky for creating and helping troubleshoot this botframework backend. This thanks cannot be understated. Now that we have the Bot Channels Registration appId and appPassword, on the AWS Ubuntu terminal run the following commands:

cd ~/errbot-root
git clone https://github.com/vasilcovsky/errbot-backend-botframework.git
cp config.py config.orig
vim config.py



import logging

#BACKEND = 'Text'
BACKEND = 'BotFramework'  # Errbot will start in text mode (console only mode) and will answer commands from there.

BOT_DATA_DIR = r'/path/to/errbot-root/data'
BOT_EXTRA_PLUGIN_DIR = r'/path/to/errbot-root/plugins'
BOT_EXTRA_BACKEND_DIR = r'/path/to/errbot-root/errbot-backend-botframework/'

BOT_LOG_FILE = r'/path/to/errbot-root/errbot.log'
BOT_LOG_LEVEL = logging.DEBUG

BOT_IDENTITY = {
    'appId': '<ENTER IT HERE>',
    'appPassword': '<ENTER IT HERE>'
    }

BOT_ADMINS = ('@CHANGE_ME', )  # !! Don't leave that to "@CHANGE_ME" if you connect your errbot to a chat system !!




Note:  Our /path/to/ was /home/ubuntu/

Example values for appId and appPassword (from above):

BOT_IDENTITY = {
    'appId': ‘7635snip-snip-snip-snip-snip4cf15a0f’,
    'appPassword': ‘9@snipsnipsnipsnipsnipsnipCg6F’
    }

Modify the botframework plugin

To make the output prettier in teams we modified Igor’s botframework plugin.  This modification detects the number of lines of output and then adds either adds an in-line or multi-line code block around the output.  Lines 156 – 159 were added to the following file

vim ~/errbot-root/errbot-backend-botframework/botframework.py


154     def _build_reply(self, msg):
155         conversation = msg.extras['conversation']
156         if len(msg.body.splitlines())==1:
157             msg.body="`" + msg.body + "`"
158         else:
159             msg.body="```" + msg.body
160
161         payload = {



Now that the config file is complete and pointing at the modified Botframework backend, start/restart errbot

errbot

Preliminary Test

There are a couple of ways to test the receiving end (nginx, errbot, etc)

1) Via a Web Browser
With the errbot window open, you can test the nginx redirection using a simple web browser, navigating to your messaging endpoint:

https://<yoursite>:3142/botframework

If you see traffic arrive in errbot, it means your domain, SSL cert, nginx redirection, and errbot Web Server plugin are all working.  If this does not work, you may need to check firewall settings and possibly configurations for everything.


Figure 6:  Browser was able to corectly route from SSL nginx to errbot Webserver plugin

2) Test via the Web Chat
Now that you tested the basic connectivity, let’s test the Microsoft side of the house by using the Web Chat feature within the Azure portal.
1. Go to Azure Portal - https://portal.azure.com/
2. Navigate to:  Dashboard -> Your Bot name -> Test in Web Chat

If everything seems ok, try to run !help.  If all is well, you should receive the help menu as shown in the screenshot below.


Figure 7: Errbot help menu exercised through the Azure Portal Web Chat

If you did not see the help menu, there is something wrong with the Microsoft piece of the integration and you may need to use the Botnet Framework Emulator to troubleshoot (see that section for more details).

If you see the help menu, you need to now add the MSTeams channel to your bot and then communicate with the bot through Teams.

Add your Bot to Microsoft Teams

Now that the webchat worked, the next step is to add the MSTeams channel to your bot.¬ Once added you should be able to communicate with the Bot over the via Teams. The three way we will outline are the following:

1) Use the appId for direct communication  <-- Worked on our Teams instance, but not others
2) Publish publicly to Teams <-- We are avoiding this..
3) Package the bot to import into a third part Teams instance <-- Worked for other Teams


Figure 8:  Adding MSTeams channel to the bot

Chat with bot via the appId
One of the trickier steps in the process is figuring out how to actually communicate with the Bot. The easiest way is to use the appId that we noted earlier.  Example:

7635snip-snip-snip-snip-snip4cf15a0f


Figure 9:  Finding the bot in teams via the appId.

This seems to work for direct messaging the bot, but it does not seem possible to add the bot to a team via the appId. To accomplish this, we have to package the bot so we could upload it to our organization and use privately. The alternative is to publish the bot to Teams at large and allow anyone to use it, but the risk of misuse greatly increases.

Package the Bot

To upload the bot to Teams, we must package it up first. A Teams apps package is relatively simple and consists of a JSON manifest file and two icons.


Figure 10:  Teams apps package

Icon guidance
The icons must conform to a certain size and filename.  For the latest guidance please consult the following link:

https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/apps/apps-package

Manifest guidance
Even though the Azure portal seems to contain a manifest file, strangely enough it is not the same format as what is required for app upload into Teams—Go Microsoft! The easiest way to generate the required manifest is to use App Studio within Teams.  Please see the link below on how to activate it within your Teams instance.

https://docs.microsoft.com/en-us/microsoftteams/platform/get-started/get-started-app-studio

Use Microsoft Teams App Studio

To create the bot, open App Studio within Microsoft Teams
1) Click Manifest editor
2) Create a new app
3) Details section:  Fill in details shown below.  (The app ID is the same app ID from previous steps)


Figure 11:  Creating the Teams Package

4) Capabilities Section:  Bots subsection – Fill in the details below:


Figure 12:  Capabilities -> Bot Section

Install or Download the app to publish later
Once the at the end of the App Studio creation process (Finish -> Test and distribute), you can immediate test the app by using the Install button or you can download the app. Provided that you have permissions to sideload the app, you can try the install button.


Figure 13:  Options for Install or Download

If installing on a different Teams instance, you may be able to sideload the app with a manual upload using Apps -> Upload a custom app.  Then just point to the app zip file.


Figure 14:  Sideload the app if this option is enabled

If that is disabled, you may need to have your Azure admins install the app for you. Once installed, you will be able to add your bot to chats just like a person.

https://docs.microsoft.com/en-us/microsoftteams/tenant-apps-catalog-teams

Install CyBot Plugins

Now that the heavy lifting is done, it is time to install the CyBot plugins.

cd /tmp
git clone https://github.com/cylance/CyBot.git
cp -a CyBot/plugins/* ~/errbot-root/plugins/

Restart errbot and use !commands to start using the CyBot plugins.

Figure 15:  Chatting with CyBot in Teams


Added Security

Now that everything is working, let's add some additional security by only allowing traffic on port 3142 from the following ranges:
  • 13.104.0.0/14
  • 13.96.0.0/13
  • 13.64.0.0/11

Troubleshooting

If you run into any issues and need help, please see our next article on Troubleshooting CyBot on Microsoft Teams:

http://securitysynapse.blogspot.com/2019/09/troubleshooting-cybot-on-microsoft-teams.html

Conclusion

If you are still with us… you are a hero.  Microsoft did not design the “bring your own bot” to be simple by any means, however it seems to work for now. We spent the past two weeks cleaning up plugin output to be more Teams friendly while still maintaining compatibility with Slack and other platforms. We will continue to improve the integration and plugin functionality over time, but feel free to let us know if you have any issues.

Special Thanks

Special thanks goes to the errbot team for making this flexible cross-chat platform available.  Special thanks also goes to Igor Vasilcovsky for his work on the botframework backend.

Thursday, July 25, 2019

Wyze Cameras - Keeping Honest Vendors Honest - Part II – Test Results

By Tony Lee

Quick Recap from part I in the series:
It can be difficult for a security nerd to inherently trust cloud vendors and products that do not keep all data on-premises—especially when it comes to home automation IoT devices such as cameras since they can record sensitive data. One such product with excellent reviews, ample capability, and a very reasonable price is the ever-popular Wyze Camera. So, I snatched up a Wyze Cam v2 triple pack that went on-sale, but became concerned after reading reviews and even a Reddit thread found here (https://www.reddit.com/r/wyzecam/comments/beq0sk/do_you_trust_wyze/) and here (https://www.reddit.com/r/wyzecam/comments/7cykgf/wyzecam_sending_data_to_servers_other_than_aws/) mentioning the data is possibly going to China. Note: while no country is perfect, not all countries condone state-sponsored corporate espionage and mass general population data collection.  Just sayin...

One positive note at the time was that it seemed that the manufacturer was chiming in on the Reddit threads explaining that they attempted a fix and that they needed someone to test again. So, in order to test the validity of the reviews and to help answer WyzeTao in the second article:  “We are asking help from some Reddit forum helpers to help check.”, we needed to set up our own environment.  This blog series outlines both the setup involved and then the results.
If you are setting this up yourself, you should refer to Part I - Setup here:   http://www.securitysynapse.com/2019/07/wyze-cameras-keeping-honest-vendors-honest-I.html

Spoiler:
Our camera arrived with firmware version 4.9.2.52 (Release date: October 22, 2018) and we upgraded to the latest version at the time of: 4.9.3.64 (Release date: December 17, 2018). We found that the other reviewers were correct in that the data was going to China (and other countries) due to a content distributor that Wyze uses—however, after working with the very responsive manufacturer, Wyze corrected the issue for everyone. So a huge thanks goes to Tao And Martin at Wyze for their great handling of this responsible disclosure.  Now, please update your mobile app and camera to the latest version (or newer) found below :-)

Corrected Versions:
Mobile app:  V2.4.24 (release date:  July 9th, 2019)
Wyze Cam v2 Firmware V4.9.4.108 (Release date: July 8, 2019)  <-- Update your camera firmware!



Traffic Analysis

After completing the setup in Part I of this series and opening wireshark, it is now time to analyze the traffic. We mentioned previously that we set a display filter (ex:  ip.addr==192.168.8.214) to narrow in on only traffic to and from the Wyze Camera.

Figure 5:  Wyze Cam v2 traffic


As you can see, the Wyze Camera is making DNS requests for:

  • gm.iotcplatform.com
  • cm.iotcplatform.com


These FQDNs resolved to the following IP addresses:
gm.iotcplatform.com

  • 52.79.197.188
  • 50.7.98.242
  • 198.16.70.58


cm.iotcplatform.com

  • 120.24.59.150


Using MaxMind GeoIP2, these IPs are located in the following countries:


Figure 6:  GeoIP resolution


This leaves us with the following:
gm.iotcplatform.com

  • 52.79.197.188 - Incheon, South Korea - Amazon.com
  • 50.7.98.242 - Los Angeles, United States - FDCservers.net
  • 198.16.70.58 - Amsterdam, Netherlands - FDCservers.net 


cm.iotcplatform.com

  • 120.24.59.150 - China - Hangzhou Alibaba Advertising Co.,Ltd.


Traffic Sent

If you were wondering if actual camera traffic was sent through China (via 120.24.59.150), it was indeed.


Figure 7:  Traffic sent to China


That said, the data by default does not use RTSP and could not easily be interpreted. Per Wyze, “The contents are encrypted via AES 128-bit encryption to protect the security of the live stream and playback data. During the connection process, every device in the process has its own secret key and certification, so that we can validate their identity during handshake. Even if a hacker intercepts the data package, the data cannot be decrypted.”

Source:  https://support.wyzecam.com/hc/en-us/articles/360009314072-Security-Privacy- 


Working with Wyze

After reporting the issue to Wyze tech support, they were extremely professional and concerned that the previous patch did not work. They worked quickly to provide a solution and test firmware (test version 4.9.4.44) that appeared to fix the issue.

Instead of the previous firmware querying "gm.iotcplatform.com" and "cm.iotcplatform.com", the new firmware queries "us-master.iotcplatform.com".  Just to be thorough, we let it run a bit and monitored for other traffic and found the following:

api.wyzecam.com

  • 34.208.107.136
  • 35.161.164.220
  • 35.167.190.246


wyze-iot.s3-us-west-2.amazonaws.com

  • 52.218.160.49


a24rq1e5m4mtei-ats.iot.us-west-2.amazonaws.com

  • 35.160.15.131


us-master.iotcplatform.com

  • 50.19.254.134
  • 50.7.98.242

Figure 8:  New GeoIP results


Conclusion

The initial contact took a little while, however over a one month period of working with the vendor, they were able to correct the issue. The level of detail and follow-through was greatly appreciated. Wyze engineers took our concerns seriously and delivered an acceptable solution. Based on our interactions, they appear to be an honest and transparent company that is focused on doing right by their customers. That is just one more reason in my book for us to purchase more Wyze cameras.


Disclaimer:  We do not work for Wyze (or any of the vendors mentioned) and do not benefit from this article in anyway. All cameras were purchased the same as anyone else.  We do like their customer service, quality of the goods, and prices though.  :-)

Monday, July 22, 2019

Wyze Cameras - Keeping Honest Vendors Honest - Part I - Setup

By Tony Lee

Background:
It can be difficult for a security nerd to inherently trust cloud vendors and products that do not keep all data on-premises—especially when it comes to home security/automation IoT devices such as cameras since they can record sensitive data. One such product with excellent reviews, ample capability, and a very reasonable price is the ever-popular Wyze Camera. So, I snatched up a Wyze Cam v2 triple pack that went on-sale, but became concerned after reading reviews and even Reddit threads found here (https://www.reddit.com/r/wyzecam/comments/beq0sk/do_you_trust_wyze/) and here (https://www.reddit.com/r/wyzecam/comments/7cykgf/wyzecam_sending_data_to_servers_other_than_aws/) mentioning the data is possibly going to China. Note: while no country is perfect, not all countries condone state-sponsored corporate espionage and mass general population data collection.  Just sayin...

One positive note at the time was that it seemed that the manufacturer was chiming in on the Reddit threads explaining that they attempted a fix and that they needed someone to test again. So, in order to test the validity of the reviews and to help answer WyzeTao in the second article:  “We are asking help from some Reddit forum helpers to help check.”, we needed to set up our own environment.  This blog series outlines both the setup involved and then the results.

Spoiler:
Since this is a two part series and we want readers to benefit from the latest security enhancements, we are providing a spoiler in the first article. Our camera arrived with firmware version 4.9.2.52 (Release date: October 22, 2018) and we upgraded to the latest version at the time of: 4.9.3.64 (Release date: December 17, 2018). We found that the other reviewers were correct in that the data was going to China (and other countries) due to a content delivery network that Wyze uses—however, after working with the very responsive manufacturer to test and retest, Wyze corrected the issue for everyone. So a huge thanks goes to Tao And Martin at Wyze for listening to customer concerns and their great handling of responsible disclosures. Now, please update your mobile app and camera to the latest versions (or newer) found below :-)

Corrected Versions:
Mobile app:  V2.4.24 (release date:  July 9th, 2019)
Wyze Cam v2 Firmware V4.9.4.108 (Release date: July 8, 2019)  <-- Update your camera firmware too!

Figure 1:  The ever-popular (and pretty awesome) Wyze Cam 1080p HD Indoor Wireless Smart Home Camera

Test Environment

The hardware and software in our environment is a mixture of what we had on hand and what was required to compensate for lack of existing features.  Also keep in mind that there are quite a few ways to test these devices, however we are presenting just one of the solutions here.

Hardware:

  • Wyze Cam v2
  • eero Pro WiFi System (Set of 3 eero Pros) – 2nd Generation
  • GL-iNet AR750s
  • Standard laptop
  • USB Ethernet adapter


Software:

  • Windows 10 base OS
  • Kali Linux OS running in VMWare Workstation with USB ethernet adapter connected as pass through



Quick Note on Limitations of Mesh Routers (Including the Eero Pro WiFi System)

One potentially tricky scenario in monitoring wireless traffic on a mesh network is determining the AP to which the device connects and keeping it on that AP. To avoid that issue, ideally it should be simple to monitor the last hop AP that connects to the source of Internet (cable modem in our case), but this is not always a provided feature. It certainly isn’t a feature in the Eero Pro. Don’t get us wrong, the Eero hardware and reliability makes it one of the best mesh setups around, but the lack of advanced features is depressing—especially for the price tag (~$500) (https://www.amazon.com/eero-Home-WiFi-System-Beacon/dp/B071DWXLYL/). Maybe things will change after the semi-recent Amazon acquisition (https://www.theverge.com/2019/2/11/18220960/amazon-eero-acquisition-announced).  Fingers crossed!

Figure 2:  Typical Mesh network diagram (courtesy of Eero)


Work Around to Sniff Wireless Traffic

Since the Eero woefully lacks a way to route the traffic to a SPAN port, we purchased a GL.iNet GL-AR750S-Ext Gigabit Travel AC Router (https://www.amazon.com/GL-iNet-GL-AR750S-Ext-pre-Installed-Cloudflare-Included/dp/B07GBXMBQF) to do so.  The impressive stats on this compact device are as follows:


  • Dual band AC750 Wi-Fi: 433Mbps(5G) +300Mbps(2.4G)
  • QCA9563,@775MHz SoC
  • 128MB RAM, 16MB NOR Flash and 128 MB NAND Flash
  • Up to 128GB MicroSD slot
  • USB 2.0 port
  • Three ethernet ports (1 WAN, 2 LANs)
  • Powered by Micro USB 5V/2A power supply
  • And best of all:  OpenWrt pre-installed


Configuration and Setup

Now that we know the hardware, let’s jump into it.

Wiring:
 1) Cable Modem --> Wireless router --> Wireless Mesh receiver --> Hardwire to WAN port of AR750s
 2) AR750s Switch port --> USB ethernet adapter (connected to Kali VM)

Figure 3:  Wiring and configuration

First configuration of the router:

  • Power up the router
  • Connect wirelessly using the supplied wireless SSID and default password: goodlife
  • Upon connecting to the web UI (ex: http://192.168.8.1) you will be required to set a password for the router admin


Figure 4:  Web UI that shows the Wyze Cam v2 target and the Kali host to send the SPAN data


Setting up a SPAN port:
 Putty or SSH to router (ex: 192.168.8.1) with proper credentials (ex:  root:<password set above>)
 - Run the following to set up a SPAN port:

Syntax to setup a SPAN port:
iptables -t mangle -A PREROUTING -j TEE --gateway <IP of Kali VM>
iptables -t mangle -A POSTROUTING -j TEE --gateway <IP of Kali VM>

Example (where our Kali VM IP is 192.168.8.217):
iptables -t mangle -A PREROUTING -j TEE --gateway 192.168.8.217
iptables -t mangle -A POSTROUTING -j TEE --gateway 192.168.8.217

NOTE:  If you get the following error:
iptables v1.6.2: unknown option "--gateway"

 - Run the following and then the iptables commands again
opkg update
opkg install iptables-mod-tee kmod-ipt-tee


Figure 5:  SSH into the AR750S and setting up the SPAN port to go to the Kali Linux host (192.168.8.217)



Sniff Traffic:

  • Open Wireshark and sniff on the same interface specified above and you should now see all traffic to and from the AR750S.
  • Pro-tip:  Use a filter in Wireshark to limit traffic to just the device you want to monitor (in our case it is the Wyze Camera)
    • Ex:  ip.addr==<IP ADDRESS>


Conclusion

Now that we covered our hardware, software, setup and how to create a SPAN port of the AR750S wireless traffic… we are ready to cover our findings.  But, we will save that for Part II of the series found here:  http://securitysynapse.blogspot.com/2019/07/wyze-cameras-keeping-honest-vendors-honest-II.html

Tuesday, July 9, 2019

Creating Network Device CLI Visibility in Splunk

By Tony Lee

Creating visibility is not always a popular topic--especially when that visibility can be used to hold folks accountable. But if you have ever had a network outage due to an incorrect command or change in configuration, it may save your bacon to know how and where to correct it. The same is especially true if a network administrator account is ever compromised.

This article will show how to create a running log of searchable commands executed on Cisco ASA and Juniper devices. As a bonus, we will provide the dashboard code at the end of the article.

Figure 1:  Network Change Management dashboard

Raw Logs

Let's take a moment to see how these logs typically look.

Cisco

2017-10-20T08:33:09+00:00 admin : %ASA-5-111010: User 'TONYLEE', running 'CLI' from IP 10.10.10.10, executed 'write terminal'

Juniper

2017-10-20T04:18:30+00:00 JuniperRTR mgd[91265]: UI_CMDLINE_READ_LINE: User 'TONYLEE', command 'show igmp interface'




Logic to Find CLI Commands

We provided the exact Cisco and Juniper packets you are seeking, but these will not be the only packets. This is the logic we used to find it:

Cisco

index=cisco-asa message_id=111010 command!="changeto*"

Juniper

index=juniper UI_CMDLINE_READ_LINE

Source:  https://www.cisco.com/en/US/docs/security/asa/asa80/system/message/logmsgs.html


Fields to Parse

There are some fields that are critical in terms of making this data useful, such as:

  • Event time
  • Device changed
  • Source of change
  • User
  • Command executed

Fortunately, Splunk should have a Cisco and Juiniper TA to parse these events.  If not, respond here and we will help with the regex.


Searches

Now that we have the fields parsed, we need two searches to help us gain visibility into CLI commands:

Cisco:
index=cisco-asa message_id=111010 command!="changeto*" $wild$ | table _time, host, user, src, command | rename host AS CiscoHost, src as SourceIP


Juniper:
index=juniper UI_CMDLINE_READ_LINE $wild$ | table _time, host, user, command, _raw


Conclusion

Creating visibility is not always popular, but it sure is helpful when troubleshooting. We hope this article helped others save time. Let us know what you think by leaving a comment below. Happy Splunking!


Dashboard Code

The following dashboard assumes that the appropriate logs are being collected and sent to Splunk. Additionally, the dashboard code assumes an index of cisco-asa and an index of juniper. Feel free to adjust as necessary. Splunk dashboard code provided below:


<form>
  <label>Network Change Management</label>
  <fieldset submitButton="true" autoRun="true">
    <input type="time" token="time" searchWhenChanged="false">
      <label>Time Range</label>
      <default>
        <earliest>-24h@h</earliest>
        <latest>now</latest>
      </default>
    </input>
    <input type="text" token="wild" searchWhenChanged="false">
      <label>Wildcard Search</label>
      <default>*</default>
    </input>
  </fieldset>
  <row>
    <panel>
      <table>
        <title>Cisco ASA (message_id=111010 excluding changeto events)</title>
        <search>
          <query>index=cisco-asa message_id=111010 command!="changeto*" $wild$ | table _time, host, user, src, command | rename host AS CiscoHost, src as SourceIP</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
          <sampleRatio>1</sampleRatio>
        </search>
        <option name="drilldown">none</option>
        <option name="refresh.display">progressbar</option>
      </table>
    </panel>
  </row>
  <row>
    <panel>
      <table>
        <title>Juniper (UI_CMDLINE_READ_LINE)</title>
        <search>
          <query>index=juniper UI_CMDLINE_READ_LINE $wild$ | table _time, host, user, command, _raw</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
          <sampleRatio>1</sampleRatio>
        </search>
        <option name="drilldown">none</option>
        <option name="refresh.display">progressbar</option>
      </table>
    </panel>
  </row>
</form>



Monday, July 1, 2019

Quick and Flexible IOC Hunting in Splunk

By Tony Lee and Arjun Mathew

Imagine that you are battling a known threat actor.  You have gathered indicators of compromise (IOCs) from reversing malware as well as helpful contributions from the rest of the security community.  But how could those IOCs be tasked across your existing data quickly in order to track attacker movement in real-time?  Here is one possible solution:
  1. Use a lookup file
  2. Clever Splunk search
  3. Even more clever dashboard
This article will outline the process and even share an example dashboard (shown in the screenshot below).

Figure 1:  Known IOC Dashboard provided at the end of the article

Lookup File

We used the following process to create a lookup file and definition.  Create a file in excel and save it as a CSV called known_iocs.csv (similar to the file below).

Figure 2:  CSV that we initially populated with our IOCs

Then within Splunk, navigate to the following to create the lookup and the definition:

Settings > Lookups > Lookup table files > Add new

  • Destination app:  Select the app
  • Upload a lookup file:  known_iocs.csv
  • Destination filename:  known_iocs.csv


Settings > Lookups > Lookup definitions > Add new

  • Destination app:  Select the app
  • Name:  known_iocs.csv
  • Type:  File-based
  • Lookup file:  known_iocs.csv


Now, here is the problem.  How do you scale this solution to a group effort to update a lookup table with IOCs?  It does not work well to pass the CSV around and then constantly upload.  Enter another graceful solution from Luke Murphey -- The Lookup File Editor Splunk App (https://splunkbase.splunk.com/app/1724/).

Figure 3:  Lookup File Editor App from Luke Murphey

Once the Lookup File Editor Splunk App is installed, navigate to it, search for your known_ioc.csv file.  Open it and right click on the bottom line and "Insert a new row".  You can edit the lookup file right in Splunk.  Once it is saved, the correlation searches will automatically run with the new IOC data.


Figure 4:  Inserting a new line to our known_ioc.csv file

Clever Search

Now that we have a lookup table that has our IOCs in it and a convenient way to edit it, we just need a search that will apply the IOCs to our data.  The example below applies the IOCs to the cylance_protect index, but feel free to change the index name as needed.  Additionally, we show how to search just one column of the IOC data as well as multiple columns.


One type of IOC (Hash):

index=cylance_protect [|inputlookup known_iocs.csv | rename Hash as query | table query] | stats count


Two types of IOCs (Hash & FileName)

index=cylance_protect [|inputlookup known_iocs.csv | rename Hash as query | table query] OR [|inputlookup known_iocs.csv | rename FileName as query | table query] | stats count

Note the OR statement between the two inputlookups -- needed when querying multiple columns.


Figure 5:  What will be our top panels showing a count of the hits


Even More Clever Dashboard

Now that we have functional searches, we need a dashboard to monitor our different data feeds such as:
  • Proxy
  • Firewalls
  • DNS
  • Antivirus Hits
  • Email Protection
  • Windows Event Logs

You can see in the screenshot below that we use Single Value panels on the top row.  Each of these panels contains a dynamic drilldown to populate the panel below it with the contents of the Single Value panel when clicked.


Figure 6:  Dashboard displayed at the start of the article and in the Sample Dashboard section below

The drilldown for each Single Value panel sets a token which is essentially the search, but without the stats count (feel free to table the data as needed):

        <drilldown>
          <set token="alert">index=proxy $wild$ [|inputlookup known_iocs.csv | rename Domain as query | table query] | table _raw</set>
        </drilldown>



Then the bottom panel is just a search of the token set in the drilldown above.

        <search>
          <query>| search $alert$</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>

Conclusion

Using a clever combination of features that already exist within Splunk (for the most part), we were able to create a quick method to update an IOC list and apply it against existing data within Splunk. Simply monitor these dashboards and use it to track the attacker's activities in real-time.


Sample Dashboard

The sample dashboard below uses a number of indexes to search over different data feeds.  Just change these indexes to the ones you are interested in monitoring.


<form>
  <label>Known IOC Hits</label>
  <description>Threat Actor</description>
  <fieldset submitButton="true">
    <input type="time" searchWhenChanged="true" token="time">
      <label>Time Range</label>
      <default>
        <earliest>-24h@h</earliest>
        <latest>now</latest>
      </default>
    </input>
    <input type="text" searchWhenChanged="true" token="wild">
      <label>Wildcard Search</label>
      <default>*</default>
    </input>
  </fieldset>
  <row>
    <panel>
      <single>
        <title>Proxy</title>
        <search>
          <query>index=proxy $wild$ [|inputlookup known_iocs.csv | rename Domain as query | table query] | stats count</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="colorMode">none</option>
        <option name="drilldown">all</option>
        <option name="rangeColors">["0x65a637","0xd93f3c"]</option>
        <option name="rangeValues">[0]</option>
        <option name="useColors">1</option>
        <drilldown>
          <set token="alert">index=proxy $wild$ [|inputlookup known_iocs.csv | rename Domain as query | table query] | table _raw</set>
        </drilldown>
      </single>
    </panel>
    <panel>
      <single>
        <title>Firewalls</title>
        <search>
          <query>index=firewalls $wild$ [|inputlookup known_iocs.csv | rename IP as query | table query] | stats count</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="drilldown">all</option>
        <option name="rangeColors">["0x65a637","0xd93f3c"]</option>
        <option name="rangeValues">[0]</option>
        <option name="refresh.display">progressbar</option>
        <option name="useColors">1</option>
        <drilldown>
          <set token="alert">index=firewalls $wild$ [|inputlookup known_iocs.csv | rename IP as query | table query] | table _raw</set>
        </drilldown>
      </single>
    </panel>
    <panel>
      <single>
        <title>DNS</title>
        <search>
          <query>index=dns $wild$ [|inputlookup known_iocs.csv | rename Domain as query | table query] | stats count</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="drilldown">all</option>
        <option name="rangeColors">["0x65a637","0xd93f3c"]</option>
        <option name="rangeValues">[0]</option>
        <option name="useColors">1</option>
        <drilldown>
          <set token="alert">index=dns $wild$ [|inputlookup known_iocs.csv | rename Domain as query | table query] | table _raw</set>
        </drilldown>
      </single>
    </panel>
    <panel>
      <single>
        <title>Antivirus Hits</title>
        <search>
          <query>index=av $wild$ [|inputlookup known_iocs.csv | rename Hash as query | table query] | stats count</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="drilldown">all</option>
        <option name="rangeColors">["0x65a637","0xd93f3c"]</option>
        <option name="rangeValues">[0]</option>
        <option name="useColors">1</option>
        <drilldown>
          <set token="alert">index=av $wild$ [|inputlookup known_iocs.csv | rename Hash as query | table query] | table _raw</set>
        </drilldown>
      </single>
    </panel>
    <panel>
      <single>
        <title>Email Protection</title>
        <search>
          <query>index=mail_protection $wild$ [|inputlookup known_iocs.csv | rename Domain as query | table query] | stats count</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="drilldown">all</option>
        <option name="rangeColors">["0x65a637","0xd93f3c"]</option>
        <option name="rangeValues">[0]</option>
        <option name="useColors">1</option>
        <drilldown>
          <set token="alert">index=mail_protection $wild$ [|inputlookup known_iocs.csv | rename Domain as query | table query] | table _raw</set>
        </drilldown>
      </single>
    </panel>
  </row>
  <row>
    <panel>
      <title>Information Table (Click one of the numbers above to populate this table with Details)</title>
      <table>
        <search>
          <query>| search $alert$</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="drilldown">cell</option>
      </table>
    </panel>
  </row>
</form>