PlaidCTF 2020 was PPP’s 10th anniversary of the competition. To commemorate the special event (and just for fun), we decided to theme the CTF as “Ready Pwner One”, a play on the book/movie “Ready Player One”. Each of the challenges were accompanied with a piece of the story based around the challenge.
As part of the theme, we wanted to feature technologies that would evoke some of the nostalgia from the past. And of course, what is more nostalgic than our good friend BonziBuddy? The resulting challenge, as f0xtr0t described it, was
A healthy mix of misc and meme. A good dash of file-format rev. And the faintest whisper of the ghost of pwn.
Arguably, “healthy mix” would be more like a drop of food coloring in the ocean of memes, but yeah the description is pretty spot-on for what it’s worth.
This write-up will be a bit different than some of my previous ones as it goes beyond the solution, sharing a lot of the Bonzi goodness I learned about. If you just want the intended solution, feel free to skip to that section.
The History Behind It All
Microsoft Agent Characters
The story goes that Microsoft Agent was built on a “tragic misunderstanding” of research that came out of Stanford University. This research found that people used the same part of their brain when interacting with people and technology. Of course, Microsoft decided this meant they needed to humanize your computer.
Thus, the virtual Microsoft assistant was born. Microsoft Agent and its predecessor, Microsoft Bob, provided a platform to display a virtual “assistant” that users could interact with. Its most well-known character, Clippit or Clippy, was the face of the Microsoft Office of the early 2000s and could help users with . While my elementary school friends and I thought Clippy was the shit, many people found him annoying and he has since been heavily parodied in media.
Clippy featured in the episode “The Void” of The Amazing World of Gumball
Microsoft Agent was everywhere. It was in Microsoft Office. It was there when you installed Windows XP (yes, the question mark is in fact a MS Agent character, Qmark!). People could create and share their own custom characters. Third party companies could even add them to their own software!
But by 2001, the people’s revolt on MS Agent started to prove successful. One huge selling point of Microsoft Office XP was that Clippy was disabled. (In fact, Microsoft published several fever dream-esque ads about this in which Clippy was voiced by the voice actor for Digit from Cyber Chase.) By Window 7, MS Agent no longer came prepackaged with Windows and by Windows 8, MS Agent was completely deprecated and removed from their website.
BonziBuddy
But before we close on this chapter of Microsoft’s history, we of course need to talk about the good that came of it. Specifically the BonziBuddy part. As MS Agent made it possible for third party developers to create their own characters and integrate it into their software, companies like BONZI Software had the opportunity to add a face to their product. And of course BONZI Software thought that the perfect face for their virtual assistant software would be *checks notes* a purple gorilla named Bonzi.
As much as BONZI Software wanted you to find a friend in it, people did not like Bonzi. It was not long before it was considered malware, collecting information via its voice email, web searches, and other features that all ran through BONZI Software’s servers. The FTC even hit BONZI Software with a $75k COPA violation fine.
BonziBuddy made a resurgence in meme culture, popularized by Vinesauce Joel’s Windows XP Destruction and Windows Vista Destruction videos. The latter featured Bonzify, a trojan by the MEMZ creator, Leurak, using the BonziBuddy character .
Designing the Challenge
So of course when bluepichu suggested the idea of a BonziBuddy challenge, I really wanted to make it work.
Learning
I had no knowledge about how BonziBuddy worked so I had to play around with it a lot before I could even understand what options were on the table for problem development. But since MS Agent had been deprecated as of Windows 7, I first needed to solve the recon challenge of finding tools and resources (Oh boy!). Below are the tools and other resources I found to be relevant to getting started with BonziBuddy and MS Agent.
Tools
- Double Agent: an open-source alternative to MS Agent
- Microsoft Agent Character Editor (MACE): tool to create custom ACS character files
- Microsoft Agent Scripting Helper (MASH): tool to script animations and interactions with ACS characters
- MSAgent Decompiler: decompile an ACS file into the ACD, image, and audio files components TETYYS/SAPI4: SAPI 4 is the text-to-speech service used for MS Agent character speech synthesis; this project turned that into a Linux server
Documentation
- Microsoft Agent: legacy Microsoft documentation
- MSAgent File Format Spec Sheet: unofficial documentation on the MS Agent ACS, ACF, and ACA file formats
BonziBuddy
- BonziBuddy website (original)
- BonziBuddy website (mirror)
- Bonzify: MEMZ-variant trojan designed for Vinesauce Joel’s Vista destruction video; originally on Leurak’s GitHub, but since removed
The original idea floated for the challenge was to modify the malicious parts of BonziBuddy and turn it into a RE problem. So I started by poking at the BonziBuddy installer and files it dropped (several Visual Basic executables, the ACS character file, and installed additional MS Agent software). BonziBuddy wasn’t malicious in a particularly interesting way. The maliciousness was that it tracked user information that was entered into it - emails, searches, etc. It didn’t feel quite compelling or reasonable set-up-wise, so I redirected my efforts to better understanding the technology behind BonziBuddy.
To get a MS Agent character to display on the screen you need 3 things; Microsoft Agent, TruVoice, and your own program. MS Agent and TruVoice only interpreted and carried out commands. Your program was the one that had to specify them.
Components involved in displaying the interactable ACS character.
I played a little bit with an interface for TruVoice, but I realized regardless of what I decided to do for the challenge, I’d need to interact with the ACS file format. MACE and MASH were useful, but didn’t offer fine-grained programmatic control over ACS file manipulation. Because of this, I spent a significant amount of time writing parsing code. This was difficult since there was no official documentation for the ACS file format; the only thing available was Leabeau Software’s unofficial file spec. Referencing this spec, everything seemed to line up except the GUID struct (see correct version below), but it was a godsend. The full ACS parsing code can be found here.
TODO: Add ACS file parsing code TODO: Add Bonzify-master.zip
1
2
3
4
5
6
7
typedef struct GUID {
ULONG Data1;
USHORT Data2;
USHORT Data3;
USHORT Data4; // Missing in Leaveau Software version of spec
BYTE Data5[6];
} GUID, *PGUID;
Another lesson learned during this process: read the spec closely. Not doign this of course led to several bugs in my image data decompression algorithm, which led to some pretty hilarious images.
As I began wrapping up the draft of my parsing code, I started thinking - the ACS file format is old and weird, so why not base a challenge around it?
Development
One thing I think other categories tend to have over forensics-type challenges is that they’re more likely to have some sort of interaction component. I like that set up and wanted to try and create a more engaging forensics/misc problem. The main requirement I had was that I wanted players to demonstrate their understanding of the ACS file format. And what would demonstrate understanding more than making people have to create their own ACS file? As I experienced, none of the MS Agent tools go in-depth, so players would have to make their own parser or tools to understand and manipulate ACS files in a fine-grained manner.
I picked an interesting part of the ACS file format, the compressed character images, and considered where things could go wrong with it.
- How is the end of compressed data indicated? If we don’t add the “end of compressed data” marker, could trick it into reading the next compressed image.
- How is the destination buffer used? If the buffer is not cleared out & the reported size is not the same as the actual size of compressed data, might be able to leak stale data.
- How does the algorithm decompress bytes? Could trick it into copying data from elsewhere in file/memory with certain offsets.
I went with the 3rd option. The challenge was set up as a web app that would take an ACS file and number N
, and would extract and decompress the N
th image in the ACSImageInfo
list.
For this to work, the flag would need to be placed somewhere in the ACS file (e.g. a string field, such as the description), and to leak the flag, decompression would have to happen in-place to be able to have access to the flag. Yes, it would’ve made more sense to write it in C/C++ but lazy so it was shoved into Python.
And then of course, most importantly: themeing the problem. Which means replicating the mirrored Bonzi website and making it as obnoxiously meme-y as possible.
- Spicy “An amazing fact” memes randomly picked from a group of 25: I loved watching the requests come into the server and see people madly refresh the index page to find the others.
- That disgusting emoji cursor: Apparently increased CPU usage by 30% for some people “its making my computer hot my legs ouch owie” - a friend who visited the site
- MIDI Darude Sandstorm: Played on loop, restart everytime you refresh or visit a new page.
-
<marquee>
and replicated<blink>
: For that early 2000’s website crunch.
Testing
Difficulties: wanted competitors to learn the spec, so decided to remove parsing & decompression code (also bc the bug was in the decompression algorithm). This sent my tester down the rabbit hole for a while - unclear what the data looked like after decompression step -> what did get_image
do? Decided to give get_image
code. After some discussion, we decidd that it should be possible to get the gist of what the decompress_img_in_place
code would do even if it’s not included. If they read the spec and thought creatively of “what could go wrong”, they could figure out some things they could test and get to a solution.
[TODO: No this is long] A common misconception is that the ACS character file contains all the logic behind the character and content such as the text that might go in the speech balloons. In actuality, ACS files only contain the character definition; the available animations, the images that make them up, the appearance of the speech bubble, etc.
Lastly, I really really didn’t want people looking at a black box problem and playing “let’s fuzz the challenge” so I added in a captcha which I believe is universal language for “you’re not supposed to fuzz this challenge.”
(Big thanks to jarsp & f0xtr0t for helping test & tweak the challenge)
Solution
Now you just need to know how to make one. Download your buddy
- Other writeups
- Intended solution - also welcomed other solutions - seemed like it was possible to get other clever solutions by playing around with file format, but decided would require about the same amount of effort so fine
- Construct fake LOCALIZEDINFO list prior to an image of your choice
- Make sure the ACSLocator correctly points to this
- Flag will get placed in description here
- Spec decompression algorithm - when it encounters compressed bytes, copies X bytes from offset Y from earlier in buffer
- Our buffer is the whole acs file which means that offset can be from wayyyy earlier than it should be
- Like the LOCALIZEDINFO struct the flag is conveniently placed in :)
- [TODO: Solve script/files]
- [IMAGE: Diagram of solution]
- What did other teams do?
Conclusion
Despite the difficulties, it was a ton of fun learning and working with something I enjoyed (memes) and incorporating it into a CTF challenge.
Appendix
Resources
- History