Naughty FortiClient

As somebody often connecting to networks not belonging to me (legally!), I have a variety of VPN clients. It seems that everybody uses something else. That’s why I had to install FortiClient a few months back. If you never heard of it, it’s a VPN client that thinks it’s more than that and has no support for VPN portion under Linux.

While FortiClient wasn’t the worst VPN client I ever used, I must say there were no tears when I didn’t need it anymore. As any normal person would, I went to uninstall it only to be faced with a grayed out Uninstall button. Never mind - Windows 10 Settings app might be buggy - so I went to the Control Panel. There situation was even worse as I only had Repair available. No uninstall again.

I searched Internet for a solution and found knowledge base article by Forti itself. And it describes the exact procedure I tried to no avail. So I searched a bit and found solution on Reddit of all places (might be the first time I ever used Reddit for anything other than wasting time).

Solution was to use wmic in order to trigger uninstall. For this one should write the following into the Command Prompt with administrator rights:

wmic product where "name like 'Forti%%'" call uninstall /nointeractive

This will uninstall FortiClient and reboot computer automatically afterward. And finally it’s gone.

Parsing GZip Stream Without Looking Back

Some files can exist in two equivalent forms - compressed and uncompressed. One excellent example is .pcap. You can get it as standard .pcap we all know and love but it also comes compressed as .pcap.gz. To open a compressed file in C#, you could pass it to GZipStream - it works flawlessly. However, before doing that you might want to check if you’re dealing with compressed or uncompressed form.

Check itself is easy. Just read first 2 bytes and, if they’re 0x1F8B, you’re dealing with a compressed stream. However, you just consumed 2 bytes and simply handing over file stream to GZipStream will no longer work. If you are dealing with file on a disk, just seek backward and you’re good. But what if you are dealing with streaming data and seeking is not possible?

For .pcap and many more transparently compressed formats, you can simply decide to skip into bread-and-butter of encryption - deflate algorithm. You see, GZip is just a thin wrapper over deflate stream. And quite often it only has a fixed size header. If you move just additional 8 bytes (thus skipping a total of 10), you can use DeflateStream and forget about “rewinding.”

Wanna see example? Check constructor of PcapReader class.

SignTool and Error -2146869243/0x80096005

As I was trying out my new certificate, I got the following error:

SignTool Error: An unexpected internal error has occurred.
Error information: "Error: SignerSign() failed." (-2146869243/0x80096005)

Last time I had this error, I simply gave up and used other timeserver. This time I had a bit more time and wanted to understand from where the error was coming. After a bit of checking, I think I got it now. It’s the digest algorithm.

SignTool still uses SHA-1 as default. Some servers (e.g. timestamp.digicert.com) are ok with that. However, some servers (e.g. timestamp.comodoca.com and timestamp.sectigo.com) are not that generous. They simply refuse to use weak SHA-1 for their signature.

Solution is simple - just add /td sha256 to the list of codesign arguments.

SDR on Ubuntu x86

[This is a post 3 in two-part series :), for hardware setup go here]

While running SDR radio on Raspberry was fine, I kinda wanted to move this to one of my x86 servers. Due to this, I had to revisit my old guide.

When device is plugged in, trace should be seen in dmesg. If everything is fine, you should see some activity.

dmesg | tail[4306437.661393] usbcore: registered new interface driver dvb_usb_rtl28xxu

To get SDR running, there is some work involved with its compilation. Note the DETACH_KERNEL_DRIVER=ON flag enabling SDR application to access device without disabling its driver. Rest is really similar to official instructions.

sudo apt-get install -y git build-essential cmake libusb-1.0-0-dev libglib2.0-dev
cd ~
git clone git://git.osmocom.org/rtl-sdr.git
cd rtl-sdr/
mkdir build
cd build
cmake ../ -DINSTALL_UDEV_RULES=ON -DDETACH_KERNEL_DRIVER=ON
make
sudo make install
sudo ldconfig

This is an ideal time to test it. As I have the iptables active, I manually enable port on external interface. Other than that I will not restrict application to a single IP but allow it to listen on all interfaces.

iptables -A INPUT -i ^^eth0^^ -p tcp --dport 1234 -j ACCEPT
/usr/local/bin/rtl_tcp -a 0.0.0.0

The last step is to enable running it as a service. We need to create a separate user, enable service, and finalize it all with reboot.

sudo adduser --disabled-password --gecos "" sdr
sudo usermod -a -G plugdev sdr

sudo cat > /lib/systemd/system/rtl_tcp.service <<- EOF
[Unit]
After=network.target

[Service]
Type=exec
ExecStart=/usr/local/bin/rtl_tcp -a 0.0.0.0
KillMode=process
Restart=on-failure
RestartSec=10
User=sdr

[Install]
WantedBy=multi-user.target
Alias=rtl_tcp.service
EOF

sudo systemctl enable /lib/systemd/system/rtl_tcp.service
sudo reboot

And that’s it. Now you can run SDR TCP server on your Ubuntu server.

Merging Two Git Repositories

As I went onto rewriting QText, I did so in the completely new repository. It just made more sense that way. In time, this new code became what the next QText version will be. And now there’s a question - should I still keep it in a separate repository?

After some thinking, I decided to bring the new repository (QTextEx) as a branch in the old repository (QText). That way I have a common history while still being able to load the old C# version if needed.

All operations below are to executed in the destination repository (QText).

The first step is to create a fresh new branch without any common history. This will ensure Git doesn’t try to do some “smart” stuff when we already know these repositories are unrelated.

git switch --discard-changes --orphan ^^new^^

This will leave quite a few files behind. You probably want to clean those before proceeding.

The next step is to add one repository into the other. This can be done by adding remote into destination, pointing toward the source. Remote can be anywhere but I find it easiest if I use it directly from my file system. After fetching the repository, a simple merge is all it takes to get the commits. Once that’s done, you can remove the remote.

git remote add ^^QTextEx^^ ^^../QTextEx^^
git fetch --tags ^^QTextEx^^
git merge --ff --allow-unrelated-histories ^^QTextEx^^/main
git remote remove ^^QTextEx^^

After a push, you’ll see that all commits from the source repository are now present in destination too.


PS: Do make backups and triple verify all before pushing it upstream.

PPS: This is a permanent merge of histories. Consider using subtree if you want to keep them separate.

PPPS: Things get a bit more complicated if you want to transfer multiple branches from the other repository.