Sunday, October 31, 2021

The polar bear method

Mandatory book: Secure Coding in C and C++      

Preface

I have been a bug hunter since 2015. You can see my CVEs here: http://sandboxescaper.blogspot.com/p/disclosures_8.html

A large majority of those bugs have been logic bugs. I started my career as an high school drop-out with nearly no coding experience. Back in 2015 I was heavily inspired by the work James Forshaw did. He exposed a previously mostly untouched gold mine of logic bugs. I quickly figured out how to find these logic bugs despite my limited coding and reversing experience. I continued to do this until I joined Microsoft. However, in retrospect, despite having had success in finding bugs, my technical skills quickly plateaued and I wasn't learning anything new or improving my skills.

So now I will introduce to you, the correct way to lay a solid foundation to become a bug hunter.

The Polar Bear method

Disclosed bugs found using this method. 

This method is a huge departure from what I used to do before.

Now I just read source code and use windbg.

-CVE-2021-33772: Windows TCP/IP remote DoS

This is a remote DoS. Won't go into detail

-CVE-2021-34511: Windows installer LPE

This is an UaF in the system service (first exploitable mem corruption bug in msi in its history I believe discounting one from 2000s that didn't cross priv boundaries)

-CVE-2021-28479: Windows CSC Service Information Disclosure

This is a big stack memory info leak

To add more credibility to my method, watch for Januaries patch tuesday as the majority of my past year's work will get patched then. And those bugs are also by far more severe then anything I've ever found.

Finding your target

Variant hunting is an easy way to find bug. And often the safer option.

However, I would strongly recommend exploring new components.

You can find information about components on the msdn pages or books such as windows internals.

There's a lot of areas with no history of CVEs. This could be an indicator that nobody has really looked at them. 

A target is usually defined as something that either crosses privilege or device boundaries (or both!).

Finding an entry point in your target

A little background:

Going forward I will be using network protocols as an example. The majority of my work in the last year has been in network protocols (you will see in January's patch tuesday).

About a year ago, one of my bosses told me about these crazy tcpip bugs in the msrc tracker.

I got curious. Until that moment my world was limited to local bugs. Sending bytes and pwning a device remotely, WHAT THE HELL? I couldn't believe this type of bug existed. I was fascinated by it.

I spent atleast one or two months taking these PoCs apart, learning scapy to construct packets and reading much of the code in tcpip.sys. 

Doing this was vital, because it taught me about bug patterns that can occur in network facing attack surfaces. 

I have never talked to the person who found all these doomsday tcpip bugs, they work at Microsoft and I believe their twitter handle is: @piazzt .. their PoCs opened up a whole new world for me, so I can't in good conscience write this blogpost without giving credits there.

Getting started:

Unless you can read assembly or decompiler output just as easily as actual code, start with open source.

Seriously. Don't be cocky. Find an open source project, and build a debug build so you have pdb files.

Like, find some crappy open source ftp server or something,

Next you download windbg next (windows store). In the settings, point to pdb and source files.

What you want is the ability to step through source code. You have to be able to step through source code, otherwise you are not doing the polar bear method. No sane person steps through assembly instructions unless you are an elite hacker with 50 years of experience, and in that case this blog post is not aimed at you.

Generate legitimate traffic:

Ideally you want two seperate VMs. One ubuntu VM (or whatever) for running wireshark and one Windows VM with the target you want to exploit.

So you're running an ftp server on windows. While Wireshark is running, logon to the ftp server from your ubuntu VM.

The reason we do this, is that you may see keywords that you can use to search the source code and set an initial breakpoint in Windbg (on the windows VM).

Getting a breakpoint to hit:

Just set a bunch of breakpoints in windbg using functions that you suspect are used in that initial packet parsing.

One you get a hit. View the callstack. Keep going up the callstack until you find the mother of all functions. With that I mean, the function where all of the packet parsing starts.

This is your main goal! Get a breakpoint at the start of packet parsing!!!!

Exploration:

You can capture legitimate traffic. So you know atleast one valid way to structure a packet. Is the protocol public? Then there's probably and RFC out there which you can use. RFCs are awesome.

The first step is to recreate the packet that triggers your breakpoint in a tool like scapy.

In scapy you can just add raw bytes to a variable and send it to your target, it should be the same bytes you see in wireshark (scapy also supports protocols, but for more obscure protocols I just write my entire packets in bytes). Scapy is not hard to learn. And you can find many examples. I've decided against a complete step-by-step guide this time, because learning to figure out things yourself is important too and will make this write-up even more convoluted. Aside from that, I'm always willing to answer questions if I know the answer.

Take note of the initial code path of your legitimate packet. When I refer to code path. I mean, your initial packet parsing function until it returns again.

Your entire packet is user controlled. Find out what you can 'taint' using this packet.

Are things from your packet being copied into buffers? How are size calculations done?  Is there any indexing you control? Any pointer math you can influence? These are the first things I will look at. At this point, I won't worry too much yet about object lifetime bugs, to find those you often need a more complete picture first.

Once you have exhausted your first codepath. Go down the next codepath.



Your initial packet parsing function is the root, the rest are the many branches. 
You go down a different branch by modifying your PoC in scapy so it takes another route during a switch case, if statement, whatever. Then you just walk down the code path in your debugger, again try to spot bugs. Try to make things go out of bounds, stuff like that.

After a while of going down code paths, exploring, you will learn where the most complexity happens. Once you know these areas. Spent a couple of days just trying to break them. Be creative. Sometimes you'll get that Eureka moment when in bed.

PLEASE NO MORE CODE, I FEEL SICK

There will be days when you just don't want to stare at code in a debugger all day.

These will be your FUN days!

You come up with craaaaazy ideas. Like, how can I come up with a worst case complexity scenario?

Can I make it consume resources without them being released? Or just blindly try out potential UaF cases.

Remember that UaF in the MSI installer? 

I found that bug during a day like this. 

There were 3 API calls, one that created something, one that used it, and one that deleted it.

In one thread I called the functions that created and deleted it.

In another thread I called the function that used it asynchronously.

There was no locking on the internal object being used and I had just found a UaF without much effort!

Many weeks later

Once you have explored most of the code paths. You can begin thinking about object lifetime bugs. One important thing you will need to check first is see if packets are process multithreaded or put in a queue. I hope by god nobody doesn't use a queue for packets that operate on the same internal objects (or use perfect locking).

 You can either audit the slow methodical way. Or just use intuition.. like, don't see locking? Just quickly create a PoC.  At this point you can also start coming up to create more complex testcases. Hit codepaths that you're not supposed to be hitting in your current state. Try to free an object, but instead of making it return, make it continue processing until it either frees again or uses it. There's a lot of weird things that can happen. Sometimes you can directly control lifetime of internal object using options in your packet. Just be creative, have fun, shit doesn't have to be boring.

Closing word and fuzzing

People at Microsoft are elite fuzzers and they use very cool technology. They will always be better and faster at bug hunting then me. 

However, I do see merit in becoming good at spotting bug by reading code and using a debugger. You get a very intimate understanding of both bugs and components. Personally I also just enjoy this more then writing fuzzers. It's important to do things you enjoy. Doing things you don't enjoy is for adults and shit.

When assembly and debugger?

Once you have found enough bugs using source code and debugger, you can try hardcore mode. Just be careful because if you die in hardcore mode, it's game over.

Good luck.