DevDisasters
Tale of the Cryptic Encoding
Lee S. nodded gently as she re-read the message-board post.
Someone named Robbie had created a posting asking for assistance in resolving a problem with a simple Visual Basic .NET console application. It was used to retrieve and process product registrations and credit card transactions via the Internet for a piece of niche shareware.
"Bottom line, I do FORTRAN and C++, I don't know or want to know Visual Basic .NET," the post explained. "All I know is that I have an app with the 2KB source file for it that I need fixed so I can earn money. I will happily send $100 to the person who can fix this."
Naturally, Lee felt a little bit cautious dealing with some guy (or gal) from the Internet, but the promise of an easy $100 tempted her to take a chance.
Processing over the Internet ... Kind Of
Within minutes of crafting and sending out a professionally worded missive, Lee received a reply.
After graciously thanking Lee for her e-mail, Robbie explained that the attached .exe file normally would run on a daily basis with the output directed to a text file that would, in turn, get loaded into a spreadsheet. Written years ago, it had worked perfectly until the other day when it started choking.
A quick run of the executable revealed the error: Invalid length for a Base-64 char array.
Drawing on her professional experience with troubleshooting Base-64 encoding issues, Lee was positive that the problem would be a cinch to solve. Eager to test her mettle, Lee jumped straight into the attached .vb source file. She was quickly caught off guard:
Imports System.Net.Sockets
Imports System.IO
Imports Confidential
Module EmailApp
Sub Main()
Dim ProcessPayment As New Secret
Dim Server As TcpClient
Dim ns As NetworkStream
Dim sr As StreamReader
Dim s1 As String = "pop3.initech.com"
Dim user As String = "[email protected]"
Dim pass As String = "l&28a%"
Server = New TcpClient(s1, 110)
ns = Server.GetStream
sr = New StreamReader(Server.GetStream)
Dim data As String = "USER " + user + vbCrLf + "PASS " + pass + _
vbCrLf + "STAT" + vbCrLf + "STAT" + vbCrLf
Dim enc1() As Byte = _
System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
ns.Write(enc1, 0, enc1.Length)
Dim x As Integer = CInt(String.Concat(sr.ReadLine + sr.ReadLine + _
sr.ReadLine + sr.ReadLine).Split(" ")(6))
Dim tmp As String
For i As Integer = x To x
data = "RETR " & i.ToString & vbCrLf
enc1 = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
ns.Write(enc1, 0, enc1.Length)
tmp = sr.ReadLine
While (tmp <> ".")
If tmp.StartsWith("Subject") Then
data = tmp.Substring(9, tmp.Length - 9)
End If
tmp = sr.ReadLine
End While
Console.WriteLine(i.ToString + "," + ProcessPayment.DeCrypt(data))
data = "DELE " & i.ToString & vbCrLf
enc1 = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
ns.Write(enc1, 0, enc1.Length)
Next
data = "QUIT " + vbCrLf
enc1 = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray())
ns.Write(enc1, 0, enc1.Length)
End Sub
End Module
Lee's mind was reeling. The way the program "worked" was almost unthinkable. Processing payments over e-mail in the 21st century ... and in the subject field?! Exactly what kind of madness had she walked into?
Reality Sets In
After Lee calmed down, she thought back to what Robbie had said before realizing, "Ah ha! This must be a data problem!" She proceeded to take a peek at the e-mail messages backed up in the account listed in the source code.
The majority of the messages, at least five per day, had subjects that looked like this: H4sIAJ4qnU0AA4vML1VIyy/NS1EoyUhVCE5NLkotUQgN8lFUyCgpKbDS10/KLNHLqdRPyw3LcXLjAgDGBcb9LwAA
However, a Web marketer had apparently discovered the "hidden" account, poisoning it with amazing deals for quasi-legal mail-order pharmaceuticals, which caused the program to choke. Lee figured that she would've choked too.
Because adding a heuristic spam filter to the program was not only out of scope, but also outside of the $100, Lee took the quick and easy route by wrapping the "DeCrypt" function within a Try...Catch block. A quick test revealed that the program could now download and export user registrations as it had before. User names, e-mail addresses, telephone numbers and credit card information all appeared, arranged in neat, comma-delimited fields. Lee sent her revision back to Robbie, who, in return, offered to meet up for coffee.
When they met, Lee did her best to explain why the process failed when it did and what she did to fix it. Robbie appeared to be receptive. Following some additional chit-chat, the payment was handed over and Lee asked one question that still gnawed at her.
"The third file you sent me -- the Confidential.DLL file -- what does that do? Is that ..."
"Sorry, no idea," Robbie cut in with palms opened in front of her. "Not my area of expertise, remember?"
"Besides," Lee chuckled, "everything works exactly as it did before if not better, and that's what counts, right?"
Lee held her breath for a second before extending a hand thanking Robbie for the opportunity. Her sense of developer responsibility was screaming in her head: "Are you crazy, lady?! Yeah, it works today, but what if something else changes? What if you get hacked?"
On the way home, Lee resolved to put off saving the world until another day. Meanwhile, she was going to find out what that DLL did.
Shrouded in Secrecy?
Two main obstacles prevented Lee from seeing how the DLL worked. The lack of program source and the file named "Confidential," which had a class named "Secret." Despite these obstacles, Lee was able to easily decompile the binary file to see the truth that lay therein:
Public Function DeCrypt(ByVal strInput As String) As String
Dim ms As New MemoryStream(Convert.FromBase64String(strInput))
Dim gz As Stream = New GZipStream(ms, CompressionMode.Decompress)
Dim sr As New StreamReader(gz)
Return sr.ReadLine
End Function
Because the initial shock of the calling application had subsided, all that Lee could muster was, "At least they didn't use ROT-13." Somehow, this implementation of decryption fit.
A few months passed before Lee heard from Robbie; payment processing was throwing another fit. The cause this time, though, was the small ISP that had kept the registration e-mail address afloat. It had finally been swallowed by a large telecom prompting them to rename their e-mail servers.
Robbie offered Lee another $100 to help figure out a potential fix. Lee replied that she didn't have the time to dedicate to such a task. "In the meantime," she said, "perhaps you'd like to investigate other options for handling secure online transactions," and forwarded a set of links.
About the Author
Mark Bowytz is a contributor to the popular Web site The Daily WTF. He has more than a decade of IT experience and is currently a systems analyst for PPG Industries.