Short write-ups from the lab: infrastructure notes, troubleshooting stories,
and automation experiments.
Building a Lightweight, Self-Hosted IT Ticketing & KB Portal
osTicket · Ubuntu Server · LAMP · CAPEX-first
Designing a simple, reliable, and cost-effective ticketing system on repurposed
hardware using Ubuntu Server, a LAMP stack, and osTicket — with a strong push
toward self-help via a dedicated knowledge base.
I recently completed an IT consulting project where the goal was to create a
simple, reliable, and cost-effective ticketing system for a small organization.
The main requirement was to have a platform that could track tickets, store
everything cleanly in a database, and lean heavily on a self-service
knowledge base.
Why self-hosted?
Instead of choosing a SaaS service desk, I went with a fully self-hosted setup:
CAPEX over OPEX: the org preferred a one-time capital
expense instead of ongoing subscription costs. Running the service in-house
gave them full ownership with no recurring licensing fees.
Sized for a small team: with fewer than 40 office users,
something like Jira Service Management would have been unnecessary overhead.
The stack
The solution runs on a repurposed workstation with Ubuntu Server and:
LAMP stack (Apache, MySQL/MariaDB, PHP).
osTicket as the core open-source ticketing system.
OAuth / SSO tied into the organization’s AD DS environment so users don’t
need another password.
Automated email notifications and priorities aligned to their internal
workflows.
Regular backups to the existing backup server.
UI customization to make the knowledge base prominent and the interface
more user-friendly.
Result
Fully self-hosted and extremely cost-efficient.
Straightforward for employees to use.
Reliable for tracking and storing ticket history.
Structured around a strong self-help knowledge base (canned responses +
KB articles).
Flexible enough to grow or be customized over time.
Free from SaaS lock-in or recurring charges.
It’s always satisfying to take older hardware, modern tools, and a clear set
of requirements and turn them into something that delivers real value for a
small team.
Beyond “Run SPMT”: SharePoint Online Migration in the Real World
SharePoint Online · SPMT · PowerShell · Power Automate
Migrating on-prem Windows file shares to SharePoint Online using SPMT is the
easy part. The real work is backups, verification, least-privilege design,
information architecture, and automation that actually sticks.
I recently migrated on-prem Windows Server file shares to SharePoint Online
using the SharePoint Migration Tool (SPMT). It’s a solid tool, but it’s only
one piece of the job.
Backups first
Before moving a single file, I took redundant backups: server snapshots,
cloud backups, and offline copies. The rule was simple — rollback must
always be an option.
Verify, don’t trust
Large shares (300GB+) would sometimes report Success while quietly
skipping files. To catch that, I wrote PowerShell checks to:
Compare file counts and sizes between source and destination.
Re-upload missed content.
Re-run verification until everything matched 100%.
Least-privilege by design
Permissions were rebuilt instead of blindly copied. Department groups,
security trimming, and GPO alignment were all designed with least privilege
in mind — for example:
Accounting can see Payroll; Payroll is limited to the payroll group.
Sensitive libraries are split by ownership and security boundaries, not
just by “nice-looking” site layout.
Information architecture that users can navigate
A central hub site acting as a company portal and launchpad into
departmental sites.
Clear separation of sites vs. pages — sites for ownership
and security, pages for content.
Navigation, naming, and library design focused on “can people find this in
3 clicks or less?”
Automation that sticks
Power Automate for approvals, notifications, and lifecycle tasks (e.g.
document review reminders).
Scripts for repeatable checks, post-migration cleanups, and ongoing
integrity checks.
Takeaway: migration is not “run a tool.” It’s planning, scripting,
auditing, and permission modeling so content ends up complete, secure, and
usable — not just “somewhere in SharePoint.”
Finding the Key: Notes from a Simple Reverse Engineering Lab
x86 · XOR decoding · Control-flow analysis · COMP325
A small “malware-style” assignment: tracing control flow from main,
ignoring false paths, spotting an XOR loop in checkkey, and
recovering the hidden string Ballyourbasearebelongtous.
For a COMP325 assignment I was given a stripped Linux binary with a simple
goal: reverse engineer the key it expects and use that key to make the
program accept my input. It was framed like a tiny piece of malware —
confusing control flow, a couple of fake paths, and one real check.
Mapping the paths from main
Starting at main I mapped out the obvious branches and saw
three candidate functions: foo, foobar, and
checkkey. With a debugger and some breakpoints, it became
clear that the interesting path was guarded by a comparison against the
first character of my input:
cmp eax, 42h ; 'B'
jz short loc_8048629
When this comparison succeeded, execution jumped toward
checkkey. That told me two things:
The key must start with the character 'B'.
The real validation logic lives after that jump, not in
foo or foobar.
Spotting the XOR loop in checkkey
Inside checkkey there was a loop that loaded a byte, XORed it
with 2Ah, and walked forward until it hit a zero byte. That
looked exactly like an XOR-encoded string decode routine.
The encoded string in memory was:
"KFFSE_XHKYOKXOHOFEDM^E_Y"
Tracing the registers showed edx ending up with a pointer to
this buffer before the XOR and compare logic. I manually decoded a few
characters with 0x2A to confirm the professor’s partial hint,
then used a quick Python script to XOR the full string.
The result was the classic phrase:
allyourbasearebelongtous
Putting the pieces together
At this point I had a plausible key fragment, but the program still
rejected it. Going back to main, that earlier comparison
against 0x42 made more sense: the first character has to be
'B' before the code even reaches checkkey.
Prepending 'B' to the decoded string gave the final key the
binary was expecting:
Ballyourbasearebelongtous
What I took away from this
Don’t walk every basic block line-by-line. Map the high-level paths,
then discard obviously fake or redundant branches.
Look for patterns: tight XOR loops around constant strings are usually
doing some kind of simple decryption or obfuscation.
Trace the important registers (eax, edx, etc.)
between blocks and set breakpoints where they change in interesting ways.
It’s fine to automate the boring parts. Once I knew the XOR mask, having
a script decode the string was faster and less error-prone than doing it
by hand.
Overall, the lab was a good reminder that reverse engineering is mostly
about reducing the search space: follow the real path, ignore the noise,
and let the control flow tell you where the actual checks live.