You may notice that the following tips are non-technical, that’s because I honestly believe my best hacking tips are not actually technical points rather concepts that have helped me overcome barriers and enjoy a well-paid, fruitful career.
Don’t Assume Anything
The biggest things that have got me stuck on jobs, during CTFs and even exams like OSCP is a very simple point, I assumed things were harder than they were. I can’t tell you how many times I have done some elaborate steps to get what I need, only to find out later that the solution was much easier and often staring me right in the face. I have also experienced the other side of the coin, like trying to crack certain hashes when I just started out only to realise I would have to wait a million years to crack it. The point? Don’t ever assume, in fact, the opposite, deeply research, choose carefully and strike hard. Watch these talks to see surgical approaches to finding 0days.
Don’t Learn to Hack, Hack to Learn
This one is easy, sure, go learn all you can but the only way to learn is to do. That said, I keep these posts short as to be a top-up/boost in certain areas so you can take those tips and then practise using them in your own ways, after all that is what hacking is about, taking what we know and trying new things with it. I also say another thing which goes one step further, if you want to break it, learn how to make it; I can’t even begin to tell you how many times experience from building/deploying something helped me to exploit it, take this all the way and deploy new types of operating systems, new apps and build things from the ground up.
Learn Everything from a Macro Level First
This is a pretty simple concept, one I learn from programming which I will use an example. I can write in a number of languages, how many? I don’t know, I don’t count anymore. I don’t count because answer is any one I want to, how? I can do this because I learn things from a macro perspective.
In our example, programming, there are only a certain number of things you will want to do:
Hold Multiple Values in Array’s (or language equivalent)
Set Up Variables
This means you can learn one language well to understand how these things might work, then you can simply Google how to do specific things in the new language. Sure there are differences like syntax (just use Google!), and you may have to do things like manage memory yourself; but these are small things to overcome when you realise it’s a language specific issue. This makes it so much easier to write new code in a new language, imagine doing it the other way and approaching it like you had to learn all about a new language each time.
This same concept applies to security, generally speaking there are actually only a few macro vectors, figuring out their platform/level nuances is half the fun but again much easier than thinking all vulnerabilities are different.
The Windows Registry is a hierarchical database that stores low-level settings for the Microsoft Windows operating system and for applications that opt to use the registry. The kernel, device drivers, services, Security Accounts Manager, and user interface can all use the registry. The registry also allows access to counters for profiling system performance.
We have all been there, you see a post or a script that says grep for this or search for that, so you do, but you get more than a haystack in return. The real benefit comes into play when you know common config files and WHAT they contain; what config files contain is important because it might be encoded a certain way, or dare I say it, encrypted with their own algorithm (which can be easily cracked) or it might just be plaintext/base64 encoded. However it is stored, knowing what we are looking for and knowing what we might find there is important to reducing the noise and time spend on fruitless tasks when manually pentesting or researching without tools.
Unlike MS-DOS-based applications, Windows-based applications are event-driven. They do not make explicit function calls (such as C run-time library calls) to obtain input. Instead, they wait for the system to pass input to them.
The system passes all input for an application to the various windows in the application. Each window has a function, called a window procedure, that the system calls whenever it has input for the window. The window procedure processes the input and returns control to the system. For more information about window procedures, see Window Procedures.
If a top-level window stops responding to messages for more than several seconds, the system considers the window to be not responding. In this case, the system hides the window and replaces it with a ghost window that has the same Z order, location, size, and visual attributes. This allows the user to move it, resize it, or even close the application. However, these are the only actions available because the application is actually not responding. When in the debugger mode, the system does not generate a ghost window.
Application runs with higher privileges It may be possible to escalate users privileges
Application disables / hides features It may be possible to obtain unauthorised access
Unauthorised application closing It may be possible to close applications running to monitor usage
Target app uses GUI text for SQL queries It may be possible to exploit classic SQL injection attacks
Target app uses GUI text for file access It may be possible to gain arbitrary file access
Ideas for Research
Given we know apps like messages, and messages are juicy payloads for all types of shenanigans then it’s well worth us fuzzing messaging functions. Personally, I would write simple programs that do one API call, compile it for WinAFL and fuzz it. Go deep enough and I would be truly shocked if you didn’t find anything. Below is a list of API functions to get you started with Windows Messaging.
As you can see blow Microsoft make extensive use of the messaging API for everything from keyboard input to application errors, it’s a nice delivery method when vulnerable as Bret Moore has shown over the years.
while (( bRet = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0)
if (bRet == -1);
// handle the error and possibly exit
if (TranslateAccelerator(hwndMain, haccl, &msg) == 0)
Win API Message Functions
Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
The access() system call checks the accessibility of the file specified in pathname based on a process’s real user and group IDs (and supplementary group IDs).
int access(const char *pathname, int mode);
If pathname is a symbolic link, access() dereferences it. If all of the permissions specified in mode are granted on pathname, then access() returns 0; if at least one of the requested per- missions is not available (or an error occurred), then access() returns –1.
The time gap between a call to access() and a subsequent operation on a file means that there is no guarantee that the information returned by access() will still be true at the time of the later operation (no matter how brief the interval). This situation could lead to security holes in some application designs.
Suppose, for example, that we have a set-user-ID-root program that uses access() to check that a file is accessible to the real user ID of the program, and, if so, per- forms an operation on the file (e.g., open() or exec()).
The problem is that if the pathname given to access() is a symbolic link, and a malicious user manages to change the link so that it refers to a different file before the second step, then the set-user-ID-root may end up operating on a file for which the real user ID does not have permission. (This is an example of the type of time-of- check, time-of-use race condition described in Section 38.6.) For this reason, recommended practice is to avoid the use of access() altogether (see, for example, [Borisov, 2005]). In the example just given, we can achieve this by temporarily changing the effective (or file system) user ID of the set-user-ID process, attempting the desired operation (e.g., open() or exec()), and then checking the return value and errno to determine whether the operation failed because of a permissions problem.
I will update this section with a demo as soon as I am back at work.