A Tale of Two PoCs or: How I Learned to Stop Worrying and Love the Honeypot

Winnie the Pooh image by Disneyclips.com

Direct calls to my mobile from the branch chief, Jim, were recent occurrences, as COVID-19 teleworking efforts dragged into their 6th week and day-to-day operations at my cyber defense employer continued to transform around a remote workforce.

The phone call was about an e-mail sent 20 minutes earlier from the Threat team to us, the Penetration Testers. It amounted to an unsolicited I-found-it-you-check-it chore of investigating two new proofs of concept (PoCs) for CVE-2020-0883 that claim to take control of a system without user interaction. Not a task we wanted, seeing as our cup already runneth over with deadlines and we had no immediate use for such scripts.

Proofs of Concept

The proofs of concept advertised a user-interactionless reverse shell, which was was contrary to the Microsoft advisory that clearly stated the vulnerability required action on the part of the end-user. If either of the proofs of concept could do what they advertised, the risk that CVE-2020-0883 posed would drastically increase by turning a multi-stage exploit requiring time and trickery into a point-and-shoot affair.

Over the phone, Jim and I went through the Microsoft advisory and skimmed over the source code for both proofs of concept. He asked my opinion of the PoCs and I was non-committal, telling him I would take a deeper look at the code and get back to him with an opinion. Pretty sure I can shoot this down in 30 minutes or less.

Exploitation

I sent the details of the task over to my teammate, Ryne, asking his opinion. He’s been doing this a lot longer than I have, and I hoped he’d be able to help get this off our plate quicker. We both agreed that there was a very large chasm between the official description of the vulnerability and what the proofs of concept purport to do. There was also a strange relationship between both PoCs: they seemed to be nearly the same. Was one a fork of the other?

CVE-2020-0883-POC.py by curtbraz
CVE-2020-0883-POC.py by l33terman6000

My curiosity had been piqued. Clearly, I had no other choice than to clone one of the proofs of concept in my laboratory. There, I had an ESXi hypervisor with an already deployed and unpatched Windows 10 virtual machine and a current Kali VM on a flat 192.168.1.0/24 network—an ideal testing ground for the PoC. After untangling some Python 2 vs. Python 3 configuration conflicts on my system, I ran the script and immediately got a shell on the Windows box.

C:\WINDOWS\system32\

What the fuck? A tiny hit of adrenaline absorbed into my hyper-caffeinated bloodstream. The first command I punched in was a dir and a directory listing that overflowed my terminal buffer came back. The session disconnected, so I reconnected and ran whoami.

nt authority\system

I immediately switched back to the chat with Ryne.

Me: “The MS advisory is wrong.”

Ryne: “That doesn’t make sense.”

I sent over a screen shot of my shell.

Command line snippet showing the execution of the proof of concept along with the Windows shell and results of a whoami command.

I began working out whom I was going to have to notify, but there was lingering suspicion struggling to slow me down. Nascent questions were forming, then suffocating beneath the tidal wave of discovery. Ryne began to set up his own test in his home lab. A collective of questions forming in the back of my mind punched to the forefront for a moment: Is this an April Fools’ prank?

Command line image of using the echo command to leave a calling card on the remote Windows system.
The creation of a reverse calling card from the remote Windows side.

Disconnected again, I ran the script for the third time and echo-ed out a calling card. I switch over to my Windows VM to pull up the card, but I can’t find it anywhere. I create a text file on the Windows machine, then flip back to Kali and run the script again to reconnect. Nothing.

Ryne finishes his own test. “I don’t get a shell.”

“Something doesn’t add up here,” I respond.

A few minutes go by as I look at the source code. “I’m gonna decode that block of Unicode. I don’t trust it.”

Unicode payload from the l33terman6000 proof of concept.

The Payload

Me: “I’ve got the code converted. Looks legit.”

Ryne: “It looks like it prints ‘Target is Vul’ no matter what. Does your shell actually work?”

Me: “Ehhh… kinda. The only successful thing I’ve done so far is spit out directory contents. My calling card and reverse calling card aren’t appearing over the wire. I wanna make sure this isn’t a fake-y shell for stupid lulz.”

Five minutes go by as Ryne and I both examine our respective results. I find something.

Me: “So… I decoded from Unicode text, to Unicode entities, to a block of code with a base64 item assigned to the URL variable.”

Me: “That URL variable is NOT my VM. It goes to 54.184.20.69/poc2.php.”

Me: “I have to stop now. This has crossed a line. This is why we don’t run unknown PoCs…”

Resolution With Lingering Questions

“I stand by my initial assessment that this is a client side exploit,” Ryne maintains, never doubting the advisory.

“I agree,” I respond. “I think it’s an emulator. Of some sort.”

“That shell was not your own?”

“No,” I replied. “I think it was a shell into some dude’s PHP script. The server it was on was Ubuntu. Not Windows.” The CVE only affected Windows machines.

Our conversation continues as we discuss notification responsibilities, myself alternating between anger, thankfulness, and horror that these scripts were run on personal home labs instead of work equipment. Thank you, COVID-19?

Ryne had run what appeared to be the original script inside the GitHub repository of a Curtis Brazzell, while I had run the derivation from a user whose account was less than a week old, l33terman6000. Both scripts had nested base64 payloads that pointed to two different IP addresses in the AWS cloud. Was the first one a joke that the second person forked and turned malicious? At Ryne’s recommendation, I put both addresses into VirusTotal. Nothing.

We report our findings up the chain, everyone abuzz with interest and fascination. And questions.

Later that evening, I explain to my wife over dinner the two strange scripts that had consumed my day. I wondered aloud if I had put our home network at risk. Immediately after Ryne and I had concluded our results, I patched my firewall and looked into force-requesting a new IP from my ISP.

A former PHP developer from the early ’00s, I knew there was only so much a server-side script like that could glean from me through that vector, nevermind the fact that the Python script only seemed interested in attaching my username, hostname, and IP to the end of a GET request. My mind twisted around the details clean through my kids’ bedtime routine.

At Last, Some Answers

Later that night, Jim sends me a link to a week-old Twitter thread by the previously mentioned Curtis Brazzell.

Relief washed over me. It was all an experiment. I began to reconsider the entire day in the light of the news. Indeed, I had made several mistakes of a rookie nature. There were several chances to have taken the right road and, had my colleague Ryne been at the helm of this experiment, no doubt he would have found it sooner. I had let my excitement bury my questions in an attempt to barrel to the end of the trap, rather than stop and answer the concerns that popped up along the way.

Missed Opportunities

  1. I think it was Ed Skoudis who told the Marriott ball room full of GPEN hopefuls to always capture your PCAP before you connect, to verify what your eyes see.
  2. When has any C:\WINDOWS\system32\ folder had so many files that it pushes your terminal window buffer out of scroll back?
  3. Come to think of it, since when does “system32” have a lowercase “s?” And WINDOWS isn’t capitalized anymore. Capitalization hat trick? What’s this business about lower-cased “nt” in “nt authority\system.”
  4. If you weren’t capturing PCAP from the beginning of the experiment, you certainly should have captured it when you couldn’t see your own calling cards.
  5. Always, always, ALWAYS read and understand what you’re running before you run it. While this is number 5 in chronology, this is probably number 1 in weight.
  6. Even if you just glance at the source and it’s common practice for payloads to be in Unicode or hexidecimal, forever be suspicious of obfuscated blocks. It takes 60 seconds to decode it on a slow day.
  7. DON’T STOP DECODING. Why is that variable’s value in base64?
  8. Do not assume vetting of a proof of concept has taken place just because of how it got to you. In this case, it went through our Threat team who was alerted to it from Recorded Future, a threat intelligence platform. We were apparently the first ones to examine it.

Ryne had an even bigger red flag when he got a shell before he had even started up his Windows VM for testing. My excitement even bowled over that little tidbit.

Still, we never understood the relationship between the two almost identical proofs of concept. I lingered on the l33terman6000 code, which I had run. At least Ryne’s execution was linked to Curtis Brazzell and the destination for his data was explicable.

Conclusion

As I began to organize my thoughts and collect my artifacts for this article, I began to wonder how Mr. Brazzell would take it if I beat him to publication. I had sent Ryne the Twitter thread the same night I received it, but he didn’t click on it until the next morning. It had been deleted. Was Mr. Brazzell in trouble? Should I at least give him the courtesy of notice before I post this?

Let me go back and Google this last data item that had lingered even smaller than the others in my mind. Both proofs of concept cited the vulnerability developer “TRSTDXPLOITZ” in their near-identical header comments. I had casually searched on that name early in my journey with no results.

Google search results for "Exploit Author: TRSTDXPLOITZ" with Curtis Brazzell's published article as the second result.

Oh! It looks like Brazzell has published! I forced myself not to read the article until I had finished this post. And now that I have gotten out all my experiences…

Post Script

I can only imagine the roller coaster of emotions. So sorry!

Curtis Brazzell

Imagine no more, Curtis! Can I call you Curtis? It feels like we’re friends, now.

As it happens, the relationship between l33terman6000 and curtbraz on GitHub and why the proofs of concept were nearly identical is because they were the same person.

I don’t mind so much falling for the trap. It was probably the most interesting thing I’d done since hunkering down in my office six weeks ago. Going through Curtis’ postmortem takes the sting off the burn, seeing that I wasn’t alone in falling for it.

But it’s also a bit frightening to realize that the only real safety net beneath the use of all these open source proofs of concepts are the people looking at using them.

Why then, do we feel so comfortable running our infosec tools without checking the source? Is it because they’re open source and we assume something would have been caught? Is it due to the widespread use or the fact that someone well known in the industry shared it?

Curtis Brazzell

Yes to all. While I have previously shied away from using freshly published proofs of concept, particularly if the code uses a language I don’t understand, this experience may well have turned my paranoia knob to 11.

Proof of concept for the GhostCat vulnerability, with significant portions written in Chinese characters.
I can’t examine 4 out of 5 GhostCat proofs of concept

I can see how Curtis would have been on the receiving end of some unpleasant thoughts and messages. Relatively early into my penetration testing career pivot, I don’t think I’ve yet grown the ego required to be bruised. In fact, this was a timely lesson for me and one that I think will keep me on a more cautious path when handling 3rd party software.

Leave a Comment