Top 3 Hacking Tips

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:

  • Persist Data
  • Do Arithmetic
  • Hold Multiple Values in Array’s (or language equivalent)
  • Call Code
  • Compare Values
  • Set Up Variables
  • etc..

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.

Windows API Calls for Process Injection / Manipulation / Migration

Essential Win API Functions

  • OpenProcess() for opening the remote process
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ DWORD dwProcessId
  • VirtualAllocEx() for allocating memory in remote process
_In_ HANDLE hProcess,
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
  • WriteProcessMemory() for writing shellcode in a newly allocated memory and make it executable
BOOL WINAPI WriteProcessMemory(
_In_ HANDLE hProcess,
_In_ LPVOID lpBaseAddress,
_In_ LPCVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesWritten
  • CreateRemoteThread() for creating a new remote thread and executing the relevant code
HANDLE WINAPI CreateRemoteThread(
_In_ HANDLE hProcess,
_In_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_ LPDWORD lpThreadId
Registry Passwords – Windows Post Exploitation

What is The Windows Registry?

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.

Reading values from registry

C:\> reg query "HKLM\SOFTWARE\Microsoft\Windows NT\Currentversion\Winlogon"

Interesting Registries

reg query "HKCU\Software\ORL\WinVNC3\Password" [VNC]

# Windows autologin
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\Currentversion\Winlogon" [Windows]

# SNMP Paramters
reg query "HKLM\SYSTEM\Current\ControlSet\Services\SNMP" [SNMP PARAMS]

# Putty
reg query "HKCU\Software\SimonTatham\PuTTY\Sessions" [Putty Plaintext Credentials]

# Search for password in registry
reg query HKLM /f password /t REG_SZ /s
reg query HKCU /f password /t REG_SZ /s
Diggin’ for Gold – Windows Post Exploitation

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.

Common Gold

c:\sysprep.inf [Base64 Encoded Password]
c:\sysprep\sysprep.xml [Base64 Encoded Password]
c:\unattend.xml [Plaintext Password]
%WINDIR%\Panther\Unattend\Unattended.xml [Plaintext Password]
%WINDIR%\Panther\Unattended.xml [Plaintext Password]
vnc.ini [Password Easily Decrypted]
ultravnc.ini [Password Easily Decrypted]
dir c:\ /s /b | findstr /si *vnc.ini [Plaintext Password]
dir c:\*vnc.ini /s /b [Plaintext Password]
dir c:\*ultravnc.ini /s /b [Plaintext Password]
dir c:\ /s /b | findstr /si *vnc.ini [Plaintext Password]

Spray and Pray

findstr /si password *.txt
findstr /si password *.xml
findstr /si password *.ini

#Find all those strings in config files.
dir /s *pass* == *cred* == *vnc* == *.config*

# Find all passwords in all files.
findstr /spin "password" *.*
findstr /spin "password" *.*

Recovering Credentials

Extended List/Rare Finds

This list will include common project which are not so mainstream, like web servers and other third party tools users install which leave credential files on system. Check back for update!

Windows Messages, Message Queues & The Infamous Win32 Shatter Attack

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.

Original Research and Pic by Brett Moore

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.

Attack Possibilities

  • 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.

MSG msg;
BOOL bRet;

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.

To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread’s message queue and return immediately, use the PostMessage or PostThreadMessagefunction.


LRESULT SendMessage(
  HWND   hWnd,
  UINT   Msg,
  WPARAM wParam,
  LPARAM lParam


Sends a message to the specified recipients. The recipients can be applications, installable drivers, network drivers, system-level device drivers, or any combination of these system components.

To receive additional information if the request is defined, use the BroadcastSystemMessageEx function.


LRESULT SendMessage(
  HWND   hWnd,
  UINT   Msg,
  WPARAM wParam,
  LPARAM lParam


Places (posts) a message in the message queue associated with the thread that created the specified window and returns without waiting for the thread to process the message.

To post a message in the message queue associated with a thread, use the PostThreadMessage function.



BOOL PostMessageA(
  HWND   hWnd,
  UINT   Msg,
  WPARAM wParam,
  LPARAM lParam

Exploit access() with Symlinks

About access()

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).

#include <unistd.h>
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 Issue

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.


I have forked an old Modbus testing framework that I will be adding to, keep checking back for updates.

What is Modbus?