Using Auditd to monitor changes to Linux

Install and enable auditd with

sudo dnf install auditd
sudo systemctl enable auditd
sudo systemctl start auditd

Add a file or directory to monitor with

auditctl -w /etc/passwd -k password

-w is watch path
-k is a filter key we can use later to search through logs

Now we can search with ausearch

ausearch -k password

Using Preconfigured Rules

There are already some preconfigured rules in /usr/share/audit/sample-rules/

We can copy those to /etc/auditd/rules.d/ and use them.

cd /usr/share/audit/sample-rules/
cp 10-base-config.rules 30-stig.rules 31-privileged.rules 99-finalize.rules /etc/audit/rules.d/
augenrules --load

Note on the 31-privileged.rules file. You’ll need to run the commands in the file which will create a new file. Then we can copy that to “/etc/auditd/rules.d/”

find /bin -type f -perm -04000 2>/dev/null | awk '{ printf "-a always,exit -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $1 }' > priv.rules
#find /sbin -type f -perm -04000 2>/dev/null | awk '{ printf "-a always,exit -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $1 }' >> priv.rules
#find /usr/bin -type f -perm -04000 2>/dev/null | awk '{ printf "-a always,exit -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $1 }' >> priv.rules
#find /usr/sbin -type f -perm -04000 2>/dev/null | awk '{ printf "-a always,exit -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $1 }' >> priv.rules
#filecap /bin 2>/dev/null | sed '1d' | awk '{ printf "-a always,exit -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $2 }' >> priv.rules
#filecap /sbin 2>/dev/null | sed '1d' | awk '{ printf "-a always,exit -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $2 }' >> priv.rules
#filecap /usr/bin 2>/dev/null | sed '1d' | awk '{ printf "-a always,exit -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $2 }' >> priv.rules
#filecap /usr/sbin 2>/dev/null | sed '1d' | awk '{ printf "-a always,exit -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $2 }' >> priv.rules

And Copy priv.rules to /etc/audit/rules.d/31-privileged.rules. Overwrite the file there if needed.

cp ./priv.rules /etc/audit/rules.d/31-privileged.rules

Load the rules.

augenrules --load

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/security_hardening/auditing-the-system_security-hardening

How to Create WireGuard Point-to-point Between Mikrotik Routers

We’ll create a tunnel between two Mikrotik RouterOS routers. Once we have the tunnel connected, we can then route traffic between them.

Note: You can add Preshared keys, but we don’t cover that in this post, just to keep things simple. Check out the following post if you want to add Preshared keys.

How to Create a Preshared Key for Wireguard

Here is how we will want our routers set up. The WireGuard PtP IP is the IP addresses used on both ends of the tunnel. The WAN IP is the IP of each Router. Local IP on Host B is setup to distribute DHCP.

Host A

WAN IP: 172.16.0.1
WireGuard PtP IP: 10.1.1.1/30

Host B

WAN IP: 10.0.0.2
WireGuard PtP IP: 10.1.1.2/30
Local IP: 192.168.0.1/24

We need Host A to be able to access Private IP’s (192.168.0.0/24) behind Host B.

We’ll pretend that the 172.16.0.1 address is a public IP, and Host B, is behind some sort of NAT network.

To create the Point-to-point, or PtP, we will create a WireGuard VPN tunnel, and then add routes from Host A to Host B.

For each Mikrotik we need to create a WireGuard interface, and then a peer. One of the peers needs a keep alive if we are behind a NAT.

Wireguard Setup Overview

Here is an overview screenshot of what our WireGuard settings will look like. Host A is on top, and Host B on the bottom. On the left are the WireGuard interfaces, and the right contains the Peers.

We copy the Public Key from the remote WireGuard interface, to the Public Key on the local Peer. I.e. The Host_B Peer contains Host_A’s Interface Public Key and vice verse

Host A

If you want to, you can use the WinBox GUI to setup and configure the router.

Create the WireGuard interface

 /interface/wireguard/add name=wireguard-Host_A disabled=no

Add IP address 10.1.1.1/30 to the newly created WireGuard Interface in /IP/Address

/ip/address/add address=10.1.1.1/30 interface=wireguard-Host_A disabled=no

Create WireGuard Peer, WireGuard -> Peers

  • Select the WireGuard interface,
  • In the Allowed Addresses, put 10.1.1.0/30 and 192.168.0.0/24*.
  • Finally, put in the Public Key from Host B.
    Note that we can’t do this until we create the WireGuard Interface on Host B, so you’ll need to come back for this step.
interface/wireguard/peers/add interface=wireguard-Host_A public-key=HOST_B_WG_PUBLIC_KEY allowed-address=10.1.1.0/30,192.168.0.0/24

Add route for 192.168.0.0/24 to point to 10.1.1.2

/ip/route/add dst-address=192.168.0.0/24 gateway=10.1.1.2

*The Allowed Address sets which addresses work on the other side of the tunnel. If we don’t specify 192.168.0.0/24, then we won’t be able to route to those addresses. If we don’t add 10.1.1.0/30, then our tunnel won’t work at all. Since we only need to route to the 192.168.0.0/24 network from the Host A side, we don’t need this IP range on Host B.

Host B

Create the WireGuard interface, WireGuard -> Add

 /interface/wireguard/add name=wireguard-Host_B disabled=no

Add IP address 10.1.1.2/30 to the newly created WireGuard Interface in /IP/Address

/ip/address/add address=10.1.1.2/30 interface=wireguard-Host_B disabled=no

Create a WireGuard Peer, WireGuard -> Peers

  • Select the WireGuard interface,
  • In the Allowed Addresses, put 10.1.1.0/30
  • Finally, put in the Public Key from Host A.
/interface/wireguard/peers/add interface=wireguard-Host_A public-key=HOST_A_WG_PUBLIC_KEY endpoint-address=172.16.0.1 endpoint-port=13231 allowed-address=10.1.1.0/30 persistent-keepalive=00:00:30

Conclusion

That should be it. Verify that there is a connection. From Host A, ping 192.168.0.1 or any other remote device.

Troubleshooting

Unfortunately, there appear to be some wonky bugs with WireGuard on RouterOS. It does appear to be getting better, but here are a couple things to check if the tunnel is not connecting.

  1. Verify that the Firewall is not blocking WireGuard. You can allow the WireGuard port in the Firewall.
  2. Try disabling and re-enabling the Interfaces and/or Peers
  3. Verify that all the routes for the PtP are in /ip/routes. If not, try manually adding the route (10.1.1.0/30) on the WireGuard interface on both routers.
  4. Add a keep alive if a router is behind a firewall/NAT.
  5. Reboot and or Upgrade the RouterOS version and firmware.

MikroTik RouterOS Privilege Escalation Exploit CVE-2023-37099

Mikrotik Recently patched CVE-2023-37099 which was a way someone with an admin account, could escalate to a “super admin”, or jail break a router.

It appears the technique has been around for about a year.

Affected versions: < 6.49.7

The good news is that someone would already have to have an account to elevate permissions. If your routers have been using strong passwords or SSH public/private keys and have internet management disabled, then you are probably fine.

https://github.com/MarginResearch/FOISted

https://vulncheck.com/blog/mikrotik-foisted-revisited

Information on the mcuser on Ubiquiti Radios

Who is this mcuser on ubiquiti devices? Nothing shows up in the radio config file about it, but the user shows up in /etc/passwd

mcuser is used for AirControl2. If we look what is in the passwd file, we’ll notice that there is a ! at the beginning of the hash. Meaning that this password is disabled as the hash is not a proper hash. It’s only 10 characters long instead of the normal 13 for Unix DES hashes.

mcuser:!VvDE8C2EB1:0:0::/etc/persistent/mcuser:/bin/sh

https://community.ui.com/questions/Virus-atack-v2/be924ab6-5cb0-4f9b-a4f7-246025196cc0?page=10

There is a valid ssh key, so the mcuser can ssh to the device without a password and do what it needs to do. Doing an ls on a device shows the following.

Refer to the following article on removing AirControl Provisioning

How to Create a Preshared Key for Wireguard

You may have encountered a Mikrotik error when trying to create preshared key

Couldn't change wireguard peer<> - invalid preshared key (6)

This is because a Wireguard preshared key needs to be 256bit (32 byte) base64 encoded key. We have a couple different ways we can generate the correct format.

1. Use Openssl to generate a random 32 byte password

openssl rand 32 | base64

2. Create a 31 character password and base64 encode it

echo Thisisthepassword31characterslo | base64
VGhpc2lzdGhlcGFzc3dvcmQzMWNoYXJhY3RlcnNsbwo=

Now we can take this and add it to our config. The config option is

PresharedKey = VGhpc2lzdGhlcGFzc3dvcmQzMWNoYXJhY3RlcnNsbwo=

https://www.wireguard.com/papers/wireguard.pdf

https://forum.mikrotik.com/viewtopic.php?t=184469

Operation Triangulation – iOS Zero-click APT Exploit Info

Quick Summary: Operation Triangulation is an iOS zero-click exploit that will self destruct, looks to have been used since at least 2019, works on iOS 15.7, unsure if it works on iOS 16. Can collect location, mic recordings, photos, and manipulate iMessages. First point of entry is from an iMessage message, that compromises the device, after compromise, the message gets deleted.

https://securelist.com/operation-triangulation/109842/

https://www.kaspersky.com/about/press-releases/2023_kaspersky-reports-on-new-mobile-apt-campaign-targeting-ios-devices

https://arstechnica.com/information-technology/2023/06/clickless-ios-exploits-infect-kaspersky-iphones-with-never-before-seen-malware/

Links for checking for infection.

https://securelist.com/find-the-triangulation-utility/109867/

https://github.com/KasperskyLab/triangle_check

The following is a list of C&C domains from the securelist.com article. Did a quick DNS lookup for each domain and they currently have the following records & IP addresses. Note that these can change at any time and some of the IP addresses are/can be shared with other legitimate websites if it is on a shared hosting provider.

addatamarket.net - sandy.ns.cloudflare.com, doug.ns.cloudflare.com - No A records, or TXT
backuprabbit.com - nelci.ns.cloudflare.com, morgan.ns.cloudflare.com - No A records, or TXT
businessvideonews.com - ns2.dnsowl.com, ns3.dnsowl.com, ns1.dnsowl.com - 198.251.81.30, 209.141.38.71, 107.161.23.204
cloudsponcer.com - Cloudflare, kipp.ns.cloudflare.com, joyce.ns.cloudflare.com
datamarketplace.net - ns78.domaincontrol.com, ns77.domaincontrol.com, 34.98.99.30
mobilegamerstats.com - ns1.bitdomain.biz, No A records, TXT=v=spf1 redirect=_spf.mailhostbox.com
snoweeanalytics.com - cody.ns.cloudflare.com, arlee.ns.cloudflare.com - 104.21.76.6, 172.67.184.201
tagclick-cdn.com - ns4.bitdomain.biz, ns3.bitdomain.biz, ns2.bitdomain.biz, ns1.bitdomain.biz - No A records, TXT=v=spf1 redirect=_spf.mailhostbox.com"
topographyupdates.com - nero.ns.cloudflare.com, dalary.ns.cloudflare.com - 104.21.27.67, 172.67.141.199
unlimitedteacup.com - nelci.ns.cloudflare.com, javon.ns.cloudflare.com - 104.21.55.58, 172.67.145.72
virtuallaughing.com - elaine.ns.cloudflare.com, braden.ns.cloudflare.com - 104.21.60.240, 172.67.202.140
web-trackers.com - dns1.registrar-servers.com, dns2.registrar-servers.com - 15.164.228.250
growthtransport.com - ns3.dnsowl.com, ns2.dnsowl.com, ns1.dnsowl.com - 198.251.81.30, 107.161.23.204, 209.141.38.71
anstv.net - ns64.domaincontrol.com, ns63.domaincontrol.com. - 93.90.223.185
ans7tv.net - ns37.domaincontrol.com,ns37.domaincontrol.com - 93.90.223.185

List of domains

addatamarket.net
backuprabbit.com
businessvideonews.com
cloudsponcer.com
datamarketplace.net
mobilegamerstats.com
snoweeanalytics.com
tagclick-cdn.com
topographyupdates.com
unlimitedteacup.com
virtuallaughing.com
web-trackers.com
growthtransport.com
anstv.net
ans7tv.net

List of IPv4 addresses used

107.161.23.204
198.251.81.30
209.141.38.71
34.98.99.30
172.67.184.201
104.21.76.6
172.67.141.199
104.21.27.67
172.67.145.72
104.21.55.58
104.21.60.240
172.67.202.140
15.164.228.250
209.141.38.71
198.251.81.30
93.90.223.185

Bash command to get an updated IP address list. bad.txt contains all the above domain names.

for i in `cat bad.txt` ; do dig $i a +short >> badips.lst; done

Check DNS logs

If you have a DNS server, you can check to see if there has been any name resolution by using the following. Change named.log to your dns log

# list=""addatamarket.net"
"backuprabbit.com"
"businessvideonews.com"
"cloudsponcer.com"
"datamarketplace.net"
"mobilegamerstats.com"
"snoweeanalytics.com"
"tagclick-cdn.com"
"topographyupdates.com"
"unlimitedteacup.com"
"virtuallaughing.com"
"web-trackers.com"
"growthtransport.com"
"anstv.net"
"ans7tv.net""

# for domain in $list; do echo $domain && sudo grep -i $domain /var/log/named.log; done

Setup Mikrotik capture traffic

Mikrotik packet sniffer settings to capture traffic coming or going to the above IP addresses.

/tool sniffer
set file-limit=32000KiB file-name=Triangulation filter-ip-address="107.161.23.20\
    4/32,198.251.81.30/32,209.141.38.71/32,34.98.99.30/32,172.67.184.201/32,104.\
    21.76.6/32,172.67.141.199/32,104.21.27.67/32,172.67.145.72/32,104.21.55.58/3\
    2,104.21.60.240/32,172.67.202.140/32,15.164.228.250/32,209.141.38.71/32,198.\
    251.81.30/32,93.90.223.185/32" 

You can then start the sniffer by running Tools -> Packet Sniffer Settings -> Start

or run

/tool/sniffer/start

Resolution

Apple issued an update that fixes the kernel part of the vulnerability.

https://securelist.com/triangledb-triangulation-implant/110050/

Unable to launch Flatpaks on Fedora using Hardened Kernel

If you have installed the hardened Linux Kernel on Fedora, you may have encountered the following error when trying to launch Flatpak applications.

bwrap: No permissions to creating new namespace, likely because the kernel does not allow non-privileged user namespaces. On e.g. debian this can be enabled with 'sysctl kernel.unprivileged_userns_clone=1'.
error: Failed to sync with dbus proxy

https://security.stackexchange.com/questions/209529/what-does-enabling-kernel-unprivileged-userns-clone-do

https://github.com/containers/bubblewrap/issues/324

The issue looks to arise from the fact that the hardened Linux Kernel disables unprivileged name space and Fedora does not have setuid on by default on the bubblewrap executable.

Enabling setuid on bubblewrap

You can set the setuid permission on the bubblewrap executable with

sudo chmod u+s /usr/bin/bwrap

Allow Unprivileged Name Space (Alternative work around)

You could also allow unprivileged name space by running

sysctl kernel.unprivileged_userns_clone=1

Note that setting the setuid seems the safer/recommended option.

It looks like using the setuid binary for bubblewrap would be better to use then enabling unprivileged user space.

https://madaidans-insecurities.github.io/guides/linux-hardening.html#sysctl-kernel

Remove setuid on bubblewrap

If you would like to remove the setuid permission for any reason, you can with the following command.

sudo chmod u-s /usr/bin/bwrap

Reversing Obfuscated Phishing Email

Ran across an email that had an attachment named Payment.htm. This kind of phishing attack isn’t anything new, but the htm file had some interesting obfuscation inside of it.

https://news.trendmicro.com/2022/10/31/html-email-attachments-phishing-scam/

Doing some online searching brought up the following analysis on Joe Sandbox

https://www.joesandbox.com/analysis/831537/0/html

Opening up the file in a virtual a Kali virtual machine, starts to load what appears to look like a Microsoft Sharepoint site. Notice the URL is the local file. It’s setup to pull the photos from the web. Since the VM had no internet available, the images never loaded.

After spinning around for a second, it loads the “log on page”, already populated with our email address. Note I changed the email address before taking the screenshot.

Typing in a random password and hitting Sign in triggers the sign in page.

Notice the ipinfo.io network connection

Going to https://ipinfo.io/json gives us a good bit of info about our IP address, location etc. It looks like this information is requested and then sent to the hackers.

Since there was not an internet connection, the malicious htm web page never received the IP information and so didn’t continue on to the next stage, it just sat there loading. Should be able to setup a fake local server and feed it the information to continue on to the next stage. Or we can just do some static code analysis

Base64, Base64 and more Base64

Opening up the file in a text editor shows tons of Base64 encoded data. The file is only about 20 lines long, but the individual lines are super long.

This first section of Base64 encoded data is by far the shortest. atob is a javascript function that decodes Base64 data. There are multiple atob functions, meaning that to actually get the data, we’ll need to decode the data multiple times. Or we can just copy out the atob functions, and run them directly in Node.js to get the output.

This is fairly easy to do, run nodejs from the command line, set the variable, and print it to console

# nodejs
> let b64 = atob(atob(etc...etc...etc...))
> console.log(b64)

Unfortunately, the next few lines are too large to do what we just did. What we can do is duplicate the file, then delete all non javascript text. Next we can replace the beginning lines where it says “document.head……atob” to

console.log(atob(atob(atob(.....))));

After we have cleaned up the file and made those changes, we save it, and now run it as a javascript file.

nodejs ./Payment.htm

If we want to, we can pipe the output into another file with the > operator

nodejs ./Payment.htm > Decoded_Payment.js

Deobfuscating the important stuff

Looking at the decoded code shows that there is still some obfuscated stuff in that last line.

The var _0x8378= array contains a lot of human unreadable text.

Fortunately, this is not hard to decode at all. In a terminal, launch nodejs again, copy the whole array as a variable, and then just print the whole array.

nodejs
> var _0x8378 [.....]
> > console.log(_0x8378);
[
  '.loaderxBlock',
  'querySelector',
  '.overlay',
  '.loginForm',
  '.lds-roller',
  '#logoPage2',
  '.backArrow',
  '.emailBlock',
  '.passwordBlock',
  '#next',
  '#signin',
  '.emailInvalid',
  '.passwordError',
  '.passwordNull',
  '#boilerText',
  '.passwordImput',
  '.emailInput',
  'ssvv',
  'getAttribute',
  'rrt',
  'getElementById',
  '#bbdy',
  '.canvas',
  '.imgclass',
  '.loader',
  '.logerMe',
  '.tittleText',
  'aHR0cHM6Ly9zdXBwb3J0Lm1pY3Jvc29mdC5jb20vZW4tdXMvb2ZmaWNlL2ZpeC1vbmVkcml2ZS1zeW5jLXByb2JsZW1zLTA4OTliMTE1LTA1ZjctNDVlYy05NWIyLWU0Y2M4YzQ2NzBiMg==',                                                                                                                                 
  'test',
  'Email =',
  'log',
  'load html',
  'href',
  'location',
  '#',
  'backgroundImage',
  'style',
  'body',
  'dXJsKCdodHRwczovL2FhZGNkbi5tc2F1dGgubmV0L3NoYXJlZC8xLjAvY29udGVudC9pbWFnZXMvYmFja2dyb3VuZHMvMl9iYzNkMzJhNjk2ODk1Zjc4YzE5ZGY2YzcxNzU4NmE1ZC5zdmcnKQ==',                                                                                                                             
  'display',
  'none',
  'block',
  'value',
  '5823592882:AB1830h83D83DjWmnaEao398JHEXhueXE83',
  '-839602468',
  'aHR0cHM6Ly9hcGkudGVsZWdyYW0ub3Jn',
  'aHR0cHM6Ly9pcGluZm8uaW8vanNvbg==',
  'userAgent',
  'navigator',
  '0',
  'padStart',
  'getDate',
  'getMonth',
  'getFullYear',
  '/',
  'json',
  'ip',
  'city',
  'country',
  'org',
  'postal',
  '/bot',
  '/sendMessage?chat_id=',
  '&text=<b>OFFICE365-HTML-LOGS@ZERO</b>%0A[',
  '] ',
  '%0A<b>USER-AGENT: </b>',
  '%0A<a>see me: @mrcew</a>%0A<b>EMAIL: </b><pre>',
  '</pre>%0A<b>PASSWORD: </b><a>',
  '</a>%0A<b>Location: </b>IP: ',
  ' | CITY: ',
  ' | COUNTRY: ',
  ' | ORG: ',
  ' | POSTAL: ',
  '&parse_mode=html',
  'obago!',
  'borderColor',
  '#0067b8',
  'onLine',
  'reload',
  '.emailLabel',
  'innerHTML',
  'grid',
  'red',
  'click',
  'addEventListener',
  'length',
  'Done 2 times',
  'replace',
  '',
  ' ',
  'src',
  'keyup',
  'keyCode',
  'preventDefault'
]

Notice we have some more Base64 encoded URLs.

These are easy to decode.

> console.log(atob("aHR0cHM6Ly9zdXBwb3J0Lm1pY3Jvc29mdC5jb20vZW4tdXMvb2ZmaWNlL2ZpeC1vbmVkcml2ZS1zeW5jLXByb2JsZW1zLTA4OTliMTE1LTA1ZjctNDVlYy05NWIyLWU0Y2M4YzQ2NzBiMg=="));
https://support.microsoft.com/en-us/office/fix-onedrive-sync-problems-0899b115-05f7-45ec-95b2-e4cc8c4670b2
> console.log(atob("dXJsKCdodHRwczovL2FhZGNkbi5tc2F1dGgubmV0L3NoYXJlZC8xLjAvY29udGVudC9pbWFnZXMvYmFja2dyb3VuZHMvMl9iYzNkMzJhNjk2ODk1Zjc4YzE5ZGY2YzcxNzU4NmE1ZC5zdmcnKQ=="));
url('https://aadcdn.msauth.net/shared/1.0/content/images/backgrounds/2_bc3d32a696895f78c19df6c717586a5d.svg')
> console.log(atob("aHR0cHM6Ly9hcGkudGVsZWdyYW0ub3Jn"));
https://api.telegram.org
> console.log(atob("aHR0cHM6Ly9pcGluZm8uaW8vanNvbg=="));
https://ipinfo.io/json

The last URL is the ipinfo.io one we saw in the browser developer tools. Some of the variables from the above variable also seem to map to the return info from ipinfo.

SELinux Audit Commands and Links

Show what and why something is failing

audit2why < /var/log/audit/audit.log

Search with ausearch

ausearch -m avc --start recent

Create and apply a module to fix the failure

This creates two files, a .pp and .te. The .pp is the compiled version of the .te

audit2allow -M mymodule < /var/log/audit/audit.log
semodule -i mymodule.pp

Note that “mymodule.pp” will replace any previous “mymodule.pp”. If your needing to create multiple modules/allow multiple exceptions, you can change the name of each module.

You can also add the rules together then manually compile it. Refer to the first link for more details.

Links with more info

https://danwalsh.livejournal.com/24750.html

http://selinuxgame.org/tutorials/ausearch/index.html

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security-enhanced_linux/sect-security-enhanced_linux-fixing_problems-allowing_access_audit2allow