Juan Karlo Licudine is currently employed as a Cyber Security Engineer where he uses his programming and technical skills in helping companies protect themselves from cyber threats. In his free time, he works on cybersecurity-related programming projects like malware analysis tools and remote access tools. He jumps between the red or blue camps depending on which project currently interests him.

New Tool Preview: vATT&CK

in tools, cybersecurity

I have released a new cybersecurity-related tool called vATT&CK (Visual ATT&CK). It is a relationship visualizer for the Mitre ATT&CK framework.


What the tool does is that it makes a visual map of the searched technique and all the related information. You can watch a video of the tool in action here.

Each node will be colored depending on it's category. The color legends is as follows:

  • Pink - Related subtechniques
  • Orange - Malware that uses the searched technique
  • Red - Groups that uses the searched technique
  • Blue - Tools that use the searched technique
  • Yellow - Mitigations

This tool is still in development. I plan to add a number of improvements such as:

  • Ability to click on nodes and then update the visual map
  • Ability to search not just by technique, but also by other categories

I also plan on releasing a live demo of the tool very soon in the hopes of getting feedback from the community.

For now, if you are interested in the project, you could visit the tool's Github project page or contact me for any comments or suggestions.

IOLI Crackme 0x04

in re, crackme

I am continuing my reverse engineering review by tackling the IOLI crackmes by @pof. These are beginner friendly challenges that is perfect for newbies or for those who want to review the basics like me. Check out my writeups for 0x00, 0x01, 0x02, and 0x03.

Getting the password

Loading the program in IDA revealed something new. There is now a _check function that when opened looks more complicated than the previous challenges.


The one thing that I immediately noticed is the call to the _strlen function similar to the previous challenge. This means that the length of the input string plays another important role.

One curious thing is the condition that leads to the "Password Incorrect" block, as shown below.


call _strlen
cmp [ebp+var_C], eax
jnb short loc_401387

From the looks of it, the check will fail if var_C (Which is our var_counter from the previous challenge) reaches the length of the entered string. If you think about it, this means that it doesn't matter how long the string that the user inputs. What's important is the content.

To find out what the correct content the program expects, we need to look at the other block of code.


The code uses the same approach as the previous challenge where var_counter is used to loop through individual characters in the input string.

The part that is new is the use of the _sscanf function which is defined as:

"sscanf reads data from s and stores them according to parameter format into the locations given by the additional arguments, as if scanf was used, but reading from s instead of the standard input (stdin)."

Looking at how the function _sscanf is used, it gets each character in the input string and converts them to decimal integers. This means that the password can only contain the numbers 0 through 9. The reason for this is because the result is added to another value at the line add [eax], edx.

This "other value" is the converted integer value from previous loops. This means that the algorithm adds each number from the input string after every loop. For example, an input string of 123 translates to 1+2+3 where the computed sum is saved to var_8.

Finally, there is the line cmp [ebp+var_8], 0Fh, which tells us that the program expects the computed sum to be equal to 0Fh or 15. So as long as we enter numbers that would equal to 15 when combined, then we are good.


Patching the executables

Patching the executable is different this time around. If on previous challenges we patched the program by changing an conditional opcode to a jmp (74 to EB), for this one we only need to change the conditional to a no op instruction (00).


As you can see, the line cmp [ebp+var_8] and the conditional branch disappears allowing us to go directly to the "Password OK" part of the code.


On to the next challenge...

I liked this challenge mostly because it changed the passwords the program expects. The first time I tackled this challenge I used purely static analysis. I thought I got the answer only to realize that I was wrong by debugging the code. We have 5 more challenges to go!

Building my Virtual Cybersecurity Home Lab

in malware, dev

I have recently realized that one part of cybersecurity that I am lacking basic knowledge on is networking. I honestly did not think it was important when I was starting. It was the reason why I skipped Network+ so I could take Security+ directly.

Now I know better.

Ever since my realization, I have taken steps to patch the holes in my knowledge. I've started taking courses and bought books. But one thing that has made the most impact is me building my very own "homelab".

I first came to know of the concept of homelabs from Reddit. To those unfamiliar, it is the practice of building a networked environment to gain practical knowledge in networking and IT. One way to do this is by making a virtual network.

And so, over the past month, I have been building my very own virtual homelab with a focus on integrating cybersecurity products.

The Lab

The network diagram below shows the current implementation of my lab. I will be discussing each part to give an idea of their purpose (Click here for a bigger version).


At the heart of the network is a firewall running pfSense. Its purpose is to ensure that each sub-network is separated and protected, and also to protect my virtual host from any malware outbreaks. This machine also serves as a DHCP and NTP server to all the machines in the network.


The Target Network

On the right side of the diagram is the "Target" network where workstations and vulnerable servers reside. These are the machines that I use to attack with exploits and malware.


I have Metasploitable 2 and Metasploitable 3 machines that have various services turned on to play around with. I can learn about specific attacks by exploiting this machine, but I can also don my defenders hat and learn about how to secure them.

The Windows and Linux machines will serve as typical workstations for various experiments.

One of the perks of my job is that I get to play with different cybersecurity solutions. I currently have access to a few that I am able to use on my lab for testing.

One solution that I am using right now is an EDR (Endpoint Detection and Response) (Sorry, I can't reveal which). Each machine has an EDR agent deployed which monitors for any malicious activities on the host. It has an anti-virus feature, anti-ransomware, and fileless attack monitoring. It's awesome stuff but I have yet to maximize this.

An IDS (intrusion Detection System) running Snort monitors the traffic for any malicious activity. Signatures are constantly updated to ensure that I can detect the latest types of attack. If it finds anything important, it then sends an alert to a SIEM (running Splunk) on the Management network.


The Management Network

On the left side of the diagram is the Managemnet network. This is where the management part of the EDR, IDS, and the SIEM can be accessed from my virtual host.


There's nothing special about this network, I do want to note though that I find it interesting the Snort IDS has two interfaces. One is used for access to the management page, and the other is for sniffing traffic on the Attacker network.

The Operations Network

At the bottom side of the diagram is the "Operations" network.

A machine running Kali is placed here. I can launch attacks from this machine towards the vulnerable machines on the Target network. This machine also has OpenVAS scanner that helps in discovering vulnerabilities on the target machines.


A windows machine serves as my malware analysis lab. It contains a lot of malware analysis tools to aid with investigations.

This machine is then connected to a Remnux Linux machine. All traffic from the Windows machine is port forwarded by Remnux. From here I can run Wireshark to inspect the traffic coming from the Windows malware lab and it can also spoof the network responses to influence the behavior of malware. If the Remnux machine is turned off, then the Windows machine is effectively cut off from the whole network. It's a really neat setup that I learned here.

The Present

While the main intent of the network is to learn networking and implementing cybersecurity products, I can also investigate malware and learn about exploits by launching attacks. So it has a lot of multiple uses, which is perfect for someone like me who gets interested in different aspects of cybersecurity.

My host machine currently has 32GB, 8 cores, and a total of 1.75TB which may seem a lot but is not powerful enough for all the machines to run at the same time. As a workaround, I just open the machines that I need for a particular exercise.


For example, if I want to investigate malware then I only need the firewall, Remnux, and the windows malware lab open. But if I want to attack and run an exploit, while making sure that it gets detected, then I need the firewall, EDR, IPS, SIEM, Kali, and the target machine to be open at the same time. This easily consumes around 20GB+!

The Future

Working on this homelab has taught me a lot of practical knowledge. It helped solidify a lot of networking concepts I've learned througout the years.

I'm not stopping here though. I also plan to upgrade the Target network so it would better resemble an enterprise network. For example, setting up an active directory, an internal DNS server, and maybe even a mail server (why not?). This is so I could play around in detecting and remediating more varied enterprise-level scenarios.

I am also hoping I could get access to more cybersecurity products so I could play around with them. A SOAR (Security Orchestration and Response) would be a nice addition that would work really well.

But, of course, before I could do any of the above I first need to upgrade my RAM and add more cores!

Making a RAT

in malware, dev

A Remote Access Tool (RAT) is used to remotely access a computer. It has legitimate uses but it can also be used for malicious purposes. I've seen it used in malware I've analyzed and I've always been curious as to how it works.

I was following along the Handmade Hero project 1 when the topic about dynamic DLL loading came up. This is a process of dynamically loading a DLL at runtime which is useful if you want your program to check if a DLL is present in a system before loading it.

Two of the system calls that were discussed were LoadLibrary and GetProcAddress. These were familiar to me as I've seen them used on malware shellcode I analyzed in the past. I later learned that this is also used as an anti-virus evasion technique. I found this interesting.

Having learned how to do runtime DLL loading myself I decided to give it a try. And of course, a RAT is perfect for this.


Planning the RATchitecture

A lot of famous RATs are packed with features like the ability to log keystrokes, take screenshots, and turn on a webcam. I just want mine to be simple and have basic functionality like:

  • Execute command line commands remotely
  • Download a file to the client
  • Exfiltrate data via file upload

You can already do a lot of things even with the above basic functions. You can download a payload to the client, run it via remote command and then upload the results. You can even update the RAT itself using the same process!

As an extra, I also wanted it to be stealthy. I am aware however that this is something that is not easily done. There are myriads of security defenses and I don't think I have the time and energy to have my RAT to be up-to-date with the latest evasion techniques. Having basic anti-debugging and anti-sandbox checks is enough for me.

I've never made a RAT before but thankfully there are a lot of great resources online that helped me a lot:

  • ParadoxiaRat is my main resource and has done a lot of the features I wanted to implement.
  • DarkRAT is a leaked source code that gave me an idea of how a RAT used in the wild looks like
  • VXUnderground's WinAPI tricks taught me that there are alternative ways to do certain things to avoid detection

As for the name of the project, I decided on "RATwurst" after the german sausage, Bratwurst. Don't ask me why. I just thought it's funny that it had the letters RAT in it.


The nitty gRATty details

The client is written in ANSI C because it's the language I prefer. Since I am only targeting Windows I chose MSVC for the compiler. Which is great because it allows me to use Visual Studio for debugging.

The server, on the other hand, is written in Python because I wanted another excuse to practice with it. Choosing Python has been a good choice though because of the excellent low level socket and cmd libraries.

Sockets are used for communication between client and server. I've applied basic XOR obfuscation to the data to mask the traffic. The client and server can handle sending of strings and even executables over the network.

When RATwurst is first executed. It does some anti-sandbox checks via process enumeration. It checks if there are more than 15 processe that are running and if there are virtualization tools present like vmware.exe. It will also setup an auto-run registry entry for persistence. And also move the executable to Windows' temp folder and re-run it from there.

Anti-debbuging checks are littered throughout the code which checks the amount of time it takes to reach from one part of the code to the next. This is used to detect if someone is stepping through the code, increasing the delay between code execution.

When no shenanigans is detected then it'll proceed to work as intended.


For eduRATional purposes only

I've made the source of my project available on Github. The aim is to share what I've learned so that others can learn too.

I am aware of news of RAT authors having been arrested because of their work. They actively sought to gain money from their creation, I, of course, have no such plans.

To make sure that I save myself from any legal problems, I've placed a disclaimer that I am not responsible for any misuse. While I am skeptical that a piece of text would prevent any legal action towards me, I do see other projects having their own disclaimers so I decided to do the same.

I've also submitted my creation to a multi-scanner service like VirusTotal. This would help distribute my RATs signature to anti-virus companies so it can easily be detected when used in the wild.2

A RATisfying learning experience

Making this project has been a lot of fun.

The most useful thing that I learned is the client and server communication via sockets. I've dabbled with it before but only in this project have I actually sent actual data back and forth.

I am also happy that I got to use more Windows APIs. It's fun to play around with what's available and it is opening my mind as to what other things I can make in the future.

And of course, this project has given me a good insight into the techniques used by malware. Learning about them is not enough until you've built one yourself.

  1. Handmade here is a project by Casey Muratori where a game is created from scratch live on stream, has been going on for 6+ years, it's awesome 

  2. Multi-scanners help to easily distribute virus signatures to security services. An opposite to this are "no-distribute" sacnners. More info about this here

Finding phished passwords on a scam site

in phishing

Since my last post about my investigations of a Facebook phishing site, I have received several messages from friends asking me to check out other suspected phishing/scam sites. One of the most alarming out of them was this one where I was able to find the file where the scammer stores the phished usernames and passwords.


This particular phishing site conducts its operations like this:

  • An ad is shown on Facebook, promising free coupons for famous fast food restaurants
  • Clicking on the ad takes the user to a fake Facebook login page hosted on
  • Login page then sends phished username and passwords to a PHP file hosted on 000webhost

The phished passwords are then stored in a .txt file (blatantly named, victims.txt), which is publicly accessible on an open directory. Getting to this directory involved following the scripts and the URLs used by the scammers. It's not that hard to find as long as you know where to look.

What's scary is that the size of this text file kept on getting bigger. I knew I had to act quickly.

Stopping the scammers

Unfortunately, with phishing sites like these, there's not much we could do but report it to the relevant hosting providers. The problem is that sometimes it may take some time before the site gets reviewed, which is excruciating because the longer the wait, the more people fall victim. Some might even just ignore your report altogether!

I reported the fake login page to and did not receive any response at all. I understand that is a big platform and I bet they receive numerous reports like this. I guess this is why the scammer used this platform as they know they won't be taken down too quickly. Their profile even listed two sites that both had fake login pages.


Thankfully, 000webhost got back to me and eventually took down the page that hosted the PHP and text files.


You'd think that this is a victory. But sadly, setting up a new phishing site is rather easy so within a few hours there is already a new one. Of course, I reported this new site too. Only for a new one to pop up later...

You can see how this can become an endless cat and mouse game.

Stopping from other sources

One way that could be effective to stop the scammer's operations is by reporting the Facebook advertisement that is used to lure users to the phishing site. Unfortunately, my friend who shared this with me did not get a chance to snap a screenshot of the ad. If he did then it would probably have more impact on stopping their operations. Maybe the Facebook abuse team can trace the payment details used to pay for the ad, and maybe block it.


If you know anyone who may have seen a Facebook advertisement that offers free coupon codes for fast food restaurants that might be pointing to a suspicious login page, then please do contact me!

Awareness is the key

As of this posting, the landing page is still up while the page that hosts the PHP and victims file is down. I'm sure it'll be back up soon. All I was able to do was delay their operations. A minor inconvenience for them.


This is why out of everything, spreading awareness is the best countermeasure. If people are more aware of phishing sites and how to avoid them then that would greatly diminish their impact. This is why I continue to post and write about phishing sites. Seeing the number of victims rising like that made me act knowing that I at least have the power to prevent things from escalating.

And you have the power too, dear reader. Educate your family and friends by warning them or by showing them my posts. Remember, awareness is our best defense!

Emprisa Maldoc Writeup

in writeup

This is a writeup for Emprisa maldoc challenge that I made for You can play it here.

The very first thing that I do when confronted with a malicious document is to run it in a malware lab. This particular document, however, would not exhibit anything malicious on recent versions of Word.

A quick search of the hash on malware sandboxes would reveal that the document makes use of the CVE-2017-18822 vulnerability. This is a vulnerability that became known and was promptly patched around November of 2017.

The above details give us a hint on how to trigger the document, which is to run the maldoc on a version of Microsoft Word that doesn't have the patches that fix the vulnerability. The easiest way to do this is to boot up a new VM with a fresh install of Windows 7 and with updates disabled.

This new environment is where the document would trigger once double-clicked. After a bit of loading, a pop-up would later appear greeting the analyst with congratulations (this is a stand-in for a malicious payload for this challenge), but of course, it is clear that we are not done yet.


Tools such as Process Hacker will reveal a new process named EQNEDT32.EXE getting spawned right after opening the document. Those who have read through the CVE details would know that this is the expected behavior, as the vulnerability uses this process to run malicious code. In this case, the exploit downloads a file from the internet and automatically runs it.

Another tool such as Regshot would reveal newly created files. It can determine these by taking a snapshot before the malicious document is opened, then taking another one after the downloaded payload gets triggered, and finally comparing the two snapshots and listing the differences. It's an invaluable tool to have.


Running would then reveal some telling details about our maldoc, like for example, magic signatures and object streams.

Upon close inspection of the hexdump of the largest object stream (still via rtfdump), one would see a sequence of NOPs (aka a NOPsled) in certain parts. A NOPsled such as this usually indicates the possible start of shellcode. Carving this part of the shellcode and running it on an emulator such as speakeasy or scdbg won't work properly, however.


The output shows the first line to be LoadLibrary, and then there's an error after that. This indicates that maybe there's a problem with the shellcode.

On further inspection, a little more further down there is another set of seemingly readable strings. This could indicate another shellcode. Or, maybe, a continuation of the first one? In between these supposed two shellcodes is a readable string that seems out of place in between the gibberish. Carving the two shellcodes and then combining them would now work when run on an emulator.


If the previous solution was not immediately clear to you then there is another approach to the above. And that is to step through the EQNEDT32 process as soon as it runs. However, attaching to this process is tricky as it triggers only for a split second and then exits. To debug this, a debugger should be automatically connected as soon as the process starts. Check out this post for details on how to do this.

Once attached, the painstaking process of debugging begins. Thankfully, we have an idea of what code is being loaded into memory. And this is the shellcode that has a NOPSled during our analysis with above. Looking for this sequence and then putting a breakpoint where the memory location is accessed would stop the program just before the shellcode is run. Once the breakpoint triggered, we could step through the shellcode and find out what exactly the shellcode does and which Libraries are being called.

From here, we could also backtrack from where the shellcode is called to figure out how the exploit is triggered via a buffer overflow. This requires a bit of knowledge in reverse engineering. An alternative is to check out the CVE details in search for the tool that was likely used to make the exploit, and then examining the code.

After all of that, you should have everything that you need to answer all the questions in the challenge. You may have noticed that I have not revealed the answers outright. You still have to find it on your own. However, I do hope that by walking you through the process, I have helped you understand how to get there.

If you have more questions, or want to tell me what you think of the challenge, feel free to leave a comment below or send me a mesage at @accidentalrebel.

Investigating an FB phishing site

in phishing

Last April 21, people were posting warnings about a suspicious Facebook post where your account will supposedly get hacked when you click it. From the discussions, I gathered that it is a classic phishing site scam. A very effective one too, because as soon as an account gets compromised the attacker logs in and tags the friends in the account allowing it to spread further. The news of this got big that even the PH CERT issued a security advisory on it.


I was just curious, I swear!

I wanted to see the phishing site for myself but I was unlucky and did not get tagged by anyone. So I reached out to people who did and I eventually got to this page shown below:


To a trained eye, one could easily see the obvious red flags. But how can one notice them if there is a very attention-catching image in the middle beckoning to be clicked? It's a very simple tactic yet very effective. Clicking this link leads to an external website with an even more tantalizing image masquerading as a video.


Clicking play on that video would then lead to a fake Facebook login page. We all know what's next after that.


Of course, the very best course of action when a phishing site is discovered is to report it. I, however, was curious so I decided to poke around first.

The poking begins

Using my knowledge in OSINT (Open Source Intelligence) and pentesting, I poked around to see what I could learn from these set of pages.

One thing that immediately became obvious was that these "set of pages" were hosted on separate domains. The page with the video points to one domain, and the login page to another (that is even protected by DDNS (Dynamic DNS) via No-IP).


I also noticed that the way that the two pages were built was different. The coding style is not the same, different frameworks were used, plus the robots.txt of the login page was more restrictive.

Why are they in separate domains? Wouldn't it be cheaper to just have both pages on the same domain?

My hunch is that maybe the two sites were made by different people. One guy made the landing page then a different one made the login page. Or maybe the login page is an out-of-the-box solution you pay for or rent if you want to set up your own phishing scam? A PhAAS (Phishing-as-a-Service)?


During my reconnaissance, I also noticed that the URLs for the login page were changed a few times over a few hours. It's possible that the pages were being taken down thanks to the reports and the malicious actors were just making new instances and redirecting to it to make sure that the operation continues.

Đăng nhập hoặc đăng

Another thing I noticed is references to various Vietnamese terms and websites. Both pages have directories using the word "homnay", Vietnamese for the word "today". The source code also has a link to the news website "".


The Google Analytics ID used can also be found in previously tagged but now-defunct Phishing websites with references to Vietnam. It's entirely possible that these phishing sites initially targeted Vietnamese users but eventually got to Philippine users via the tagging spreading mechanism.


Or maybe it's a deliberate ploy to make it seem that the origin of the phish is Vietnamese. Just to throw off those of us snooping around.

And then it was gone

I was tempted to make a dummy Facebook account and send the login details to the phishing site. The idea was to see how long before an account gets accessed after submitting the credentials and if the tagging of friends is automated or done manually. But sadly I ran out of free time and by the time I came back to it the login page was already completely offline. The landing page is still up though.

This investigation has taught me a lot about phishing sites. It's different from investigating malware but it's easy to see the similarities in intent and approaches. I might try investigating more in the future. I'm curious to find out what the usual modus operandi is and also how the general populace can better protect themselves from it.

This particular site may be down now, but I bet there will be more in the future. As long as there are people to fall for scams like these, this type of attack will continue.

If you want to know more or discuss the details about the phishing site, I would be happy to exchange notes. Drop me a line on Twitter @accidentalrebel.

The Emprisa Maldoc Challenge

in maldoc, ctf

I was inspired to make my own CTF challenge after finishing Maldoc101 found at The challenge I made is called Emprisa Maldoc and it is now up on their website.

Emprisa is based on a malicious document that I downloaded blindly from a malware sandbox. It used a relatively old but still interesting exploit that is still in use today. After researching more about it I came across a tool that can generate a malicious doc using the same exact exploit. This is when I got the idea to turn it into a challenge.


The challenge has 14 questions with increasing and varying difficulty. The challenge is targeted towards intermediate analysts who already have experience examining maldocs before. The goal is to reinforce the use of common malware analysis tools, but at the same time, teach players new things and techniques. It involves flexing muscles related to open source intelligence, examining shellcodes, and debugging processes.

I don't want to spoil too much but if you are for it, you can give it a go here. It was hella fun to make and I do hope that it is also as fun to solve!

Official write-up with hints coming soon.

I would like to extend my thanks to the team behind They accepted my submission, reviewed it, and worked with me in improving it. And also to Josh Stroschein for making Maldoc101 and being kind enough to entertain me with my questions related to making challenges.

IOLI Crackme 0x03

in re, crackme

I am continuing my reverse engineering review by tackling the IOLI crackmes by @pof. These are beginner friendly challenges that is perfect for newbies or for those who want to review the basics like me. Check out my writeups for 0x00, 0x01, and 0x02.

Getting the password

After opening the program in IDA I immediately saw that the code is almost exactly as the one in challenge 0x02, with the exception of our expected cmp command being inside the _test function.


Reading through the code I realized that the password for this challenge is exactly the same as the previous one!

But what's this? The success and failure messages are all garbled? And plus, what is this other new function called _shift?


A different kind of challenge

Opening up the _shift function shows us a short, but interesting looking program flow with two branches and one of the branches looping back. It seems we have a loop here that we could investigate.


If we look at the input that the function takes we will find out that the strings that are being passed from the _test function are Lqydolg#Sdvvzrug$ and Sdvvzrug#RN$$$#=, for the failure and success messages, respectively. This tells us that a cipher is applied to these strings. What cipher it is using is what we'll be trying to find out.

Discovering the cipher

The best way to discover the cipher used is to step through the code. We can do it with both static or dynamic analysis, but the latter is way easier.


The code above starts with mov eax, [ebp+arg_0] which copies the pointer to the string passed to our _shift function. We then copy that pointer to [esp+98h+Str] which is the memory location pointing to the top of the current stack. This is done so that it can be passed as an argument when we do call _strlen.

After executing, _strlen returns the length of the specified string and is saved to register eax. This is then used in the line cmp [ebp+var_7C], eax.

But what is the value of var_7C? If you scroll up at the start of the subroutine, var_7C is assigned a value of zero. If you know how loops work, you'll realize that this variable is going to be used to hold a counter value. It starts at a value of 0 and it will eventually be incremented after every loop, which is what is happening at 401348.

To make it easy for us to remember this, let's rename var_7C to a more memorable name like var_counter.


So going back, to the comparison command cmp [ebp+var_counter], eax, which now translates to cmp 0, 17. 17 being the length of our failure string Lqydolg#Sdvvzrug$. Since this is not equal it now goes to this next block of code.


Now this block is interesting. There's a lot that is happening but the gist of it is that the program gets one character from the input string, with var_counter as an offset. It then decrements that character value by 3, and added to a destination string. I'll be going through the code that I described step by step in the next section.

Stepping through

So to start, lea eax, [ebp+var_78] loads the address to var_78 which in my case points to the address 28FE90.

mov edx, eax copies that address to edx so we can use it on the next line.

add edx, [ebp+var_counter] adds to the address of var_78. Because var_counter is still 0, the address remains at 28FE90.

add eax, [ebp+arg_0] does the same thing as above but this time adding to [arg_0] which contains the address 28FF10.

movzx eax, byte ptr [eax] copies the byte contained in [eax] or 28FF10. In this case that byte contains the value 4Ch or L in ASCII. This is the first letter in our failure string Lqydolg#Sdvvzrug$!

sub al, 3 then substracts 3 to 4Ch making it 49h which is ASCII for I.

mov [edx], al saves the new character to the variable var_78 which is the memory location 28FE90. At this point in time the content is currently the character I. To make it easy for us to understand the code, let's rename var_78 to var_dest. This name is apt because this will be the destination for our shifted ASCII characters.

lea eax, [ebp+var_counter] and then inc dword ptr [eax] now increments the value of var_counter, which now makes it an integer value of 1.

Looping back

Alright. Now we go back up again to loc_401320. I'm not going to step through each line again, but I will highlight the important parts now that we have looped back.

cmp [ebp+var_counter] now translates to cmp 1, 17, which is still not equal.

add edx, [ebp+var_counter] now adds 1 to our var_dest variable, turning 28FE90 to 28FE91. The address for the arg_0 variable is also added by 1 at add eax, [ebp+arg_0].

By the time movzx eax, byte ptr [eax] is executed it now gets the next character in our failure string which is 71h or the letter q.

sub al, 3 converts are letter q to the letter n. And is once again saved to our var_dest variable with the command mov [edx], al.

Repeat until...

If I haven't lost you, then you should now be able to follow what will happen in the next steps:

var_counter will get incremented again and again, which will point to the next characters in the string. For example, the next characters: y then d then o will get shifted to v then a then l, respectively. This shifting of each characters will continue until cmp [ebp+var_counter equates to cmp 17, 17.

By the end, var_dest now contains the newly shifted string Invalid Password!. Finally! Applying the same code above to the success message, the garbled message would end with Password OK!!! :).

Wasn't that fun?

On to the next challenge

I hope I was able to explain properly the simple shifting algorithm used by the program above. I did it this way mostly for my own benefit and to make sure I really did understand how the algorithm worked in assembly. In future writeups I'll refrain from stepping through code at such a granular level, unless there is something really important that warrants it. Or maybe a video would be a much better format for these kinds of challenges?

Anyway, I look forward to the next challenge. Hopefully, you are too!

Maldoc101 Writeup (Part 1)

in re, malware_analysis, malware

This is part 1 out of 2 of my writeup for the Maldoc101 challenge made by Josh Stroschein (@jstrosch) and is currently playable at Cyberdefenders.Org. I've done some maldoc analysis before but this is the first time I'm writing about my approach.

There is also an already existing writeup about this challenge from the creator himself. You should check that out if you want a more detailed and focused writeup. This writeup is more from the perspective of someone relatively new to malware analysis. There's a lot more exploration and trial-and-error which, I hope, might give the reader a different view in how this kind of problem is approached.

The challenge


MalDoc101 - Malicious Document


It is common for threat actors to utilize living off the land (LOTL) techniques, such as the execution of PowerShell to further their attacks and transition from macro code. This challenge is intended to show how you can often times perform quick analysis to extract important IOCs. The focus of this exercise is on static techniques for analysis.

Suggested Tools

  • REMnux Virtual Machine (
  • Terminal/Command prompt w/ Python installed
  • Oledump
  • Text editor

The easy questions

The first question seems very easy. The suggested tools section above also gives us an idea how to approach this.

What streams contain macros in this document? (comma-separated, ascending). is a tool made by Didier Stevens that allows the analysis of data streams found in OLE files such as MS Office documetns. Running the command below would show us which streams have macros in it. These are denoted with the character M.

$ sample.bin
  1:       114 '\x01CompObj'
  2:      4096 '\x05DocumentSummaryInformation'
  3:      4096 '\x05SummaryInformation'
  4:      7119 '1Table'
  5:    101483 'Data'
  6:       581 'Macros/PROJECT'
  7:       119 'Macros/PROJECTwm'
  8:     12997 'Macros/VBA/_VBA_PROJECT'
  9:      2112 'Macros/VBA/__SRP_0'
 10:       190 'Macros/VBA/__SRP_1'
 11:       532 'Macros/VBA/__SRP_2'
 12:       156 'Macros/VBA/__SRP_3'
 13: M    1367 'Macros/VBA/diakzouxchouz'
 14:       908 'Macros/VBA/dir'
 15: M    5705 'Macros/VBA/govwiahtoozfaid'
 16: m    1187 'Macros/VBA/roubhaol'
 17:        97 'Macros/roubhaol/\x01CompObj'

I later noticed that there is an upper-case and lower-case M. I learned that the upper-case M denotes a macro with a code. The lower-case denotes a user form. This is a distinction that will be important later in this challenge.

What command-line argument with Oledump do you use to view the raw content of a stream? (Do not include the leading dash)

The next question is another easy one which ran easily be solved through's --help parameter.

$ --help
Usage: [options] [file]
Analyze OLE files (Compound Binary Files)

  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -m, --man             Print manual
  -s SELECT, --select=SELECT
                        select item nr for dumping (a for all)
  -d, --dump            perform dump
  -x, --hexdump         perform hex dump
  -a, --asciidump       perform ascii dump
  -A, --asciidumprle    perform ascii dump with RLE
  -S, --strings         perform strings dump
  -T, --headtail        do head & tail
  -v, --vbadecompress   VBA decompression

The answer to question number two is easy to spot.

What event is used to begin the execution of the macros?

I used a different tool for this particular question mostly because I knew that it already shows the information I need to answer the question. The tool is called olevba which is part of the oletools package of Python tools. Olevba is used for extracting and analyzing VBA macro source code for MS Office documents.

$ olevba sample.bin
|Type      |Keyword             |Description                                  |
|AutoExec  |Document_open       |Runs when the Word or Publisher document is  |
|          |                    |opened                                       |
|Suspicious|Create              |May execute file or a system command through |
|          |                    |WMI                                          |
|Suspicious|showwindow          |May hide the application                     |
|Suspicious|CreateObject        |May create an OLE object                     |

Onto the main event

What malware family was this maldoc attempting to drop?

I figured that the way for me to determine the answer for the question above is to start investigating the macro codes included in the document.

I knew from the previous question that the entry point to begin the execution of the macros is with the function Document_open(). The next step is to look for this entry point and go through the code to understand what the macro is doing.

To view the contents of a stream, I used the command below:

$ sample.bin -s 13 -v
Attribute VB_Name = "diakzouxchouz"
Attribute VB_Base = "1Normal.ThisDocument"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Attribute VB_TemplateDerived = True
Attribute VB_Customizable = True
Private Sub _
End Sub

In the above output, I saw that Document_open() contains a single line of code which is a call to function boaxvoebxiotqueb'. This function is included in stream 15 which can be viewed with the command:

$ sample.bin -s 13 -v
Attribute VB_Name = "govwiahtoozfaid"
Function boaxvoebxiotqueb()
gooykadheoj = Chr(roubhaol.Zoom + Int(5 * 3))
Dim c7�ATOQe2�j As Integer
c7�ATOQe2�j = 6
Do While c7�ATOQe2�j < 6 + 2
c7�ATOQe2�j = c7�ATOQe2�j + 5: DoEvents
haothkoebtheil = "2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqw2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqin2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqm2342772g3&*gs7712ffvs626fqgm2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqt2342772g3&*gs7712ffvs626fq" + gooykadheoj + "2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fq:w2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqin2342772g3&*gs7712ffvs626fq322342772g3&*gs7712ffvs626fq_2342772g3&*gs7712ffvs626fq" + roubhaol.joefwoefcheaw + "2342772g3&*gs7712ffvs626fqr2342772g3&*gs7712ffvs626fqo2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqc2342772g3&*gs7712ffvs626fqes2342772g3&*gs7712ffvs626fqs2342772g3&*gs7712ffvs626fq"

The above output contains more lines of what looks like gibberish code. Upon further inspection I realized that it's actually obfuscated. I can see common coding patterns which tells me that I could make sense of the code if I step through it and organize it so it is easy to understand.

The first line of the boaxvoebxiotqueb shows:

gooykadheoj = Chr(roubhaol.Zoom + Int(5 * 3))

What's roubhaol? Since this is the first line in the function, I know that it is not a locally defined variable. It must be declared somplace else.

After looking around I learned that roubhaol is a the name of the user form at stream 16.

16: m    1187 'Macros/VBA/roubhaol'

So the next step is figuring out what roubhaol.Zoom's value is. This value is not set anywhere in any of the macros by code. This means that the value is set in the form itself. To confirm, I opened up the Word document, pressed Alt+F11 to open up the Visual Basic editor and then opened the roubhaol form. At the bottom we see that the value of Zoom is set to 100.


This means that by simulating the first line of code again we find that the variable gooykadheoj gets the character value of s.

gooykadheoj = Chr(roubhaol.Zoom + Int(5 * 3))
gooykadheoj = Chr(100 + Int(5 * 3))
gooykadheoj = Chr(115)
gooykadheoj = Chr(115) # character "s"

I then proceeded to go through the next set of lines.

Dim c7ATOQe2j As Integer
c7ATOQe2j = 6
Do While c7ATOQe2j < 6 + 2
c7ATOQe2j = c7ATOQe2j + 5: DoEvents

This one is easier to simulate. c7�ATOQe2�j is assigend 6. And then there's a loop that adds 5 that eventually results to the value of 16.

But wait, something is fishy here. The variable c7�ATOQe2�j is not found anywhere else after the block of code above. This tells us that this is just junk code that does not really do anything aside from waste an analyst's time! Sneaky sneaky.

To save me the time I proceeded to remove all junk code. I did this by going through each variables and seeing if they are used somewhere useful. If not, then they are safe to remove.

Attribute VB_Name = "govwiahtoozfaid"
Function boaxvoebxiotqueb()
    gooykadheoj = Chr(roubhaol.Zoom + Int(5 * 3))

    haothkoebtheil = "2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqw2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqin2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqm2342772g3&*gs7712ffvs626fqgm2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqt2342772g3&*gs7712ffvs626fq" + gooykadheoj + "2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fq:w2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqin2342772g3&*gs7712ffvs626fq322342772g3&*gs7712ffvs626fq_2342772g3&*gs7712ffvs626fq" + roubhaol.joefwoefcheaw + "2342772g3&*gs7712ffvs626fqr2342772g3&*gs7712ffvs626fqo2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqc2342772g3&*gs7712ffvs626fqes2342772g3&*gs7712ffvs626fqs2342772g3&*gs7712ffvs626fq"

    deulsaocthuul = juuvzouchmiopxeox(haothkoebtheil)

    Set tiajriokchaoy = CreateObject(deulsaocthuul)

    deaknaugthein = roubhaol.kaizseah.ControlTipText
    giakfeiw = deulsaocthuul + gooykadheoj + roubhaol.paerwagyouqumeid.ControlTipText + deaknaugthein
    queegthaen = giakfeiw + roubhaol.joefwoefcheaw

    Set deavjoajsear = luumlaud(queegthaen)

    xve = Array _
        ("1234444123", tiajriokchaoy. _
        Create(geulgelquuuj, kaenhaig, deavjoajsear), "9938723")
End Function

Function juuvzouchmiopxeox(yiajthoavheiw)
    geutyoeytiestheug = yiajthoavheiw
    feaxgeip = Split(geutyoeytiestheug, "2342772g3&*gs7712ffvs626fq")

    jaquhoiqu = csqw + Join(feaxgeip, eihnx)
    juuvzouchmiopxeox = jaquhoiqu
End Function

Function geulgelquuuj()
    sjiqw = roubhaol.gaoddaicsauktheb.Pages(10 / 10).ControlTipText
    geulgelquuuj = juuvzouchmiopxeox(sjiqw)
End Function

Function luumlaud(zeolkaepxoag)
    Set luumlaud = CreateObject(zeolkaepxoag)
    Dim vPu As String
    vPu = Replace$("BenqV1�igVwifwdQq", "BenqV1�i", "on5�")
        luumlaud _
        . _
        showwindow = (mujgoiy + jioyseertioch) + (neivberziok + xuajroegquoudcaij)
End Function

As you can see above, the code is shorter. It's also a little easier to understand. Only a little though, we still need to step through the code carefully to have a better grasp of what it is doing.

Let's take on the next line:

haothkoebtheil = "2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqw2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqin2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqm2342772g3&*gs7712ffvs626fqgm2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqt2342772g3&*gs7712ffvs626fq" + gooykadheoj + "2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fq:w2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqin2342772g3&*gs7712ffvs626fq322342772g3&*gs7712ffvs626fq_2342772g3&*gs7712ffvs626fq" + roubhaol.joefwoefcheaw + "2342772g3&*gs7712ffvs626fqr2342772g3&*gs7712ffvs626fqo2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqc2342772g3&*gs7712ffvs626fqes2342772g3&*gs7712ffvs626fqs2342772g3&*gs7712ffvs626fq"

If we look at the string carefully we would notice that a set of strings is concatenated with two variables. These variables are gooykadheoj and roubhaol.joefwoefcheaw. We already know the value of gooykadheoj. So what's the value of roubhaol.joefwoefcheaw?

I got this value by going back to Visual Basic Editor and selelecting joefwoefcheaw. The value we need is listed under Text.


Substituting the values s and P I got the following:

haothkoebtheil = "2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqw2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqin2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqm2342772g3&*gs7712ffvs626fqgm2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqt2342772g3&*gs7712ffvs626fqs2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fq:w2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqin2342772g3&*gs7712ffvs626fq322342772g3&*gs7712ffvs626fq_2342772g3&*gs7712ffvs626fqP2342772g3&*gs7712ffvs626fqr2342772g3&*gs7712ffvs626fqo2342772g3&*gs7712ffvs626fq2342772g3&*gs7712ffvs626fqc2342772g3&*gs7712ffvs626fqes2342772g3&*gs7712ffvs626fqs2342772g3&*gs7712ffvs626fq"

It still doesn't clear up the gibberish, but at least it's now one big string. This same string is then passed as a parameter to function juuvzouchmiopxeox.

deulsaocthuul = juuvzouchmiopxeox(haothkoebtheil)

Let's look at the code inside juuvzouchmiopxeox.

Function juuvzouchmiopxeox(yiajthoavheiw)
    geutyoeytiestheug = yiajthoavheiw
    feaxgeip = Split(geutyoeytiestheug, "2342772g3&*gs7712ffvs626fq")

    jaquhoiqu = csqw + Join(feaxgeip, eihnx)
    juuvzouchmiopxeox = jaquhoiqu
End Function

Following the code we could see that the passed string is splitted using the call to the function Split with the substring 2342772g3&*gs7712ffvs626fq. This simply means that the substring is removed from the input string. The result of Split is then joined into one string using Join. There are the variables csqw and eihnx, they don't alter the string as these variables are empty.

At the end of this function the value of the passed string is now:


Aha! Something that is not gibberish for a change!

Going back to the caller function, the result of juuvzouchmiopxeox is saved to deulsaocthuul.

    deulsaocthuul = juuvzouchmiopxeox(haothkoebtheil)

    Set tiajriokchaoy = CreateObject(deulsaocthuul)

After that an object is created out of deaulsaocthuul, which we know contains winmgmts:win32_Process.

Looking at the microsoft docs I find out that The Win32_Process WMI class represents a process on an operating system.. Interesting.

Taking a step back

At this point there are already a number of questions that we could answer based on what we've done so far. Some are not yet answerable at the moment, however, so nothing left to do but to push forward. But that will be for the next part of this two part series.

Until then, I'm taking a step back as I marvel at my progress. It wouldn't take long until all the pieces would fall into place.