Thursday, December 2, 2021

Hack The Box Cyber Santa CTF - Crypto Day 2 - XMAS Spirit Crypto Writeup


Challenge Files:  crypto_xmas_spirit.zip

Contained the following contents:
  • challenge.py
  • encrypted.bin
As expected, "encrypted.bin" contained 776,746 bytes worth of gibberish:


"challenge.py" contained the following code:

#!/usr/bin/python3

import random
from math import gcd

def encrypt(dt):
        mod = 256
        while True:
                a = random.randint(1,mod)
                if gcd(a, mod) == 1: break
        b = random.randint(1,mod)

        res = b''
        for byte in dt:
                enc = (a*byte + b) % mod
                res += bytes([enc])
        return res

dt = open('letter.pdf', 'rb').read()

res = encrypt(dt)

f = open('encrypted.bin', 'wb')
f.write(res)
f.close()

The first thing I noticed is that it opened a file called "letter.pdf", and I didn't see that in the challenge zip file.  Re-reading the challenge description, it says, "Santa has no idea about cryptography. Can you help him read the letter?"  Therefore, we need to decrypt the "encrypted.bin" into a "letter.pdf" file.  This script took in the original "letter.pdf" and encrypted it into "encrypted.bin", and now it's our job to reverse the process.

I started by trying to manually reverse the encrypt() function into a decrypt() function, but quickly got stuck trying to reverse the modulus on this line:  enc = (a*byte + b) % mod

After rigorous Googling on how to perform the inverse of a modulus operator, I took a break from that strategy after realizing how hard it is to do so, since reversing a "mod" operator yields many answers.  For example, since modulus captures the remainder of two numbers divided against each other, all odd numbers divided by 2 always has remainder 1.  So a zillion things can be the answer to "x % 2 = 1".

Changing gears, I spawned a "test.py" file to figure out how the encrypt() function works by observing how it handles simple input.  In my case, I fed it "AAAABBBB" with some debug print statements to see what the encrypted contents look like.


I ran it a few times and noticed the "a" and "b" values changed each time, but the "Byte" value stayed the same.  "Byte" is the variable representing each individual character from the input string, so that makes sense that it stayed static.  Since "a" and "b" changed each time, the math produced different encrypted strings each time as well.  I got curious if it would ever randomly produce the original input string if I ran it enough times.  Let's see why "a" and "b" keeps changing with each run:

mod = 256
a = random.randint(1,mod)
b = random.randint(1,mod)

So "a" and "b" is given a random number between 1 and 256 each run.  This means there is only a finite amount of ciphertext the encrypt() function can create; therefore, ONE of these random "a's" and ONE of these random "b's" combinations HAS to decrypt the message!  So for my small scale test, I did an infinite while loop that only stops if it finds the original input string of "AAAABBBB".  Essentially, my goal was to feed in "AAAABBBB" and obtain "AAAABBBB" as the "encrypted text" using the same challenge algorithm.  I also printed out which "a" and which "b" was responsible for this as well:

while True:
        encrypted, a, b = encrypt(message)
        if b"AAAABBBB" in encrypted:
                print("\nEncrypted Message: %s, a: %s, b: %s" % (encrypted, a, b))
                break

And I found it with "a = 1" and "b = 256", yielding this same output repeatedly:


Of course for the real thing, we wouldn't use a=1 and b=256 because that would just take in the original "encrypted.bin" and give us the same gibberish as output, but alas, we have proof of concept.  Now for the real thing, I modified the code to loop through 1-256 for "a" and 1-256 for "b" in a double for loop.  

Also, I only read in one line of gibberish from the "encrypted.bin" file because if I tried to decrypt all the data through my double for loop, it would take an eternity for a ~0.75MB text file.

More importantly, I opted to try decrypting only the first line from "encrypted.bin" because I assumed this would spit out a legitimate PDF file, and if so, the file header with the "PDF" magic number would appear if decrypted successfully.  As I decrypted each with a different "a" and "b" value, I wrote it to a file in the file name format, "output_a_b.pdf" where "a" and "b" is replaced with their current respective values in the for loop.  Here's my code to do so:

with open("encrypted.bin", "rb") as f:
        data = f.read()

for A in range(1, 256):0
        for B in range(1, 256):
                file = open("PDFs/output_%s_%s.pdf" % (A, B), "wb")
                #print(encrypt(data, A, B))
                file.write(encrypt(data, A, B))
                file.close()

2 Important things to note:  
  • When reading and writing binary data, you must read it in with "rb" and write it out with "wb" instead of just 'r' and 'w'.
  • Notice I commented out the print statement.  Here's why.  Brute forcing tactics take a long time, and printing debug messages to the screen makes it take HOURS longer, so I commented out that line after I had a warm fuzzy that my code worked properly.  
    • I created a password brute forcer in C some time ago and it took 18 hours to crack a five character password when I printed out "Password not found" over and over.
    • I commented out that line, and it took half a millisecond...
In another terminal on my Kali machine, I ran "file *.pdf | grep PDF" when it finished.  LO AND BEHOLD, ONE FILE HAS A PDF HEADER!


At this point, I could taste the flag in my mouth, AND I thought how ridiculous it would've been to try to reverse the modulus math.

I modified my code for the final time with "a=153" and "b=96" hardcoded in (it actually took a few tries with my typos because my hands were shaking from excitement).  I also changed "readline()" to "read()" since we want to process the entirety of "encrypted.bin" now.  Not required, but for satisfaction, I also made the output file "letter.pdf" as intended by the challenge story.

with open("encrypted.bin", "rb") as f:
        data = f.read()
file = open("letter.pdf", "wb")
file.write(encrypt(data, 153, 96))    # I changed the function to "def encrypt(dt, a, b)"
file.close()

And... VOILA!!!  The letter to Santa and the flag!  I've never seen something so exciting!


HTB{4ff1n3_c1ph3r_15_51mpl3_m47h5}
















Friday, February 20, 2015

How to Disable Windows 8.1 Update Notification

This is all you need to do, BLAM!
  1. Create this key: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsStore
  2. Create this String value inside WindowsStore:  DisableOSUpgrade (set its value to 1)
  3. Uninstall and hide it next time you see it in Windows Update:  KB2871389
  4. Make Windows ask you what updates you want to download and install
  • http://www.askvg.com/how-to-disable-update-to-windows-8-1-for-free-notification-in-windows-8-store/
  • http://www.eightforums.com/tutorials/37808-update-windows-8-1-store-prompt-enable-disable.html

Sunday, February 8, 2015

Android Studio ADB Doesn't Recognize Samsung Galaxy S5

Problem:  You're trying to test your awesome Android/Java code on a real live phone connected via USB, but Android Studio doesn't recognize your device no matter what you do.  Well, here is a checklist of items to make sure you have to ensure your device is recognized:

In Short:
  • Turn on Debugging Options and enable USB Debugging
  • Install Google USB Drivers from SDK Menu in Android Studio
  • Install "Samsung USB Driver for Mobile Phones"
  • Restart adb and check if your phone is in the list
  • Accept the RSA Fingerprint verification on phone
Details:
  • Connect your device via USB to your computer
  • Turn on Debugging options on your phone by tapping "Build Number" seven times in the "About Device" in your phone settings
  • Open the "Developer Options" in your phone settings and make sure "USB Debugging" is checked
  • Go to the "SDK Manager" of Android Studio and install "Google USB Driver"
  • Install "Samsung USB Driver for Mobile Phones" from Samsung:  http://developer.samsung.com/technical-doc/view.do?v=T000000117
  • Restart ADB and verify device from command line (I only typed adb devices):  
    • C:\Users\hans\AppData\Local\Android\sdk\platform-tools\adb kill-server
    • C:\Users\hans\AppData\Local\Android\sdk\platform-tools\adb start-server
    • C:\Users\hans\AppData\Local\Android\sdk\platform-tools\adb devices
  • Somewhere in this last step, your phone will prompt you for an "RSA Fingerprint" verification.  In this case, you accept.  If you see this, then you're GOLDEN!

Sunday, October 12, 2014

"VMWare Workstation and Hyper-V are not compatible..."

When running VMWare Workstation, if you've ever gotten the error "VMWare Workstation and Hyper-V are not compatible...", here's what to do. I got this error running VMWare Workstation 10 on Windows 8.1. I'm not sure if it applies to more OS's.

Here's what to do:
1. Open cmd.exe with "Run As Administrator"
2. Type bcdedit /set hypervisorlaunchtype off
3. Restart computer, DONE!!!

Sunday, July 20, 2014

"As a result, this virtual machine may experience very low graphics performance. Follow the instructions provided by your graphics card vendor or Linux distribution in order to update your computer's OpenGL drivers."

Opening VMWare Workstation 10 with Windows 7 in Ubuntu hosts initially says the 3D Acceleration doesn't work because "As a result, this virtual machine may experience very low graphics performance. Follow the instructions provided by your graphics card vendor or Linux distribution in order to update your computer's OpenGL drivers."

Simple fix is to shutdown your VM. Edit your *.vmx file in an editor like Gedit or VI and add the following line: mks.gl.allowBlacklistedDrivers = "TRUE"

Start your VM, and it should work dandily!

Trouble Mounting Windows 8 Partition onto Ubuntu?

Ever got this message when trying to access Windows 8 files on a partition from Ubuntu on a dual-boot?
"error mounting at exited with non-zero exit status Windows is hibernated refused to mount"

Type this using the data in your error message:
sudo mount -t ntfs-3g -o remove_hiberfile /dev/sda2 /media/tron/288680458680158A2

Saturday, June 28, 2014

*FIX* Dual Boot Windows 8.1 with Ubuntu 14.04: Ubuntu Install Doesn't Recognize Windows Partition

I've been using Ubuntu as my primary OS for a while now, and have been using VM's to run Windows when necessary (Games, Other Software, etc). However, I've now run into a bind that requires full 100% capability (video editing). VM's don't allow full hardware usage, and Linux video editors plain suck! I need my Adobe Premiere/After Effects/Photoshop products!

So I found it's more painful get Windows 8.1 starting from a Ubuntu base, so I backed up my files, wiped and reloaded with Windows 8.1. The process to get a Dual Boot goes like this (from the Internets): http://www.everydaylinuxuser.com/2014/05/install-ubuntu-1404-alongside-windows.html

1. Install Windows 8.1
2. Use the Windows Disk Management tool to "Shrink" or split your hard drive into a separate partition for Ubuntu
2. Disable Fast Boot/Secure Boot
3. Enable Legacy Boot
4. Make an Ubuntu 14.04 bootable USB and plug it in
5. Reboot into the Ubuntu Live session
*6. Install Ubuntu onto the free partition

Here lies the problem. Your Ubuntu install doesn't see the Windows partition. Neither does GParted. In fact, it only sees your entire hard drive as free unallocated space, and installing Ubuntu on this part would just overwrite your Windows 8.1.

However, the Ubuntu Disk tool shows two partitions as "/dev/sda2" and "/dev/sda3". So things seem half right.

Lucky for you, my Google digging found this solution:
1. Go to the GPT fdisk (gdisk) download page and install the *.deb file for your Architecture version
2. Open a shell and type "sudo sgdisk --zap /dev/sda". It'll complain about partition problems, but it will still work because it'll fix your partition troubles.
3. Successfully install Ubuntu using the Ubuntu Installer (Should be on your Desktop or left sidebar), and you should now see the option "Install Ubuntu Alongside Windows 8"!

This isn't all though. Don't restart your computer just yet because if you do, you'll restart your computer with excitement and frown when Windows 8 loads up instead of an option to use either installed OS. You must fix the bootloader using these steps in your current Ubuntu Live session:
1. Install "Boot Repair"
sudo add-apt-repository ppa:yannubuntu/boot-repair
sudo sh -c "sed -i 's/trusty/saucy/g' /etc/apt/sources.list.d/yannubuntu-boot-repair-trusty.list"
sudo apt-get update
sudo apt-get install -y boot-repair && boot-repair
2. The Boot Repair window should popup. Select "Recommended Repair", and let it go until finish.

3. BINGO! Restart and you should see a menu that gives you about 30 seconds to decide which OS you want to boot into.